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

Source Code for Module madgraph.iolibs.helas_call_writers

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2010 The MadGraph Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph 5 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 MadGraph license which should accompany this  
  10  # distribution. 
  11  # 
  12  # For more information, please visit: http://madgraph.phys.ucl.ac.be 
  13  # 
  14  ################################################################################ 
  15  """Classes for writing Helas calls. HelasCallWriter is the base class.""" 
  16   
  17  import madgraph.core.base_objects as base_objects 
  18  import madgraph.core.helas_objects as helas_objects 
  19  import aloha.aloha_writers as aloha_writers 
20 21 -class HelasWriterError(Exception):
22 """Class for the error of this module """ 23 pass
24
25 #=============================================================================== 26 # HelasCallWriter 27 #=============================================================================== 28 -class HelasCallWriter(base_objects.PhysicsObject):
29 """Language independent base class for writing Helas calls. The 30 calls are stored in two dictionaries, wavefunctions and 31 amplitudes, with entries being a mapping from a set of spin, 32 incoming/outgoing states and Lorentz structure to a function which 33 writes the corresponding wavefunction/amplitude call (taking a 34 HelasWavefunction/HelasAmplitude as argument).""" 35 36 # Dictionaries used for automatic generation of Helas calls 37 # Dictionaries from spin states to letters in Helas call 38 mother_dict = {1: 'S', 2: 'O', -2: 'I', 3: 'V', 5: 'T'} 39
40 - def default_setup(self):
41 42 self['model'] = base_objects.Model() 43 self['wavefunctions'] = {} 44 self['amplitudes'] = {}
45
46 - def filter(self, name, value):
47 """Filter for model property values""" 48 49 if name == 'model': 50 if not isinstance(value, base_objects.Model): 51 raise self.PhysicsObjectError, \ 52 "Object of type %s is not a model" % type(value) 53 54 if name == 'wavefunctions': 55 # Should be a dictionary of functions returning strings, 56 # with keys (spins, flow state) 57 if not isinstance(value, dict): 58 raise self.PhysicsObjectError, \ 59 "%s is not a valid dictionary for wavefunction" % \ 60 str(value) 61 62 for key in value.keys(): 63 self.add_wavefunction(key, value[key]) 64 65 if name == 'amplitudes': 66 # Should be a dictionary of functions returning strings, 67 # with keys (spins, flow state) 68 if not isinstance(value, dict): 69 raise self.PhysicsObjectError, \ 70 "%s is not a valid dictionary for amplitude" % \ 71 str(value) 72 73 for key in value.keys(): 74 self.add_amplitude(key, value[key]) 75 76 return True
77
78 - def get_sorted_keys(self):
79 """Return process property names as a nicely sorted list.""" 80 81 return ['model', 'wavefunctions', 'amplitudes']
82
83 - def get_matrix_element_calls(self, matrix_element):
84 """Return a list of strings, corresponding to the Helas calls 85 for the matrix element""" 86 87 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \ 88 "%s not valid argument for get_matrix_element_calls" % \ 89 repr(matrix_element) 90 91 res = [] 92 for diagram in matrix_element.get('diagrams'): 93 res.extend([ self.get_wavefunction_call(wf) for \ 94 wf in diagram.get('wavefunctions') ]) 95 res.append("# Amplitude(s) for diagram number %d" % \ 96 diagram.get('number')) 97 for amplitude in diagram.get('amplitudes'): 98 res.append(self.get_amplitude_call(amplitude)) 99 100 return res
101
102 - def get_wavefunction_calls(self, wavefunctions):
103 """Return a list of strings, corresponding to the Helas calls 104 for the matrix element""" 105 106 assert isinstance(wavefunctions, helas_objects.HelasWavefunctionList), \ 107 "%s not valid argument for get_wavefunction_calls" % \ 108 repr(wavefunctions) 109 110 res = [self.get_wavefunction_call(wf) for wf in wavefunctions] 111 112 return res
113
114 - def get_amplitude_calls(self, matrix_element):
115 """Return a list of strings, corresponding to the Helas calls 116 for the matrix element""" 117 118 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \ 119 "%s not valid argument for get_matrix_element_calls" % \ 120 repr(matrix_element) 121 122 res = [] 123 for diagram in matrix_element.get('diagrams'): 124 res.append("# Amplitude(s) for diagram number %d" % \ 125 diagram.get('number')) 126 for amplitude in diagram.get('amplitudes'): 127 res.append(self.get_amplitude_call(amplitude)) 128 129 return res
130
131 - def get_wavefunction_call(self, wavefunction):
132 """Return the function for writing the wavefunction 133 corresponding to the key""" 134 135 try: 136 call = self["wavefunctions"][wavefunction.get_call_key()](\ 137 wavefunction) 138 return call 139 except KeyError: 140 return ""
141
142 - def get_amplitude_call(self, amplitude):
143 """Return the function for writing the amplitude 144 corresponding to the key""" 145 146 try: 147 call = self["amplitudes"][amplitude.get_call_key()](amplitude) 148 return call 149 except KeyError: 150 return ""
151
152 - def add_wavefunction(self, key, function):
153 """Set the function for writing the wavefunction 154 corresponding to the key""" 155 156 assert isinstance(key, tuple), \ 157 "%s is not a valid tuple for wavefunction key" % key 158 159 assert callable(function), \ 160 "%s is not a valid function for wavefunction string" % function 161 162 self.get('wavefunctions')[key] = function 163 return True
164
165 - def add_amplitude(self, key, function):
166 """Set the function for writing the amplitude 167 corresponding to the key""" 168 169 assert isinstance(key, tuple), \ 170 "%s is not a valid tuple for amplitude key" % str(key) 171 172 assert callable(function), \ 173 "%s is not a valid function for amplitude string" % str(function) 174 175 176 self.get('amplitudes')[key] = function 177 return True
178
179 - def get_model_name(self):
180 """Return the model name""" 181 return self['model'].get('name')
182 183 # Customized constructor
184 - def __init__(self, argument={}):
185 """Allow generating a HelasCallWriter from a Model 186 """ 187 188 if isinstance(argument, base_objects.Model): 189 super(HelasCallWriter, self).__init__() 190 self.set('model', argument) 191 else: 192 super(HelasCallWriter, self).__init__(argument)
193
194 195 196 197 #=============================================================================== 198 # FortranHelasCallWriter 199 #=============================================================================== 200 -class FortranHelasCallWriter(HelasCallWriter):
201 """The class for writing Helas calls in Fortran, starting from 202 HelasWavefunctions and HelasAmplitudes. 203 204 Includes the function generate_helas_call, which automatically 205 generates the Fortran Helas call based on the Lorentz structure of 206 the interaction.""" 207 208 # Dictionaries used for automatic generation of Helas calls 209 # Dictionaries from spin states to letters in Helas call 210 self_dict = {1: 'H', 2: 'F', -2: 'F', 3: 'J', 5: 'U'} 211 # Dictionaries used for sorting the letters in the Helas call 212 sort_wf = {'O': 0, 'I': 1, 'S': 2, 'T': 3, 'V': 4} 213 sort_amp = {'S': 0, 'V': 2, 'T': 1, 'O': 3, 'I': 4} 214
215 - def default_setup(self):
216 """Set up special Helas calls (wavefunctions and amplitudes) 217 that can not be done automatically by generate_helas_call""" 218 219 super(FortranHelasCallWriter, self).default_setup() 220 221 # Add special fortran Helas calls, which are not automatically 222 # generated 223 224 # Gluon 4-vertex division tensor calls ggT for the FR sm and mssm 225 226 key = ((3, 3, 5, 3), ('A',)) 227 call = lambda wf: \ 228 "CALL UVVAXX(W(1,%d),W(1,%d),%s,zero,zero,zero,W(1,%d))" % \ 229 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'), 230 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'), 231 wf.get('coupling')[0], 232 wf.get('number')) 233 self.add_wavefunction(key, call) 234 235 key = ((3, 5, 3, 1), ('A',)) 236 call = lambda wf: \ 237 "CALL JVTAXX(W(1,%d),W(1,%d),%s,zero,zero,W(1,%d))" % \ 238 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'), 239 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'), 240 wf.get('coupling')[0], 241 wf.get('number')) 242 self.add_wavefunction(key, call) 243 244 key = ((3, 3, 5), ('A',)) 245 call = lambda amp: \ 246 "CALL VVTAXX(W(1,%d),W(1,%d),W(1,%d),%s,zero,AMP(%d))" % \ 247 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'), 248 FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'), 249 FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'), 250 amp.get('coupling')[0], 251 amp.get('number')) 252 self.add_amplitude(key, call) 253 254 # SM gluon 4-vertex components 255 256 key = ((3, 3, 3, 3, 1), ('gggg3',)) 257 call = lambda wf: \ 258 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \ 259 (FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'), 260 FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'), 261 FortranHelasCallWriter.sorted_mothers(wf)[2].get('number'), 262 wf.get('coupling')[0], 263 wf.get('number')) 264 self.add_wavefunction(key, call) 265 key = ((3, 3, 3, 3), ('gggg1',)) 266 call = lambda amp: \ 267 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \ 268 (FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'), 269 FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'), 270 FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'), 271 FortranHelasCallWriter.sorted_mothers(amp)[3].get('number'), 272 amp.get('coupling')[0], 273 amp.get('number')) 274 self.add_amplitude(key, call) 275 key = ((3, 3, 3, 3, 1), ('gggg2',)) 276 call = lambda wf: \ 277 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \ 278 (FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'), 279 FortranHelasCallWriter.sorted_mothers(wf)[2].get('number'), 280 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'), 281 wf.get('coupling')[0], 282 wf.get('number')) 283 self.add_wavefunction(key, call) 284 key = ((3, 3, 3, 3), ('gggg2',)) 285 call = lambda amp: \ 286 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \ 287 (FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'), 288 FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'), 289 FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'), 290 FortranHelasCallWriter.sorted_mothers(amp)[3].get('number'), 291 amp.get('coupling')[0], 292 amp.get('number')) 293 self.add_amplitude(key, call) 294 key = ((3, 3, 3, 3, 1), ('gggg1',)) 295 call = lambda wf: \ 296 "CALL JGGGXX(W(1,%d),W(1,%d),W(1,%d),%s,W(1,%d))" % \ 297 (FortranHelasCallWriter.sorted_mothers(wf)[2].get('number'), 298 FortranHelasCallWriter.sorted_mothers(wf)[1].get('number'), 299 FortranHelasCallWriter.sorted_mothers(wf)[0].get('number'), 300 wf.get('coupling')[0], 301 wf.get('number')) 302 self.add_wavefunction(key, call) 303 key = ((3, 3, 3, 3), ('gggg3',)) 304 call = lambda amp: \ 305 "CALL GGGGXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),%s,AMP(%d))" % \ 306 (FortranHelasCallWriter.sorted_mothers(amp)[1].get('number'), 307 FortranHelasCallWriter.sorted_mothers(amp)[2].get('number'), 308 FortranHelasCallWriter.sorted_mothers(amp)[0].get('number'), 309 FortranHelasCallWriter.sorted_mothers(amp)[3].get('number'), 310 amp.get('coupling')[0], 311 amp.get('number')) 312 self.add_amplitude(key, call) 313 314 # HEFT VVVS calls 315 316 key = ((1, 3, 3, 3, 3), ('',)) 317 call = lambda wf: \ 318 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \ 319 (wf.get('mothers')[0].get('number'), 320 wf.get('mothers')[1].get('number'), 321 wf.get('mothers')[2].get('number'), 322 wf.get('coupling')[0], 323 wf.get('mass'), 324 wf.get('width'), 325 wf.get('number')) 326 self.add_wavefunction(key, call) 327 328 key = ((3, 3, 3, 1, 4), ('',)) 329 call = lambda wf: \ 330 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \ 331 (wf.get('mothers')[0].get('number'), 332 wf.get('mothers')[1].get('number'), 333 wf.get('mothers')[2].get('number'), 334 wf.get('coupling')[0], 335 wf.get('mass'), 336 wf.get('width'), 337 wf.get('number')) 338 self.add_wavefunction(key, call) 339 340 key = ((1, 3, 3, 3), ('',)) 341 call = lambda amp: \ 342 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \ 343 (amp.get('mothers')[0].get('number'), 344 amp.get('mothers')[1].get('number'), 345 amp.get('mothers')[2].get('number'), 346 amp.get('mothers')[3].get('number'), 347 amp.get('coupling')[0], 348 amp.get('number')) 349 self.add_amplitude(key, call) 350 351 # HEFT VVVS calls 352 353 key = ((1, 3, 3, 3, 1), ('',)) 354 call = lambda wf: \ 355 "CALL JVVSXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \ 356 (wf.get('mothers')[0].get('number'), 357 wf.get('mothers')[1].get('number'), 358 wf.get('mothers')[2].get('number'), 359 wf.get('coupling')[0], 360 wf.get('mass'), 361 wf.get('width'), 362 wf.get('number')) 363 self.add_wavefunction(key, call) 364 365 key = ((3, 3, 3, 1, 4), ('',)) 366 call = lambda wf: \ 367 "CALL HVVVXX(W(1,%d),W(1,%d),W(1,%d),DUM1,%s,%s,%s,W(1,%d))" % \ 368 (wf.get('mothers')[0].get('number'), 369 wf.get('mothers')[1].get('number'), 370 wf.get('mothers')[2].get('number'), 371 wf.get('coupling')[0], 372 wf.get('mass'), 373 wf.get('width'), 374 wf.get('number')) 375 self.add_wavefunction(key, call) 376 377 key = ((1, 3, 3, 3), ('',)) 378 call = lambda amp: \ 379 "CALL VVVSXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),DUM1,%s,AMP(%d))" % \ 380 (amp.get('mothers')[0].get('number'), 381 amp.get('mothers')[1].get('number'), 382 amp.get('mothers')[2].get('number'), 383 amp.get('mothers')[3].get('number'), 384 amp.get('coupling')[0], 385 amp.get('number')) 386 self.add_amplitude(key, call) 387 388 # Spin2 Helas Routine 389 key = ((-2, 2, 5), ('',)) 390 call = lambda amp: \ 391 "CALL IOTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \ 392 (amp.get('mothers')[0].get('number'), 393 amp.get('mothers')[1].get('number'), 394 amp.get('mothers')[2].get('number'), 395 amp.get('coupling')[0], 396 amp.get('mothers')[0].get('mass'), 397 amp.get('number')) 398 self.add_amplitude(key, call) 399 400 key = ((-2, 2, 5, 3), ('',)) 401 call = lambda wf: \ 402 "CALL UIOXXX(W(1,%d),W(1,%d),%s,%s,%s,%s,W(1,%d))" % \ 403 (wf.get('mothers')[0].get('number'), 404 wf.get('mothers')[1].get('number'), 405 wf.get('coupling')[0], 406 wf.get('mothers')[0].get('mass'), 407 wf.get('mass'), 408 wf.get('width'), 409 wf.get('number')) 410 self.add_wavefunction(key, call) 411 412 key = ((3,3,3,5),('',)) 413 call = lambda amp: \ 414 "CALL VVVTXX(W(1,%d),W(1,%d),W(1,%d),W(1,%d),1d0,%s,AMP(%d))" % \ 415 (amp.get('mothers')[0].get('number'), 416 amp.get('mothers')[1].get('number'), 417 amp.get('mothers')[2].get('number'), 418 amp.get('mothers')[3].get('number'), 419 amp.get('coupling')[0], 420 amp.get('number')) 421 self.add_amplitude(key, call) 422 423 key = ((3,3,5),('',)) 424 call = lambda amp: \ 425 "CALL VVTXXX(W(1,%d),W(1,%d),W(1,%d),%s,%s,AMP(%d))" % \ 426 (amp.get('mothers')[0].get('number'), 427 amp.get('mothers')[1].get('number'), 428 amp.get('mothers')[2].get('number'), 429 amp.get('coupling')[0], 430 amp.get('mothers')[0].get('mass'), 431 amp.get('number')) 432 self.add_amplitude(key, call)
433 434
435 - def get_wavefunction_call(self, wavefunction):
436 """Return the function for writing the wavefunction 437 corresponding to the key. If the function doesn't exist, 438 generate_helas_call is called to automatically create the 439 function.""" 440 441 if wavefunction.get('spin') == 1 and \ 442 wavefunction.get('interaction_id') != 0: 443 # Special feature: For HVS vertices with the two 444 # scalars different, we need extra minus sign in front 445 # of coupling for one of the two scalars since the HVS 446 # is asymmetric in the two scalars 447 wavefunction.set_scalar_coupling_sign(self['model']) 448 449 val = super(FortranHelasCallWriter, self).get_wavefunction_call(wavefunction) 450 451 if val: 452 return val 453 454 # If function not already existing, try to generate it. 455 456 if len(wavefunction.get('mothers')) > 3: 457 raise self.PhysicsObjectError, \ 458 """Automatic generation of Fortran wavefunctions not 459 implemented for > 3 mothers""" 460 461 self.generate_helas_call(wavefunction) 462 return super(FortranHelasCallWriter, self).get_wavefunction_call(\ 463 wavefunction)
464
465 - def get_amplitude_call(self, amplitude):
466 """Return the function for writing the amplitude corresponding 467 to the key. If the function doesn't exist, generate_helas_call 468 is called to automatically create the function.""" 469 470 val = super(FortranHelasCallWriter, self).get_amplitude_call(amplitude) 471 472 if val: 473 return val 474 475 # If function not already existing, try to generate it. 476 477 if len(amplitude.get('mothers')) > 4: 478 raise self.PhysicsObjectError, \ 479 """Automatic generation of Fortran amplitudes not 480 implemented for > 4 mothers""" 481 482 self.generate_helas_call(amplitude) 483 return super(FortranHelasCallWriter, self).get_amplitude_call(amplitude)
484
485 - def generate_helas_call(self, argument):
486 """Routine for automatic generation of Fortran Helas calls 487 according to just the spin structure of the interaction. 488 489 First the call string is generated, using a dictionary to go 490 from the spin state of the calling wavefunction and its 491 mothers, or the mothers of the amplitude, to letters. 492 493 Then the call function is generated, as a lambda which fills 494 the call string with the information of the calling 495 wavefunction or amplitude. The call has different structure, 496 depending on the spin of the wavefunction and the number of 497 mothers (multiplicity of the vertex). The mother 498 wavefunctions, when entering the call, must be sorted in the 499 correct way - this is done by the sorted_mothers routine. 500 501 Finally the call function is stored in the relevant 502 dictionary, in order to be able to reuse the function the next 503 time a wavefunction with the same Lorentz structure is needed. 504 """ 505 506 if not isinstance(argument, helas_objects.HelasWavefunction) and \ 507 not isinstance(argument, helas_objects.HelasAmplitude): 508 raise self.PhysicsObjectError, \ 509 "get_helas_call must be called with wavefunction or amplitude" 510 511 call = "CALL " 512 513 call_function = None 514 515 if isinstance(argument, helas_objects.HelasAmplitude) and \ 516 argument.get('interaction_id') == 0: 517 call = "#" 518 call_function = lambda amp: call 519 520 self.add_amplitude(argument.get_call_key(), call_function) 521 return 522 523 if isinstance(argument, helas_objects.HelasWavefunction) and \ 524 not argument.get('mothers'): 525 # String is just IXXXXX, OXXXXX, VXXXXX or SXXXXX 526 call = call + HelasCallWriter.mother_dict[\ 527 argument.get_spin_state_number()] 528 # Fill out with X up to 6 positions 529 call = call + 'X' * (11 - len(call)) 530 call = call + "(P(0,%d)," 531 if argument.get('spin') != 1: 532 # For non-scalars, need mass and helicity 533 call = call + "%s,NHEL(%d)," 534 call = call + "%+d*IC(%d),W(1,%d))" 535 if argument.get('spin') == 1: 536 call_function = lambda wf: call % \ 537 (wf.get('number_external'), 538 # For boson, need initial/final here 539 (-1) ** (wf.get('state') == 'initial'), 540 wf.get('number_external'), 541 wf.get('number')) 542 elif argument.is_boson(): 543 call_function = lambda wf: call % \ 544 (wf.get('number_external'), 545 wf.get('mass'), 546 wf.get('number_external'), 547 # For boson, need initial/final here 548 (-1) ** (wf.get('state') == 'initial'), 549 wf.get('number_external'), 550 wf.get('number')) 551 else: 552 call_function = lambda wf: call % \ 553 (wf.get('number_external'), 554 wf.get('mass'), 555 wf.get('number_external'), 556 # For fermions, need particle/antiparticle 557 - (-1) ** wf.get_with_flow('is_part'), 558 wf.get('number_external'), 559 wf.get('number')) 560 else: 561 # String is FOVXXX, FIVXXX, JIOXXX etc. 562 if isinstance(argument, helas_objects.HelasWavefunction): 563 call = call + \ 564 FortranHelasCallWriter.self_dict[\ 565 argument.get_spin_state_number()] 566 567 mother_letters = FortranHelasCallWriter.sorted_letters(argument) 568 569 # If Lorentz structure is given, by default add this 570 # to call name 571 lor_name = argument.get('lorentz')[0] 572 573 # Take care of special case: WWWW or WWVV calls 574 if len(lor_name) > 3 and lor_name[:2] == "WW": 575 if lor_name[:4] == "WWWW": 576 mother_letters = "WWWW"[:len(mother_letters)] 577 if lor_name[:4] == "WWVV": 578 mother_letters = "W3W3"[:len(mother_letters)] 579 lor_name = lor_name[4:] 580 581 call = call + mother_letters 582 call = call + lor_name 583 584 # Check if we need to append a charge conjugation flag 585 if argument.needs_hermitian_conjugate(): 586 call = call + 'C' 587 588 assert len(call) < 12, "Call to Helas routine %s should be maximum 6 chars" \ 589 % call[5:] 590 591 # Fill out with X up to 6 positions 592 call = call + 'X' * (11 - len(call)) + '(' 593 # Wavefunctions 594 call = call + "W(1,%d)," * len(argument.get('mothers')) 595 # Couplings 596 call = call + "%s," 597 598 599 if isinstance(argument, helas_objects.HelasWavefunction): 600 # Extra dummy coupling for 4-vector vertices 601 if argument.get('lorentz') == 'WWVV': 602 # SM W3W3 vertex 603 call = call + "1D0," 604 elif argument.get('lorentz') == 'WWWW': 605 # SM WWWW vertex 606 call = call + "0D0," 607 elif argument.get('spin') == 3 and \ 608 [wf.get('spin') for wf in argument.get('mothers')] == \ 609 [3, 3, 3]: 610 # All other 4-vector vertices (FR) - note that gggg 611 # has already been defined 612 call = call + "DUM0," 613 # Mass and width 614 call = call + "%s,%s," 615 # New wavefunction 616 call = call + "W(1,%d))" 617 else: 618 # Extra dummy coupling for 4-particle vertices 619 # Need to replace later with the correct type 620 if argument.get('lorentz') == 'WWVV': 621 # SM W3W3 vertex 622 call = call + "1D0," 623 elif argument.get('lorentz') == 'WWWW': 624 # SM WWWW vertex 625 call = call + "0D0," 626 elif [wf.get('spin') for wf in argument.get('mothers')] == \ 627 [3, 3, 3, 3]: 628 # Other 4-vector vertices (FR) - note that gggg 629 # has already been defined 630 call = call + "DUM0," 631 # Amplitude 632 call = call + "AMP(%d))" 633 634 if isinstance(argument, helas_objects.HelasWavefunction): 635 # Create call for wavefunction 636 if len(argument.get('mothers')) == 2: 637 call_function = lambda wf: call % \ 638 (FortranHelasCallWriter.sorted_mothers(wf)[0].\ 639 get('number'), 640 FortranHelasCallWriter.sorted_mothers(wf)[1].\ 641 get('number'), 642 ','.join(wf.get_with_flow('coupling')), 643 wf.get('mass'), 644 wf.get('width'), 645 wf.get('number')) 646 else: 647 call_function = lambda wf: call % \ 648 (FortranHelasCallWriter.sorted_mothers(wf)[0].\ 649 get('number'), 650 FortranHelasCallWriter.sorted_mothers(wf)[1].\ 651 get('number'), 652 FortranHelasCallWriter.sorted_mothers(wf)[2].\ 653 get('number'), 654 ','.join(wf.get_with_flow('coupling')), 655 wf.get('mass'), 656 wf.get('width'), 657 wf.get('number')) 658 else: 659 # Create call for amplitude 660 if len(argument.get('mothers')) == 3: 661 call_function = lambda amp: call % \ 662 (FortranHelasCallWriter.sorted_mothers(amp)[0].\ 663 get('number'), 664 FortranHelasCallWriter.sorted_mothers(amp)[1].\ 665 get('number'), 666 FortranHelasCallWriter.sorted_mothers(amp)[2].\ 667 get('number'), 668 669 ','.join(amp.get('coupling')), 670 amp.get('number')) 671 else: 672 call_function = lambda amp: call % \ 673 (FortranHelasCallWriter.sorted_mothers(amp)[0].\ 674 get('number'), 675 FortranHelasCallWriter.sorted_mothers(amp)[1].\ 676 get('number'), 677 FortranHelasCallWriter.sorted_mothers(amp)[2].\ 678 get('number'), 679 FortranHelasCallWriter.sorted_mothers(amp)[3].\ 680 get('number'), 681 ','.join(amp.get('coupling')), 682 amp.get('number')) 683 684 # Add the constructed function to wavefunction or amplitude dictionary 685 if isinstance(argument, helas_objects.HelasWavefunction): 686 self.add_wavefunction(argument.get_call_key(), call_function) 687 else: 688 self.add_amplitude(argument.get_call_key(), call_function)
689 690 # Static helper functions 691 692 @staticmethod
693 - def sorted_letters(arg):
694 """Gives a list of letters sorted according to 695 the order of letters in the Fortran Helas calls""" 696 697 if isinstance(arg, helas_objects.HelasWavefunction): 698 return "".join(sorted([HelasCallWriter.mother_dict[\ 699 wf.get_spin_state_number()] for wf in arg.get('mothers')], 700 lambda l1, l2: \ 701 FortranHelasCallWriter.sort_wf[l2] - \ 702 FortranHelasCallWriter.sort_wf[l1])) 703 704 if isinstance(arg, helas_objects.HelasAmplitude): 705 return "".join(sorted([HelasCallWriter.mother_dict[\ 706 wf.get_spin_state_number()] for wf in arg.get('mothers')], 707 lambda l1, l2: \ 708 FortranHelasCallWriter.sort_amp[l2] - \ 709 FortranHelasCallWriter.sort_amp[l1]))
710 711 @staticmethod
712 - def sorted_mothers(arg):
713 """Gives a list of mother wavefunctions sorted according to 714 1. The order of the particles in the interaction 715 2. Cyclic reordering of particles in same spin group 716 3. Fermions ordered IOIOIO... according to the pairs in 717 the interaction.""" 718 719 assert isinstance(arg, (helas_objects.HelasWavefunction, helas_objects.HelasAmplitude)), \ 720 "%s is not a valid HelasWavefunction or HelasAmplitude" % repr(arg) 721 722 if not arg.get('interaction_id'): 723 return arg.get('mothers') 724 my_pdg_code = 0 725 my_spin = 0 726 if isinstance(arg, helas_objects.HelasWavefunction): 727 my_pdg_code = arg.get_anti_pdg_code() 728 my_spin = arg.get_spin_state_number() 729 730 sorted_mothers, my_index = arg.get('mothers').sort_by_pdg_codes(\ 731 arg.get('pdg_codes'), my_pdg_code) 732 733 # If fermion, partner is the corresponding fermion flow partner 734 partner = None 735 if isinstance(arg, helas_objects.HelasWavefunction) and arg.is_fermion(): 736 # Fermion case, just pick out the fermion flow partner 737 if my_index % 2 == 0: 738 # partner is after arg 739 partner_index = my_index 740 else: 741 # partner is before arg 742 partner_index = my_index - 1 743 partner = sorted_mothers.pop(partner_index) 744 # If partner is incoming, move to before arg 745 if partner.get_spin_state_number() > 0: 746 my_index = partner_index 747 else: 748 my_index = partner_index + 1 749 750 # Reorder fermions pairwise according to incoming/outgoing 751 for i in range(0, len(sorted_mothers), 2): 752 if sorted_mothers[i].is_fermion(): 753 # This is a fermion, order between this fermion and its brother 754 if sorted_mothers[i].get_spin_state_number() > 0 and \ 755 sorted_mothers[i + 1].get_spin_state_number() < 0: 756 # Switch places between outgoing and incoming 757 sorted_mothers = sorted_mothers[:i] + \ 758 [sorted_mothers[i+1], sorted_mothers[i]] + \ 759 sorted_mothers[i+2:] 760 elif sorted_mothers[i].get_spin_state_number() < 0 and \ 761 sorted_mothers[i + 1].get_spin_state_number() > 0: 762 # This is the right order 763 pass 764 else: 765 # No more fermions in sorted_mothers 766 break 767 768 # Put back partner into sorted_mothers 769 if partner: 770 sorted_mothers.insert(partner_index, partner) 771 772 same_spin_mothers = [] 773 if isinstance(arg, helas_objects.HelasWavefunction): 774 # Pick out mothers with same spin, for cyclic reordering 775 same_spin_index = -1 776 i=0 777 while i < len(sorted_mothers): 778 if abs(sorted_mothers[i].get_spin_state_number()) == \ 779 abs(my_spin): 780 if same_spin_index < 0: 781 # Remember starting index for same spin states 782 same_spin_index = i 783 same_spin_mothers.append(sorted_mothers.pop(i)) 784 else: 785 i += 1 786 787 # Make cyclic reordering of mothers with same spin as this wf 788 if same_spin_mothers: 789 same_spin_mothers = same_spin_mothers[my_index - same_spin_index:] \ 790 + same_spin_mothers[:my_index - same_spin_index] 791 792 # Insert same_spin_mothers in sorted_mothers 793 sorted_mothers = sorted_mothers[:same_spin_index] + \ 794 same_spin_mothers + sorted_mothers[same_spin_index:] 795 796 # Next sort according to spin_state_number 797 return helas_objects.HelasWavefunctionList(sorted_mothers)
798
799 800 #=============================================================================== 801 # UFOHelasCallWriter 802 #=============================================================================== 803 -class UFOHelasCallWriter(HelasCallWriter):
804 """The class for writing Helas calls in Fortran, starting from 805 HelasWavefunctions and HelasAmplitudes. 806 807 Includes the function generate_helas_call, which automatically 808 generates the Fortran Helas call based on the Lorentz structure of 809 the interaction.""" 810 811
812 - def get_wavefunction_call(self, wavefunction, **opt):
813 """Return the function for writing the wavefunction 814 corresponding to the key. If the function doesn't exist, 815 generate_helas_call is called to automatically create the 816 function. -UFO ROUTINE-""" 817 818 # Special feature: For octet Majorana fermions, need an extra 819 # minus sign in the FVI (and FSI?) wavefunction in UFO 820 # models. For MG4 models, this is taken care of by calling 821 # different routines (in import_v4.py) 822 wavefunction.set_octet_majorana_coupling_sign() 823 824 val = super(UFOHelasCallWriter, self).get_wavefunction_call(wavefunction) 825 if val: 826 return val 827 828 # If function not already existing, try to generate it. 829 self.generate_helas_call(wavefunction, **opt) 830 return super(UFOHelasCallWriter, self).get_wavefunction_call(\ 831 wavefunction)
832
833 - def get_amplitude_call(self, amplitude):
834 """Return the function for writing the amplitude corresponding 835 to the key. If the function doesn't exist, generate_helas_call 836 is called to automatically create the function.""" 837 838 val = super(UFOHelasCallWriter, self).get_amplitude_call(amplitude) 839 if val: 840 return val 841 842 # If function not already existing, try to generate it. 843 self.generate_helas_call(amplitude) 844 return super(UFOHelasCallWriter, self).get_amplitude_call(amplitude)
845
846 847 848 849 #=============================================================================== 850 # FortranUFOHelasCallWriter 851 #=============================================================================== 852 -class FortranUFOHelasCallWriter(UFOHelasCallWriter):
853 """The class for writing Helas calls in Fortran, starting from 854 HelasWavefunctions and HelasAmplitudes. 855 856 Includes the function generate_helas_call, which automatically 857 generates the Fortran Helas call based on the Lorentz structure of 858 the interaction.""" 859
860 - def generate_helas_call(self, argument):
861 """Routine for automatic generation of Fortran Helas calls 862 according to just the spin structure of the interaction. 863 """ 864 865 if not isinstance(argument, helas_objects.HelasWavefunction) and \ 866 not isinstance(argument, helas_objects.HelasAmplitude): 867 raise self.PhysicsObjectError, \ 868 "get_helas_call must be called with wavefunction or amplitude" 869 870 call = "CALL " 871 872 call_function = None 873 874 if isinstance(argument, helas_objects.HelasAmplitude) and \ 875 argument.get('interaction_id') == 0: 876 call = "#" 877 call_function = lambda amp: call 878 self.add_amplitude(argument.get_call_key(), call_function) 879 return 880 881 if isinstance(argument, helas_objects.HelasWavefunction) and \ 882 not argument.get('mothers'): 883 # String is just IXXXXX, OXXXXX, VXXXXX or SXXXXX 884 call = call + HelasCallWriter.mother_dict[\ 885 argument.get_spin_state_number()] 886 # Fill out with X up to 6 positions 887 call = call + 'X' * (11 - len(call)) 888 call = call + "(P(0,%d)," 889 if argument.get('spin') != 1: 890 # For non-scalars, need mass and helicity 891 call = call + "%s,NHEL(%d)," 892 call = call + "%+d*IC(%d),W(1,%d))" 893 if argument.get('spin') == 1: 894 call_function = lambda wf: call % \ 895 (wf.get('number_external'), 896 # For boson, need initial/final here 897 (-1) ** (wf.get('state') == 'initial'), 898 wf.get('number_external'), 899 wf.get('number')) 900 elif argument.is_boson(): 901 call_function = lambda wf: call % \ 902 (wf.get('number_external'), 903 wf.get('mass'), 904 wf.get('number_external'), 905 # For boson, need initial/final here 906 (-1) ** (wf.get('state') == 'initial'), 907 wf.get('number_external'), 908 wf.get('number')) 909 else: 910 call_function = lambda wf: call % \ 911 (wf.get('number_external'), 912 wf.get('mass'), 913 wf.get('number_external'), 914 # For fermions, need particle/antiparticle 915 - (-1) ** wf.get_with_flow('is_part'), 916 wf.get('number_external'), 917 wf.get('number')) 918 else: 919 # String is LOR1_0, LOR1_2 etc. 920 921 if isinstance(argument, helas_objects.HelasWavefunction): 922 outgoing = argument.find_outgoing_number() 923 else: 924 outgoing = 0 925 926 # Check if we need to append a charge conjugation flag 927 l = [str(l) for l in argument.get('lorentz')] 928 flag = ['C%d' % i for i in argument.get('conjugate_indices')] 929 routine_name = aloha_writers.combine_name( 930 '%s' % l[0], l[1:], outgoing, flag) 931 call = 'CALL %s' % (routine_name) 932 933 # Add the wave function 934 call = call + '(' 935 # Wavefunctions 936 call = call + "W(1,%d)," * len(argument.get('mothers')) 937 # Couplings 938 call = call + "%s," 939 940 if isinstance(argument, helas_objects.HelasWavefunction): 941 # Create call for wavefunction 942 call = call + "%s, %s, W(1,%d))" 943 #CALL L_4_011(W(1,%d),W(1,%d),%s,%s, %s, W(1,%d)) 944 call_function = lambda wf: call % \ 945 (tuple([mother.get('number') for mother in wf.get('mothers')]) + \ 946 (','.join(wf.get_with_flow('coupling')), 947 wf.get('mass'), 948 wf.get('width'), 949 wf.get('number'))) 950 else: 951 # Amplitude 952 call += "AMP(%d))" 953 call_function = lambda amp: call % \ 954 (tuple([mother.get('number') 955 for mother in amp.get('mothers')]) + \ 956 (','.join(amp.get('coupling')), 957 amp.get('number'))) 958 959 # Add the constructed function to wavefunction or amplitude dictionary 960 if isinstance(argument, helas_objects.HelasWavefunction): 961 self.add_wavefunction(argument.get_call_key(), call_function) 962 else: 963 self.add_amplitude(argument.get_call_key(), call_function)
964
965 966 967 968 #=============================================================================== 969 # CPPUFOHelasCallWriter 970 #=============================================================================== 971 -class CPPUFOHelasCallWriter(UFOHelasCallWriter):
972 """The class for writing Helas calls in C++, starting from 973 HelasWavefunctions and HelasAmplitudes. 974 975 Includes the function generate_helas_call, which automatically 976 generates the C++ Helas call based on the Lorentz structure of 977 the interaction.""" 978
979 - def generate_helas_call(self, argument):
980 """Routine for automatic generation of C++ Helas calls 981 according to just the spin structure of the interaction. 982 983 First the call string is generated, using a dictionary to go 984 from the spin state of the calling wavefunction and its 985 mothers, or the mothers of the amplitude, to difenrentiate wich call is 986 done. 987 988 Then the call function is generated, as a lambda which fills 989 the call string with the information of the calling 990 wavefunction or amplitude. The call has different structure, 991 depending on the spin of the wavefunction and the number of 992 mothers (multiplicity of the vertex). The mother 993 wavefunctions, when entering the call, must be sorted in the 994 correct way - this is done by the sorted_mothers routine. 995 996 Finally the call function is stored in the relevant 997 dictionary, in order to be able to reuse the function the next 998 time a wavefunction with the same Lorentz structure is needed. 999 """ 1000 1001 if not isinstance(argument, helas_objects.HelasWavefunction) and \ 1002 not isinstance(argument, helas_objects.HelasAmplitude): 1003 raise self.PhysicsObjectError, \ 1004 "get_helas_call must be called with wavefunction or amplitude" 1005 1006 call = "" 1007 1008 call_function = None 1009 1010 if isinstance(argument, helas_objects.HelasAmplitude) and \ 1011 argument.get('interaction_id') == 0: 1012 call = "#" 1013 call_function = lambda amp: call 1014 self.add_amplitude(argument.get_call_key(), call_function) 1015 return 1016 1017 if isinstance(argument, helas_objects.HelasWavefunction) and \ 1018 not argument.get('mothers'): 1019 # String is just ixxxxx, oxxxxx, vxxxxx or sxxxxx 1020 call = call + HelasCallWriter.mother_dict[\ 1021 argument.get_spin_state_number()].lower() 1022 # Fill out with X up to 6 positions 1023 call = call + 'x' * (6 - len(call)) 1024 # Specify namespace for Helas calls 1025 call = call + "(p[perm[%d]]," 1026 if argument.get('spin') != 1: 1027 # For non-scalars, need mass and helicity 1028 call = call + "mME[%d],hel[%d]," 1029 call = call + "%+d,w[%d]);" 1030 if argument.get('spin') == 1: 1031 call_function = lambda wf: call % \ 1032 (wf.get('number_external')-1, 1033 # For boson, need initial/final here 1034 (-1) ** (wf.get('state') == 'initial'), 1035 wf.get('number')-1) 1036 elif argument.is_boson(): 1037 call_function = lambda wf: call % \ 1038 (wf.get('number_external')-1, 1039 wf.get('number_external')-1, 1040 wf.get('number_external')-1, 1041 # For boson, need initial/final here 1042 (-1) ** (wf.get('state') == 'initial'), 1043 wf.get('number')-1) 1044 else: 1045 call_function = lambda wf: call % \ 1046 (wf.get('number_external')-1, 1047 wf.get('number_external')-1, 1048 wf.get('number_external')-1, 1049 # For fermions, need particle/antiparticle 1050 - (-1) ** wf.get_with_flow('is_part'), 1051 wf.get('number')-1) 1052 else: 1053 # String is LOR1_0, LOR1_2 etc. 1054 1055 if isinstance(argument, helas_objects.HelasWavefunction): 1056 outgoing = argument.find_outgoing_number() 1057 else: 1058 outgoing = 0 1059 1060 # Check if we need to append a charge conjugation flag 1061 l = [str(l) for l in argument.get('lorentz')] 1062 flag = ['C%d' % i for i in argument.get('conjugate_indices')] 1063 routine_name = aloha_writers.combine_name( 1064 '%s' % l[0], l[1:], outgoing, flag) 1065 call = '%s' % (routine_name) 1066 1067 # Add the wave function 1068 call = call + '(' 1069 # Wavefunctions 1070 call = call + "w[%d]," * len(argument.get('mothers')) 1071 # Couplings 1072 call = call + "%s," 1073 1074 if isinstance(argument, helas_objects.HelasWavefunction): 1075 # Create call for wavefunction 1076 call = call + "pars->%s, pars->%s, w[%d]);" 1077 #CALL L_4_011(W(1,%d),W(1,%d),%s,%s, %s, W(1,%d)) 1078 call_function = lambda wf: call % \ 1079 (tuple([mother.get('number')-1 for mother in wf.get('mothers')]) + \ 1080 (','.join(CPPUFOHelasCallWriter.format_coupling(\ 1081 wf.get_with_flow('coupling'))), 1082 wf.get('mass'), 1083 wf.get('width'), 1084 wf.get('number')-1)) 1085 else: 1086 # Amplitude 1087 call += "amp[%d]);" 1088 call_function = lambda amp: call % \ 1089 (tuple([mother.get('number')-1 1090 for mother in amp.get('mothers')]) + \ 1091 (','.join(CPPUFOHelasCallWriter.format_coupling(\ 1092 amp.get('coupling'))), 1093 amp.get('number')-1)) 1094 1095 # Add the constructed function to wavefunction or amplitude dictionary 1096 if isinstance(argument, helas_objects.HelasWavefunction): 1097 self.add_wavefunction(argument.get_call_key(), call_function) 1098 else: 1099 self.add_amplitude(argument.get_call_key(), call_function)
1100 1101 @staticmethod
1102 - def format_coupling(couplings):
1103 """Format the coupling so any minus signs are put in front""" 1104 1105 output = [] 1106 for coupling in couplings: 1107 if coupling.startswith('-'): 1108 output.append("-pars->" + coupling[1:]) 1109 else: 1110 output.append("pars->" + coupling) 1111 1112 return output
1113
1114 1115 #=============================================================================== 1116 # PythonUFOHelasCallWriter 1117 #=============================================================================== 1118 -class PythonUFOHelasCallWriter(UFOHelasCallWriter):
1119 """The class for writing Helas calls in Python, starting from 1120 HelasWavefunctions and HelasAmplitudes. 1121 1122 Includes the function generate_helas_call, which automatically 1123 generates the Python Helas call based on the Lorentz structure of 1124 the interaction.""" 1125
1126 - def get_matrix_element_calls(self, matrix_element, gauge_check=False):
1127 """Return a list of strings, corresponding to the Helas calls 1128 for the matrix element""" 1129 1130 assert isinstance(matrix_element, helas_objects.HelasMatrixElement), \ 1131 "%s not valid argument for get_matrix_element_calls" % \ 1132 repr(matrix_element) 1133 1134 res = [] 1135 for diagram in matrix_element.get('diagrams'): 1136 wfs = diagram.get('wavefunctions') 1137 if gauge_check and diagram.get('number') == 1: 1138 gauge_check_wfs = [wf for wf in wfs if not wf.get('mothers') \ 1139 and wf.get('spin') == 3 \ 1140 and wf.get('mass').lower() == 'zero'] 1141 if not gauge_check_wfs: 1142 raise HelasWriterError, \ 1143 'no massless spin one particle for gauge check' 1144 gauge_check_wf = wfs.pop(wfs.index(gauge_check_wfs[0])) 1145 res.append(self.generate_helas_call(gauge_check_wf, True)(\ 1146 gauge_check_wf)) 1147 res.extend([ self.get_wavefunction_call(wf) for wf in wfs ]) 1148 res.append("# Amplitude(s) for diagram number %d" % \ 1149 diagram.get('number')) 1150 for amplitude in diagram.get('amplitudes'): 1151 res.append(self.get_amplitude_call(amplitude)) 1152 1153 return res
1154 1155 1156
1157 - def generate_helas_call(self, argument, gauge_check=False):
1158 """Routine for automatic generation of Python Helas calls 1159 according to just the spin structure of the interaction. 1160 """ 1161 1162 if not isinstance(argument, helas_objects.HelasWavefunction) and \ 1163 not isinstance(argument, helas_objects.HelasAmplitude): 1164 raise self.PhysicsObjectError, \ 1165 "get_helas_call must be called with wavefunction or amplitude" 1166 1167 call_function = None 1168 1169 if isinstance(argument, helas_objects.HelasAmplitude) and \ 1170 argument.get('interaction_id') == 0: 1171 call = "#" 1172 call_function = lambda amp: call 1173 self.add_amplitude(argument.get_call_key(), call_function) 1174 return 1175 1176 if isinstance(argument, helas_objects.HelasWavefunction) and \ 1177 not argument.get('mothers'): 1178 # String is just IXXXXX, OXXXXX, VXXXXX or SXXXXX 1179 call = "w[%d] = " 1180 1181 call = call + HelasCallWriter.mother_dict[\ 1182 argument.get_spin_state_number()].lower() 1183 # Fill out with X up to 6 positions 1184 call = call + 'x' * (14 - len(call)) 1185 call = call + "(p[%d]," 1186 if argument.get('spin') != 1: 1187 # For non-scalars, need mass and helicity 1188 if gauge_check and argument.get('spin') == 3 and \ 1189 argument.get('mass') == 'ZERO': 1190 call = call + "%s, 4," 1191 else: 1192 call = call + "%s,hel[%d]," 1193 call = call + "%+d)" 1194 if argument.get('spin') == 1: 1195 call_function = lambda wf: call % \ 1196 (wf.get('number')-1, 1197 wf.get('number_external')-1, 1198 # For boson, need initial/final here 1199 (-1)**(wf.get('state') == 'initial')) 1200 elif argument.is_boson(): 1201 if not gauge_check or argument.get('mass') != 'ZERO': 1202 call_function = lambda wf: call % \ 1203 (wf.get('number')-1, 1204 wf.get('number_external')-1, 1205 wf.get('mass'), 1206 wf.get('number_external')-1, 1207 # For boson, need initial/final here 1208 (-1)**(wf.get('state') == 'initial')) 1209 else: 1210 call_function = lambda wf: call % \ 1211 (wf.get('number')-1, 1212 wf.get('number_external')-1, 1213 'ZERO', 1214 # For boson, need initial/final here 1215 (-1)**(wf.get('state') == 'initial')) 1216 else: 1217 call_function = lambda wf: call % \ 1218 (wf.get('number')-1, 1219 wf.get('number_external')-1, 1220 wf.get('mass'), 1221 wf.get('number_external')-1, 1222 # For fermions, need particle/antiparticle 1223 -(-1)**wf.get_with_flow('is_part')) 1224 else: 1225 # String is LOR1_0, LOR1_2 etc. 1226 1227 if isinstance(argument, helas_objects.HelasWavefunction): 1228 outgoing = argument.find_outgoing_number() 1229 else: 1230 outgoing = 0 1231 1232 # Check if we need to append a charge conjugation flag 1233 l = [str(l) for l in argument.get('lorentz')] 1234 flag = ['C%d' % i for i in argument.get('conjugate_indices')] 1235 routine_name = aloha_writers.combine_name( 1236 '%s' % l[0], l[1:], outgoing, flag) 1237 1238 1239 if isinstance(argument, helas_objects.HelasWavefunction): 1240 call = 'w[%d] = ' 1241 else: 1242 call = 'amp[%d] = ' 1243 call += '%s' % routine_name 1244 1245 # Add the wave function 1246 call = call + '(' 1247 # Wavefunctions 1248 call = call + "w[%d]," * len(argument.get('mothers')) 1249 # Couplings 1250 call = call + "%s" 1251 1252 if isinstance(argument, helas_objects.HelasWavefunction): 1253 # Create call for wavefunction 1254 call = call + ",%s, %s)" 1255 #CALL L_4_011(W(1,%d),W(1,%d),%s,%s, %s, W(1,%d)) 1256 call_function = lambda wf: call % \ 1257 ((wf.get('number')-1,) + \ 1258 tuple([mother.get('number')-1 for mother in \ 1259 wf.get('mothers')]) + \ 1260 (','.join(wf.get_with_flow('coupling')), 1261 wf.get('mass'), 1262 wf.get('width'))) 1263 else: 1264 call = call + ")" 1265 # Amplitude 1266 call_function = lambda amp: call % \ 1267 ((amp.get('number')-1,) + \ 1268 tuple([mother.get('number')-1 1269 for mother in amp.get('mothers')]) + \ 1270 (','.join(amp.get('coupling')),)) 1271 1272 # Add the constructed function to wavefunction or amplitude dictionary 1273 if isinstance(argument, helas_objects.HelasWavefunction): 1274 if not gauge_check: 1275 self.add_wavefunction(argument.get_call_key(), call_function) 1276 else: 1277 self.add_amplitude(argument.get_call_key(), call_function) 1278 1279 return call_function
1280