Package madgraph :: Package iolibs :: Module import_v4
[hide private]
[frames] | no frames]

Source Code for Module madgraph.iolibs.import_v4

  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  from madgraph.core import base_objects 
 16  """Methods and classes to import v4 format model files.""" 
 17   
 18  import fractions 
 19  import logging 
 20  import os 
 21  import re 
 22   
 23  from madgraph import InvalidCmd, MG4DIR, ReadWrite 
 24   
 25  import madgraph.core.color_algebra as color 
 26  import madgraph.iolibs.files as files 
 27  import madgraph.iolibs.save_load_object as save_load_object 
 28   
 29  import madgraph.various.misc as misc 
 30   
 31  from madgraph.core.base_objects import Particle, ParticleList 
 32  from madgraph.core.base_objects import Interaction, InteractionList 
 33   
 34  logger = logging.getLogger('madgraph.import_v4') 
35 36 #=============================================================================== 37 # import_v4model 38 #=============================================================================== 39 -def import_model(model_path, mgme_dir = MG4DIR, absolute=True):
40 """create a model from a MG4 model directory.""" 41 42 # Check for a valid directory 43 model_path_old = model_path 44 model_path = find_model_path(model_path, mgme_dir, absolute) 45 46 files_list = [os.path.join(model_path, 'particles.dat'),\ 47 os.path.join(model_path, 'interactions.dat')] 48 49 for filepath in files_list: 50 if not os.path.isfile(filepath): 51 if not absolute: 52 raise InvalidCmd, "%s directory is not a valid v4 model" % \ 53 (model_path) 54 else: 55 return import_model(model_path_old, mgme_dir, False) 56 57 # use pickle files if defined 58 if files.is_uptodate(os.path.join(model_path, 'model.pkl'), files_list): 59 model = save_load_object.load_from_file( \ 60 os.path.join(model_path, 'model.pkl')) 61 if model.has_key('version_tag') and model.get('version_tag') == os.path.realpath(model_path) + str(misc.get_pkg_info()): 62 return model, model_path 63 64 model = base_objects.Model() 65 model.set('particles',files.read_from_file( \ 66 os.path.join(model_path, 'particles.dat'), 67 read_particles_v4)) 68 69 model.set('interactions',files.read_from_file( \ 70 os.path.join(model_path, 'interactions.dat'), 71 read_interactions_v4, 72 model['particles'])) 73 74 model.set('name', os.path.split(model_path)[-1]) 75 76 # save in a pickle files to fasten future usage 77 if ReadWrite: 78 try: 79 save_load_object.save_to_file(os.path.join(model_path, 'model.pkl'), model) 80 except Exception: 81 logger.warning("fail to write %s. This is perfectly fine will just prevent speed boost in future load of this model" %\ 82 os.path.join(model_path, 'model.pkl')) 83 return model, model_path
84
85 86 -def find_model_path(model_path, mgme_dir, absolute=True):
87 """Find the path to the model, starting with path model_path.""" 88 89 # treat simple case (model_path is a valid path/ mgme_dir doesn't exist) 90 if os.path.isdir(model_path) and absolute: 91 return model_path 92 elif mgme_dir and os.path.isdir(os.path.join(mgme_dir, 'models', 93 model_path + "_v4")): 94 model_path = os.path.join(mgme_dir, 'models', model_path + "_v4") 95 elif mgme_dir and os.path.isdir(os.path.join(mgme_dir, 'Models', model_path)): 96 model_path = os.path.join(mgme_dir, 'Models', model_path) 97 elif not mgme_dir: 98 error_text = "Path %s is not a valid pathname\n" % model_path 99 error_text += "and no MG_ME installation detected in order to search in Models" 100 raise InvalidCmd(error_text) 101 102 # Try to build the valid path 103 path_possibilities = [os.path.join(mgme_dir, 'Models', model_path), 104 os.path.join(mgme_dir, 'models', model_path + "_v4"), 105 os.path.join(mgme_dir, 'models', model_path) 106 ] 107 108 for path in path_possibilities: 109 if os.path.exists(path) and \ 110 not os.path.exists(os.path.join(path, 'particles.py')): 111 return path 112 113 # No valid path found 114 raise InvalidCmd("Path %s is not a valid pathname" % model_path)
115
116 #=============================================================================== 117 # read_particles_v4 118 #=============================================================================== 119 -def read_particles_v4(fsock):
120 """Read a list of particle from stream fsock, using the old v4 format""" 121 122 spin_equiv = {'s': 1, 123 'f': 2, 124 'v': 3, 125 't': 5} 126 127 color_equiv = {'s': 1, 128 't': 3, 129 '6': 6, 130 'o': 8} 131 132 line_equiv = {'d': 'dashed', 133 's': 'straight', 134 'w': 'wavy', 135 'c': 'curly'} 136 137 logger.info('load particles') 138 139 mypartlist = ParticleList() 140 141 for line in fsock: 142 mypart = Particle() 143 144 if line.find("MULTIPARTICLES") != -1: 145 break # stop scanning if old MULTIPARTICLES tag found 146 147 line = line.split("#", 2)[0] # remove any comment 148 line = line.strip() # makes the string clean 149 150 if line != "": 151 values = line.split() 152 if len(values) != 9: 153 # Not the right number tags on the line 154 raise ValueError, \ 155 "Unvalid initialization string:" + line 156 else: 157 try: 158 mypart.set('name', values[0].lower()) 159 mypart.set('antiname', values[1].lower()) 160 161 if mypart['name'] == mypart['antiname']: 162 mypart['self_antipart'] = True 163 164 if values[2].lower() in spin_equiv.keys(): 165 mypart.set('spin', 166 spin_equiv[values[2].lower()]) 167 else: 168 raise ValueError, "Invalid spin %s" % \ 169 values[2] 170 171 if values[3].lower() in line_equiv.keys(): 172 mypart.set('line', 173 line_equiv[values[3].lower()]) 174 else: 175 raise ValueError, \ 176 "Invalid line type %s" % values[3] 177 178 mypart.set("mass", values[4]) 179 mypart.set("width", values[5]) 180 181 if values[6].lower() in color_equiv.keys(): 182 mypart.set('color', 183 color_equiv[values[6].lower()]) 184 else: 185 raise ValueError, \ 186 "Invalid color rep %s" % values[6] 187 188 mypart.set("texname", values[7]) 189 mypart.set("pdg_code", int(values[8])) 190 191 mypart.set('charge', 0.) 192 mypart.set('antitexname', mypart.get('texname')) 193 194 except (Particle.PhysicsObjectError, ValueError), why: 195 logger.warning("Warning: %s, particle ignored" % why) 196 else: 197 mypartlist.append(mypart) 198 199 return mypartlist
200
201 202 #=============================================================================== 203 # read_interactions_v4 204 #=============================================================================== 205 -def read_interactions_v4(fsock, ref_part_list):
206 """Read a list of interactions from stream fsock, using the old v4 format. 207 Requires a ParticleList object as an input to recognize particle names.""" 208 209 logger.info('load interactions') 210 myinterlist = InteractionList() 211 212 if not isinstance(ref_part_list, ParticleList): 213 raise ValueError, \ 214 "Object %s is not a valid ParticleList" % repr(ref_part_list) 215 216 for line in fsock: 217 myinter = Interaction() 218 219 line = line.split("#", 2)[0] # remove any comment 220 line = line.strip() # makes the string clean 221 222 if line != "": # skip blank 223 values = line.split() 224 part_list = ParticleList() 225 226 try: 227 for str_name in values: 228 curr_part = ref_part_list.get_copy(str_name.lower()) 229 if isinstance(curr_part, Particle): 230 # Look at the total number of strings, stop if 231 # anyway not enough, required if a variable name 232 # corresponds to a particle! (eg G) 233 if len(values) >= 2 * len(part_list) + 1: 234 part_list.append(curr_part) 235 else: break 236 # also stops if string does not correspond to 237 # a particle name 238 else: break 239 240 if len(part_list) < 3: 241 raise Interaction.PhysicsObjectError, \ 242 "Vertex with less than 3 known particles found." 243 244 # Flip part/antipart of first part for FFV, FFS, FFT vertices 245 # according to v4 convention 246 spin_array = [part['spin'] for part in part_list] 247 if spin_array[:2] == [2, 2] and \ 248 not part_list[0].get('self_antipart'): 249 part_list[0]['is_part'] = not part_list[0]['is_part'] 250 251 myinter.set('particles', part_list) 252 253 # Give color structure 254 # Order particles according to color 255 # Don't consider singlets 256 color_parts = sorted(enumerate(part_list), lambda p1, p2:\ 257 p1[1].get_color() - p2[1].get_color()) 258 color_ind = [(i, part.get_color()) for i, part in \ 259 color_parts if part.get_color() !=1] 260 colors = [c for i,c in color_ind] 261 ind = [i for i,c in color_ind] 262 263 # Set color empty by default 264 myinter.set('color', []) 265 if not colors: 266 # All color singlets - set empty 267 pass 268 elif colors == [-3, 3]: 269 # triplet-triplet-singlet coupling 270 myinter.set('color', [color.ColorString(\ 271 [color.T(ind[1], ind[0])])]) 272 elif colors == [8, 8]: 273 # octet-octet-singlet coupling 274 my_cs = color.ColorString(\ 275 [color.Tr(ind[0], ind[1])]) 276 my_cs.coeff = fractions.Fraction(2) 277 myinter.set('color', [my_cs]) 278 elif colors == [-3, 3, 8]: 279 # triplet-triplet-octet coupling 280 myinter.set('color', [color.ColorString(\ 281 [color.T(ind[2], ind[1], ind[0])])]) 282 elif colors == [8, 8, 8]: 283 # Triple glue coupling 284 my_color_string = color.ColorString(\ 285 [color.f(ind[0], ind[1], ind[2])]) 286 my_color_string.is_imaginary = True 287 myinter.set('color', [my_color_string]) 288 elif colors == [-3, 3, 8, 8]: 289 my_cs1 = color.ColorString(\ 290 [color.T(ind[2], ind[3], ind[1], ind[0])]) 291 my_cs2 = color.ColorString(\ 292 [color.T(ind[3], ind[2], ind[1], ind[0])]) 293 myinter.set('color', [my_cs1, my_cs2]) 294 elif colors == [8, 8, 8, 8]: 295 # 4-glue coupling 296 cs1 = color.ColorString([color.f(0, 1, -1), 297 color.f(2, 3, -1)]) 298 #cs1.coeff = fractions.Fraction(-1) 299 cs2 = color.ColorString([color.f(2, 0, -1), 300 color.f(1, 3, -1)]) 301 #cs2.coeff = fractions.Fraction(-1) 302 cs3 = color.ColorString([color.f(1, 2, -1), 303 color.f(0, 3, -1)]) 304 #cs3.coeff = fractions.Fraction(-1) 305 myinter.set('color', [cs1, cs2, cs3]) 306 # The following line are expected to be correct but not physical validations 307 # have been performed. So we keep it commented for the moment. 308 # elif colors == [3, 3, 3]: 309 # my_color_string = color.ColorString(\ 310 # [color.Epsilon(ind[0], ind[1], ind[2])]) 311 # myinter.set('color', [my_color_string]) 312 # elif colors == [-3, -3, -3]: 313 # my_color_string = color.ColorString(\ 314 # [color.EpsilonBar(ind[0], ind[1], ind[2])]) 315 # myinter.set('color', [my_color_string]) 316 else: 317 logger.warning(\ 318 "Color combination %s not yet implemented." % \ 319 repr(colors)) 320 321 # Set the Lorentz structure. Default for 3-particle 322 # vertices is empty string, for 4-particle pair of 323 # empty strings 324 myinter.set('lorentz', ['']) 325 326 pdg_codes = sorted([part.get_pdg_code() for part in part_list]) 327 328 # WWWW and WWVV 329 if pdg_codes == [-24, -24, 24, 24]: 330 myinter.set('lorentz', ['WWWW']) 331 elif spin_array == [3, 3, 3, 3] and \ 332 24 in pdg_codes and - 24 in pdg_codes: 333 myinter.set('lorentz', ['WWVV']) 334 335 # gggg 336 if pdg_codes == [21, 21, 21, 21]: 337 myinter.set('lorentz', ['gggg1', 'gggg2', 'gggg3']) 338 339 # go-go-g 340 # Using the special fvigox routine provides the minus 341 # sign necessary for octet Majorana-vector interactions 342 if spin_array == [2, 2, 3] and colors == [8, 8, 8] and \ 343 part_list[0].get('self_antipart') and \ 344 part_list[1].get('self_antipart'): 345 myinter.set('lorentz', ['go']) 346 347 # If extra flag, add this to Lorentz 348 if len(values) > 3 * len(part_list) - 4: 349 myinter.get('lorentz')[0] = \ 350 myinter.get('lorentz')[0]\ 351 + values[3 * len(part_list) - 4].upper() 352 353 # Use the other strings to fill variable names and tags 354 355 # Couplings: special treatment for 4-vertices, where MG4 used 356 # two couplings, while MG5 only uses one (with the exception 357 # of the 4g vertex, which needs special treatment) 358 # DUM0 and DUM1 are used as placeholders by FR, corresponds to 1 359 if len(part_list) == 3 or \ 360 values[len(part_list) + 1] in ['DUM', 'DUM0', 'DUM1']: 361 # We can just use the first coupling, since the second 362 # is a dummy 363 myinter.set('couplings', {(0, 0):values[len(part_list)]}) 364 if myinter.get('lorentz')[0] == 'WWWWN': 365 # Should only use one Helas amplitude for electroweak 366 # 4-vector vertices with FR. I choose W3W3NX. 367 myinter.set('lorentz', ['WWVVN']) 368 elif values[len(part_list)] in ['DUM', 'DUM0', 'DUM1']: 369 # We can just use the second coupling, since the first 370 # is a dummy 371 myinter.set('couplings', {(0, 0):values[len(part_list)+1]}) 372 elif pdg_codes == [21, 21, 21, 21]: 373 # gggg 374 myinter.set('couplings', {(0, 0):values[len(part_list)], 375 (1, 1):values[len(part_list)], 376 (2, 2):values[len(part_list)]}) 377 elif myinter.get('lorentz')[0] == 'WWWW': 378 # Need special treatment of v4 SM WWWW couplings since 379 # MG5 can only have one coupling per Lorentz structure 380 myinter.set('couplings', {(0, 0):\ 381 'sqrt(' + 382 values[len(part_list)] + \ 383 '**2+' + \ 384 values[len(part_list) + 1] + \ 385 '**2)'}) 386 else: #if myinter.get('lorentz')[0] == 'WWVV': 387 # Need special treatment of v4 SM WWVV couplings since 388 # MG5 can only have one coupling per Lorentz structure 389 myinter.set('couplings', {(0, 0):values[len(part_list)] + \ 390 '*' + \ 391 values[len(part_list) + 1]}) 392 #raise Interaction.PhysicsObjectError, \ 393 # "Only FR-style 4-vertices implemented." 394 395 # SPECIAL TREATMENT OF COLOR 396 # g g sq sq (two different color structures, same Lorentz) 397 if spin_array == [3, 3, 1, 1] and colors == [-3, 3, 8, 8]: 398 myinter.set('couplings', {(0, 0):values[len(part_list)], 399 (1, 0):values[len(part_list)]}) 400 401 # Coupling orders - needs to be fixed 402 order_list = values[2 * len(part_list) - 2: \ 403 3 * len(part_list) - 4] 404 405 def count_duplicates_in_list(dupedlist): 406 """return a dictionary with key the element of dupeList and 407 with value the number of times that they are in this list""" 408 unique_set = set(item for item in dupedlist) 409 ret_dict = {} 410 for item in unique_set: 411 ret_dict[item] = dupedlist.count(item) 412 return ret_dict
413 414 myinter.set('orders', count_duplicates_in_list(order_list)) 415 416 myinter.set('id', len(myinterlist) + 1) 417 418 myinterlist.append(myinter) 419 420 except Interaction.PhysicsObjectError, why: 421 logger.error("Interaction ignored: %s" % why) 422 423 return myinterlist 424
425 #=============================================================================== 426 # read_proc_card.dat (mg4 format) 427 #=============================================================================== 428 -def read_proc_card_v4(fsock):
429 """A simple function reading the files in fsock and returning a 430 ProcCardv4Reader object. This function authorize to have the same syntax as 431 for the other files treatment""" 432 433 reader = ProcCardv4Reader(fsock) 434 return reader
435
436 -class ParticleError(InvalidCmd):
437 """ A class to carch the error""" 438 pass
439
440 -class WrongFileFormat(InvalidCmd):
441 """A specific class error for wrong V4 proc_card""" 442 pass 443
444 -class ProcCardv4Reader(object):
445 """read a proc_card.dat in the mg4 format and creates the equivalent routine 446 for mg5""" 447 448 #tag in the proc_card.dat which split the proc_card content 449 450 # line pattern (remove comment at the end of the line) 451 pat_line = re.compile(r"""^\s*(?P<info>[^\#]*?)\s*(\#|$)""", re.DOTALL) 452
453 - def __init__(self, fsock):
454 """init the variable""" 455 456 self.process = [] # List of ProcessInfo 457 self.model = "" # name of the model 458 self.multipart = [] # list of the mg4 definition of multiparticle 459 self.particles_name = set() # set of authorize particle name 460 self.couplings_name = set() # set of mandatory couplings 461 self.process_path = os.path.realpath(os.path.join( 462 os.path.dirname(fsock.name), os.pardir)) 463 464 # Reading the files and store the information in string format. 465 self.analyze_v4_proc_card(fsock)
466 467
468 - def analyze_v4_proc_card(self, fsock):
469 """read the file and fullfill the variable with mg4 line""" 470 471 proc_card = fsock.read() 472 473 # store process information 474 process_open = False 475 476 process_re = re.search(\ 477 r"^# Begin\s+PROCESS.*?^(?P<process>.*)^# End\s+PROCESS", 478 proc_card, re.MULTILINE|re.DOTALL) 479 480 if not process_re: 481 raise WrongFileFormat('No valid Begin...End PROCESS tags') 482 483 model_re = re.search(\ 484 r"^# Begin\s+MODEL.*?^(?P<model>.+?)(\s+|$)^# End\s+MODEL", 485 proc_card, re.MULTILINE|re.DOTALL) 486 487 if not model_re: 488 raise WrongFileFormat('No valid Begin...End MODEL tags') 489 490 multiparticles_re = re.search(\ 491 r"^# Begin\s+MULTIPARTICLES.*?^(?P<multiparticles>.*)^# End\s+MULTIPARTICLES", 492 proc_card, re.MULTILINE|re.DOTALL) 493 494 if not multiparticles_re: 495 raise WrongFileFormat('No valid Begin...End MULTIPARTICLES tags') 496 497 process_lines = process_re.group('process').split('\n') 498 499 for line in process_lines: 500 # an 'end_coup' stop the current process, 501 # 'done' finish the list of process 502 analyze_line = self.pat_line.search(line) 503 if analyze_line: 504 data = analyze_line.group('info') #skip the comment 505 if not data: 506 continue 507 if not process_open and 'done' not in data: 508 process_open = True 509 self.process.append(ProcessInfo(data)) 510 elif 'end_coup' in data: 511 process_open = False 512 elif 'done' not in data: 513 self.process[-1].add_coupling(data) 514 515 self.model = model_re.group('model') 516 517 multiparticles_lines = multiparticles_re.group('multiparticles').split('\n') 518 519 for line in multiparticles_lines: 520 analyze_line = self.pat_line.search(line) 521 if analyze_line: 522 line = analyze_line.group('info') #skip the comment 523 if not line: 524 continue 525 data = line.split() 526 self.particles_name.add(data[0].lower()) 527 self.multipart.append(line)
528 529
530 - def extract_command_lines(self, model):
531 """Return the MG5 command line corresponding to this proc_card 532 the MG5 command import model is skipped (since the model should be 533 loaded -it is one of the argument-)""" 534 535 # extract useful information of the model 536 self.extract_info_from_model(model) 537 538 # use the model information for the splitting in particles of the mg4 539 #process line. 540 for process in self.process: 541 process.analyze_process(self.particles_name) 542 543 #Now we are in position to write the lines call 544 lines = [] 545 #first write the lines associate to the multiparticls definition 546 if self.multipart: 547 lines.append('# Define multiparticle labels') 548 for multipart in self.multipart: 549 data = self.separate_particle(multipart, self.particles_name) 550 lines.append('define ' + ' '.join(data)) 551 552 # secondly define the lines associate with diagram 553 if self.process: 554 lines.append('# Specify process(es) to run') 555 for i, process in enumerate(self.process): 556 if i == 0: 557 lines.append('generate %s' % \ 558 process.mg5_process_line(self.couplings_name)) 559 else: 560 lines.append('add process %s' % \ 561 process.mg5_process_line(self.couplings_name)) 562 563 #finally export the madevent output 564 lines.append('# Output processes to MadEvent directory') 565 lines.append('output -f') 566 567 return lines
568 569
570 - def extract_info_from_model(self, model):
571 """ creates the self.particles_name (list of all valid name) 572 and self.couplings_name (list of all couplings)""" 573 574 # add in self.particles_name (it contains normally the mulpart name 575 #already) all the valid name of particle of the model 576 for particle in model['particles']: 577 self.particles_name.add(particle['name']) 578 self.particles_name.add(particle['antiname']) 579 580 # add in self.couplings_name the couplings name of the model 581 for interaction in model['interactions']: 582 for coupling in interaction['orders'].keys(): 583 self.couplings_name.add(coupling)
584 585 586 @staticmethod
587 - def separate_particle(line, possible_str):
588 """ for a list of concatanate variable return a list of particle name""" 589 590 line = line.lower() # Particle name are not case sensitive 591 out = [] # list of the particles 592 # The procedure to find particles is the following 593 # - check if the combination of 4 string form a valid particle name 594 # if it is, move of 4 characters and check for the next particles. 595 # if not try with 3, 2, 1 596 # if still not -> exit. 597 598 pos = 0 # current starting position 599 old_pos = -1 # check that we don't have infinite loop 600 line += ' ' #add 4 blank for security 601 while pos < len(line) - 4: 602 #Check for infinite loop 603 if pos == old_pos: 604 logging.error('Invalid particle name: %s' % \ 605 line[pos:pos + 4].rstrip()) 606 raise ParticleError('Invalid particle name %s' % 607 line[pos:pos + 4].rstrip()) 608 old_pos = pos 609 # check for pointless character 610 if line[pos] in [' ', '\n', '\t']: 611 pos += 1 612 continue 613 614 # try to find a match at 4(then 3/2/1) characters 615 for i in range(4, 0, -1): 616 if line[pos:pos + i] in possible_str: 617 out.append(line[pos:pos + i]) 618 pos = pos + i 619 break 620 621 return out
622
623 -class ProcessInfo(object):
624 """This is the basic object for storing process information""" 625
626 - def __init__(self, line):
627 """Initialize information""" 628 629 self.particles = [] # list tuple (level, particle) 630 self.couplings = {} # coupling -> max_order 631 self.decays = [] # ProcessInfo of the decays 632 self.tag = '' # tag of the process 633 self.s_forbid = [] # list of particles forbids in s channel 634 self.forbid = [] # list of particles forbids 635 self.line = line # initialization line 636 637 self.is_mg5_valid = False 638 #some shortcut 639 self.separate_particle = ProcCardv4Reader.separate_particle
640
641 - def analyze_process(self, particles_name):
642 """Add a line information 643 two format are possible (decay chains or not) 644 pp>h>WWj /a $u @3 645 pp>(h>WW)j /a $u @3 646 """ 647 648 line = self.line 649 #extract the tag 650 if '@' in line: 651 split = line.split('@') 652 line = split[0] 653 self.tag = split[1] 654 655 656 # check if we have a MG5 format 657 if '/mg5/' in line: 658 self.line = line.replace('/mg5/','') 659 self.is_mg5_valid = True 660 return 661 if ',' in line or '=' in line: 662 self.is_mg5_valid = True 663 return 664 665 # extract (S-)forbidden particle 666 pos_forbid = line.find('/') 667 pos_sforbid = line.find('$') 668 669 # Select the restrictions (pos is -1 if not defined) 670 #and remove the restrictions from the line 671 if pos_forbid != -1 and pos_sforbid != -1: 672 if pos_forbid > pos_sforbid : 673 self.forbid = self.separate_particle(line[pos_forbid + 1:], \ 674 particles_name) 675 self.s_forbid = self.separate_particle(\ 676 line[pos_sforbid + 1:pos_forbid], particles_name) 677 line = line[:min(pos_forbid, pos_sforbid)] 678 else: 679 self.forbid = self.separate_particle(\ 680 line[pos_forbid + 1:pos_sforbid], particles_name) 681 self.s_forbid = self.separate_particle(line[pos_sforbid + 1:], \ 682 particles_name) 683 line = line[:min(pos_forbid, pos_sforbid)] 684 # Same but if they are no S-forbidden particles 685 elif pos_forbid != -1: 686 self.forbid = self.separate_particle(line[pos_forbid + 1:], \ 687 particles_name) 688 line = line[:pos_forbid] 689 # Same but if they are no forbidden particles 690 elif pos_sforbid != -1: 691 self.s_forbid = self.separate_particle(line[pos_sforbid + 1:], \ 692 particles_name) 693 line = line[:pos_sforbid] 694 695 # Deal with decay chains, returns lines whitout the decay (and treat 696 #the different decays. 697 if '(' in line: 698 line = self.treat_decay_chain(line, particles_name) 699 700 #define the level of each particle 701 level_content = line.split('>') 702 for level, data in enumerate(level_content): 703 particles = self.separate_particle(data, particles_name) 704 if particles: 705 [self.particles.append((level, name)) for name in particles]
706 707
708 - def treat_decay_chain(self, line, particles_name):
709 """Split the information of the decays into a tree of ProcessInfo.""" 710 711 level = 0 #depth of the decay chain 712 out_line = '' # core process 713 for character in line: 714 if character == '(': 715 level += 1 716 if level == 1: 717 decay_line = "" # initialize a new decay info 718 else: 719 decay_line += '(' 720 continue 721 elif character == ')': 722 level -= 1 723 if level == 0: #store the information 724 self.decays.append(ProcessInfo(decay_line)) 725 self.decays[-1].add_restrictions(self.forbid, self.s_forbid, 726 None) 727 self.decays[-1].analyze_process(particles_name) 728 out_line += decay_line[:decay_line.find('>')] 729 else: 730 decay_line += ')' 731 continue 732 elif level: 733 decay_line += character 734 else: 735 out_line += character 736 return out_line
737
738 - def add_coupling(self, line):
739 """Add the coupling information to the process""" 740 data = line.split('=') 741 self.couplings[data[0]] = int(data[1])
742 743
744 - def add_restrictions(self, forbid, s_forbid, couplings):
745 """Associate some restriction to this diagram""" 746 747 self.forbid = forbid 748 self.s_forbid = s_forbid 749 self.couplings = couplings
750
751 - def mg5_process_line(self, model_coupling):
752 """Return a valid mg5 format for this process """ 753 754 if self.is_mg5_valid: 755 return self.line 756 757 text = '' 758 # Write the process 759 cur_level = 0 760 for level, particle in self.particles: 761 if level > cur_level: 762 text += '> ' 763 cur_level += 1 764 text += '%s ' % particle 765 766 # Write the constraints 767 if self.s_forbid: 768 text += '$ ' + ' '.join(self.s_forbid) + ' ' 769 if self.forbid: 770 text += '/ ' + ' '.join(self.forbid) + ' ' 771 772 #treat decay_chains 773 for decay in self.decays: 774 decay_text = decay.mg5_process_line(model_coupling) 775 if ',' in decay_text: 776 text = text.rstrip() + ', (%s) ' % decay_text.strip() 777 else: 778 text = text.rstrip() + ', %s ' % decay_text.strip() 779 780 # write the tag 781 if self.tag: 782 text += '@%s ' % self.tag 783 784 if self.couplings: 785 if not self.tag: 786 text += '@0 ' 787 #write the rules associate to the couplings 788 text += self.mg5_couplings_line(model_coupling, len(self.particles)) 789 790 return text.rstrip()
791
792 - def mg5_couplings_line(self, model_coupling, nb_part):
793 """Return the assignment of coupling for this process""" 794 795 out = '' 796 for coupling in model_coupling: 797 if self.couplings.has_key(coupling): 798 # Need coupling for all cases, since might be decay chain 799 out += '%s=%s ' % (coupling, self.couplings[coupling]) 800 else: 801 # if not define put to zero (mg4 default) 802 out += '%s=0 ' % coupling 803 804 return out
805