Package madgraph :: Package interface :: Module loop_interface
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.loop_interface

  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  """A user friendly command line interface to access all MadGraph5_aMC@NLO features. 
 16     Uses the cmd package for command interpretation and tab completion. 
 17  """ 
 18   
 19  import os 
 20  import shutil 
 21  import time 
 22  import logging 
 23  import re 
 24   
 25  import madgraph 
 26  from madgraph import MG4DIR, MG5DIR, MadGraph5Error 
 27  import madgraph.interface.madgraph_interface as mg_interface 
 28  import madgraph.core.base_objects as base_objects 
 29  import madgraph.core.diagram_generation as diagram_generation 
 30  import madgraph.loop.loop_diagram_generation as loop_diagram_generation 
 31  import madgraph.loop.loop_base_objects as loop_base_objects 
 32  import madgraph.loop.loop_helas_objects as loop_helas_objects 
 33  import madgraph.core.helas_objects as helas_objects 
 34  import madgraph.iolibs.export_v4 as export_v4 
 35  import madgraph.iolibs.helas_call_writers as helas_call_writers 
 36  import madgraph.iolibs.file_writers as writers 
 37  import madgraph.interface.launch_ext_program as launch_ext 
 38  import madgraph.various.misc as misc 
 39  import madgraph.fks.fks_base as fks_base 
 40  import aloha 
 41   
 42  # Special logger for the Cmd Interface 
 43  logger = logging.getLogger('cmdprint') 
 44   
 45  #useful shortcut 
 46  pjoin = os.path.join 
 47   
48 -class CheckLoop(mg_interface.CheckValidForCmd):
49
50 - def check_display(self, args):
51 """ Check the arguments of the display diagrams command in the context 52 of the Loop interface.""" 53 54 mg_interface.MadGraphCmd.check_display(self,args) 55 56 if all([not amp['process']['has_born'] for amp in self._curr_amps]): 57 if args[0]=='diagrams' and len(args)>=2 and args[1]=='born': 58 raise self.InvalidCmd("Processes generated do not have born diagrams.") 59 60 if args[0]=='diagrams' and len(args)>=3 and args[1] not in ['born','loop']: 61 raise self.InvalidCmd("Can only display born or loop diagrams, not %s."%args[1])
62
63 - def check_tutorial(self, args):
64 """check the validity of the line""" 65 if len(args) == 0: 66 #this means mg5 tutorial 67 args.append('MadLoop') 68 else: 69 return mg_interface.CheckValidForCmd.check_tutorial(self,args)
70
71 - def check_add(self, args):
72 """ If no model is defined yet, make sure to load the right loop one """ 73 74 if not self._curr_model: 75 pert_coupl_finder = re.compile(r"^(?P<proc>.+)\s*\[\s*((?P<option>\w+)"+ 76 r"\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 77 pert_coupl = pert_coupl_finder.match(' '.join(args)) 78 model_name = 'loop_sm' 79 if pert_coupl: 80 pert_coupls = pert_coupl.group("pertOrders") 81 if "QED" in pert_coupls: 82 model_name = 'loop_qcd_qed_sm' 83 self.do_import('model %s'%model_name) 84 85 mg_interface.MadGraphCmd.check_add(self,args)
86
87 - def check_output(self, args):
88 """ Check the arguments of the output command in the context 89 of the Loop interface.""" 90 91 mg_interface.MadGraphCmd.check_output(self,args) 92 93 if self._export_format not in ["standalone", "matchbox"]: 94 self._export_format = 'standalone'
95
96 - def check_launch(self, args, options):
97 """ Further check that only valid options are given to the MadLoop 98 default launcher.""" 99 100 mg_interface.MadGraphCmd.check_launch(self,args,options) 101 if int(options.cluster) != 0 : 102 return self.InvalidCmd, 'MadLoop standalone runs cannot be '+\ 103 'performed on a cluster.' 104 105 if int(options.multicore) != 0 : 106 logger.warning('MadLoop standalone can only run on a single core,'+\ 107 ' so the -m option is ignored.') 108 options.multicore = '0' 109 110 if options.laststep != '' : 111 logger.warning('The -laststep option is only used for Madevent.'+\ 112 'Ignoring this option') 113 options.multicore = '' 114 115 if options.interactive : 116 logger.warning('No interactive mode for MadLoop standalone runs.') 117 options.interactive = False
118
119 -class CheckLoopWeb(mg_interface.CheckValidForCmdWeb, CheckLoop):
120 pass
121
122 -class CompleteLoop(mg_interface.CompleteForCmd):
123
124 - def complete_display(self, text, line, begidx, endidx):
125 "Complete the display command in the context of the Loop interface" 126 127 args = self.split_arg(line[0:begidx]) 128 129 if len(args) == 2 and args[1] == 'diagrams': 130 return self.list_completion(text, ['born', 'loop']) 131 else: 132 return mg_interface.MadGraphCmd.complete_display(self, text, line, 133 begidx, endidx)
134
135 -class HelpLoop(mg_interface.HelpToCmd):
136
137 - def help_display(self):
138 mg_interface.MadGraphCmd.help_display(self) 139 logger.info(" In ML5, after display diagrams, the user can add the option") 140 logger.info(" \"born\" or \"loop\" to display only the corresponding diagrams.")
141 142
143 -class CommonLoopInterface(mg_interface.MadGraphCmd):
144 """ An additional layer between MadGraphInterface and LoopInterface as well 145 as aMCatNLO interface, to put the common feature of these two here.""" 146
147 - def rate_proc_difficulty(self, proc, mode):
148 """ Gives an integer more or less representing the difficulty of the process. 149 For now it is very basic and such that "difficult" processes start at 150 a value of about 35.""" 151 152 def pdg_difficulty(pdg): 153 """ Gives a score from the pdg of a leg to state how it increases the 154 difficulty of the process """ 155 # For now, it is only based on the color charge. One can change that 156 # of course. 157 part=self._curr_model.get_particle(pdg) 158 if abs(part.get_color())==1: 159 return 2 160 elif abs(part.get_color())==3: 161 return 3 162 elif abs(part.get_color())==6: 163 return 4 164 elif abs(part.get_color())==8: 165 return 6
166 167 score = 0 168 for leg in proc.get('legs'): 169 if isinstance(leg,base_objects.MultiLeg): 170 score += max([pdg_difficulty(id) for id in leg['ids']]) 171 # add one if it has more than one particle 172 if len(leg['ids'])>1: 173 score += 1 174 else: 175 score += pdg_difficulty(leg.get('id')) 176 177 # No integration planned right away if only virtual, remove 6 178 if proc['NLO_mode']=='virt': 179 score = score - 6 180 # Only reals, then again remove 6 181 if proc['NLO_mode']=='real': 182 score = score - 6 183 # If tree only then it is easy 184 if proc['NLO_mode']=='tree': 185 return 0 186 return score
187
188 - def do_set(self, line, log=True):
189 """Set the loop optimized output while correctly switching to the 190 Feynman gauge if necessary. 191 """ 192 193 mg_interface.MadGraphCmd.do_set(self,line,log) 194 195 args = self.split_arg(line) 196 self.check_set(args) 197 198 if args[0] == 'gauge' and args[1] == 'unitary' and \ 199 not self.options['gauge']=='unitary' and \ 200 isinstance(self._curr_model,loop_base_objects.LoopModel) and \ 201 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 202 if log: logger.warning('You will only be able to do tree level and QCD'+\ 203 ' corrections in the unitary gauge.')
204
205 - def proc_validity(self, proc, mode):
206 """ Check that the process or processDefinition describes a process that 207 ML5 can handle. Mode specifies who called the function, 208 typically ML5, ML5_check or aMCatNLO. This allows to relieve some limitation 209 depending on the functionality.""" 210 211 tool = 'MadLoop' if mode.startswith('ML5') else 'aMC@NLO' 212 # The threshold for the triggering of the 'Warning difficult process' 213 # message. 214 difficulty_threshold = 100 215 # Check that we have something 216 if not proc: 217 raise self.InvalidCmd("Empty or wrong format process, please try again.") 218 219 # Check that we have the same number of initial states as 220 # existing processes 221 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 222 proc.get_ninitial(): 223 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 224 225 # if proc.get_ninitial()==1 and tool=='aMC@NLO': 226 # raise self.InvalidCmd("At this stage %s cannot handle decay process."%tool+\ 227 # "\nIt is however a straight-forward extension which "+\ 228 # "will come out with the next release.") 229 230 if isinstance(proc, base_objects.ProcessDefinition) and mode.startswith('ML5'): 231 if proc.has_multiparticle_label(): 232 raise self.InvalidCmd( 233 "When running ML5 standalone, multiparticle labels cannot be"+\ 234 " employed. Please use the FKS5 interface instead.") 235 236 if proc['decay_chains']: 237 raise self.InvalidCmd( 238 "ML5 cannot yet decay a core process including loop corrections.") 239 240 if proc.are_decays_perturbed(): 241 raise self.InvalidCmd( 242 "The processes defining the decay of the core process cannot"+\ 243 " include loop corrections.") 244 245 if not proc['perturbation_couplings'] and mode.startswith('ML5'): 246 raise self.InvalidCmd( 247 "Please perform tree-level generations within default MG5 interface.") 248 if not 'real': 249 if not isinstance(self._curr_model,loop_base_objects.LoopModel) or \ 250 not proc['perturbation_couplings']: 251 raise self.InvalidCmd( 252 "The current model does not allow for loop computations.") 253 254 miss_order = [ p_order for p_order in proc['perturbation_couplings'] \ 255 if p_order not in self._curr_model.get('perturbation_couplings')] 256 if len(miss_order)>0 and not 'real' in mode: 257 raise self.InvalidCmd( 258 "Perturbation orders %s not among"%str(miss_order) + \ 259 " the perturbation orders allowed for by the loop model.") 260 261 if proc['perturbation_couplings'] not in [[],['QCD']]: 262 raise self.InvalidCmd( 263 "The process perturbation coupling orders %s are beyond "+\ 264 "tree level or only QCD corrections. MadLoop can only work"+\ 265 " in the Feynman gauge for these. Please set the gauge to "+\ 266 " Feynman and try again.") 267 268 proc_diff = self.rate_proc_difficulty(proc, mode) 269 logger.debug('Process difficulty estimation: %d'%proc_diff) 270 if proc_diff >= difficulty_threshold: 271 msg = """ 272 The %s you attempt to generate appears to be of challenging difficulty, but it will be tried anyway. If you have successfully studied it with MadGraph5_aMC@NLO, please report it. 273 """ 274 logger.warning(msg%proc.nice_string().replace('Process:','process'))
275
276 - def validate_model(self, loop_type='virtual',coupling_type=['QCD'], stop=True):
277 """ Upgrade the model sm to loop_sm if needed """ 278 279 # Allow to call this function with a string instead of a list of 280 # perturbation orders. 281 if isinstance(coupling_type,str): 282 coupling_type = [coupling_type,] 283 284 if not isinstance(self._curr_model,loop_base_objects.LoopModel) or \ 285 self._curr_model['perturbation_couplings']==[] or \ 286 any((coupl not in self._curr_model['perturbation_couplings']) \ 287 for coupl in coupling_type): 288 if loop_type.startswith('real') or loop_type == 'LOonly': 289 if loop_type == 'real': 290 logger.info(\ 291 "Beware that real corrections are generated from a tree-level model.") 292 if loop_type == 'real_init' and \ 293 self._curr_model.get('name').split('-')[0]!='sm': 294 logger.info(\ 295 "You are entering aMC@NLO with a model which does not "+\ 296 " support loop corrections.") 297 else: 298 logger.info(\ 299 "The current model %s does not allow to generate"%self._curr_model.get('name')+ 300 " loop corrections of type %s."%str(coupling_type)) 301 model_path = self._curr_model.get('modelpath') 302 model_name = self._curr_model.get('name') 303 if model_name.split('-')[0]=='loop_sm': 304 model_name = model_name[5:] 305 if model_name.split('-')[0]=='sm': 306 # So that we don't load the model twice 307 if not self.options['gauge']=='Feynman' and 'QED' in coupling_type: 308 logger.info('Switch to Feynman gauge because '+\ 309 'model loop_qcd_qed_sm is restricted only to Feynman gauge.') 310 self._curr_model = None 311 mg_interface.MadGraphCmd.do_set(self,'gauge Feynman') 312 if coupling_type == ['QCD',]: 313 add_on = '' 314 elif coupling_type in [['QED'],['QCD','QED']]: 315 add_on = 'qcd_qed_' 316 else: 317 raise MadGraph5Error( 318 "The pertubation coupling cannot be '%s'"\ 319 %str(coupling_type)+" in SM loop processes") 320 321 logger.info("MG5_aMC now loads 'loop_%s%s'."%(add_on,model_name)) 322 323 #import model with correct treatment of the history 324 self.history.move_to_last('generate') 325 last_command = self.history[-1] 326 self.exec_cmd(" import model loop_%s%s" % (add_on,model_name), precmd=True) 327 self.history.append(last_command) 328 elif stop: 329 raise self.InvalidCmd( 330 "The model %s cannot handle loop processes"%model_name) 331 332 if loop_type and not loop_type.startswith('real') and \ 333 not self.options['gauge']=='Feynman' and \ 334 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 335 if 1 in self._curr_model.get('gauge'): 336 logger.info("Setting gauge to Feynman in order to process all"+\ 337 " possible loop computations available in the model.") 338 mg_interface.MadGraphCmd.do_set(self,'gauge Feynman') 339 else: 340 logger.warning("You will only be able to do tree level and QCD"+\ 341 " corrections with this model because it does not support Feynman gauge.")
342
343 -class LoopInterface(CheckLoop, CompleteLoop, HelpLoop, CommonLoopInterface):
344
345 - def __init__(self, mgme_dir = '', *completekey, **stdin):
346 """ Special init tasks for the Loop Interface """ 347 348 mg_interface.MadGraphCmd.__init__(self, mgme_dir = '', *completekey, **stdin) 349 self.setup()
350
351 - def setup(self):
352 """ Special tasks when switching to this interface """ 353 354 # Refresh all the interface stored value as things like generated 355 # processes and amplitudes are not to be reused in between different 356 # interfaces 357 # Clear history, amplitudes and matrix elements when a model is imported 358 # Remove previous imports, generations and outputs from history 359 self.history.clean(remove_bef_last='import', 360 to_keep=['set','load','import', 'define']) 361 # Reset amplitudes and matrix elements 362 self._done_export=False 363 self._curr_amps = diagram_generation.AmplitudeList() 364 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 365 self._v4_export_formats = [] 366 self._export_formats = [ 'matrix', 'standalone' ] 367 self._nlo_modes_for_completion = ['virt'] 368 self.validate_model() 369 # Set where to look for CutTools installation. 370 # In further versions, it will be set in the same manner as _mgme_dir so that 371 # the user can chose its own CutTools distribution. 372 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools')) 373 if not os.path.isdir(os.path.join(self._cuttools_dir, 'src','cts')): 374 logger.warning(('Warning: Directory %s is not a valid CutTools directory.'+\ 375 'Using default CutTools instead.') % \ 376 self._cuttools_dir) 377 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools')) 378 # Set where to look for IREGI installation 379 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src')) 380 if not os.path.isdir(self._iregi_dir): 381 logger.warning(('Warning: Directory %s is not a valid IREGI directory.'+\ 382 'Using default IREGI instead.')%\ 383 self._iregi_dir) 384 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
385
386 - def do_display(self,line, *argss, **opt):
387 """ Display born or loop diagrams, otherwise refer to the default display 388 command """ 389 390 args = self.split_arg(line) 391 #check the validity of the arguments 392 self.check_display(args) 393 394 if args[0]=='diagrams': 395 if len(args)>=2 and args[1] in ['loop','born']: 396 self.draw(' '.join(args[2:]),args[1]) 397 else: 398 self.draw(' '.join(args[1:]),'all') 399 else: 400 mg_interface.MadGraphCmd.do_display(self,line,*argss,**opt)
401
402 - def do_output(self, line):
403 """Main commands:Initialize a new Template or reinitialize one""" 404 405 args = self.split_arg(line) 406 # Check Argument validity 407 self.check_output(args) 408 409 noclean = '-noclean' in args 410 force = '-f' in args 411 nojpeg = '-nojpeg' in args 412 main_file_name = "" 413 try: 414 main_file_name = args[args.index('-name') + 1] 415 except Exception: 416 pass 417 418 # Whatever the format we always output the quadruple precision routines 419 # to allow for curing possible unstable points. 420 aloha_original_quad_mode = aloha.mp_precision 421 aloha.mp_precision = True 422 423 if self._export_format not in ['standalone', 'matchbox']: 424 raise self.InvalidCmd('ML5 only support standalone/matchbox as export format.') 425 426 if not os.path.isdir(self._export_dir) and \ 427 self._export_format in ['matrix']: 428 raise self.InvalidCmd('Specified export directory %s does not exist.'\ 429 %str(self._export_dir)) 430 431 if not force and not noclean and os.path.isdir(self._export_dir)\ 432 and self._export_format in ['standalone']: 433 # Don't ask if user already specified force or noclean 434 logger.info('INFO: directory %s already exists.' % self._export_dir) 435 logger.info('If you continue this directory will be cleaned') 436 answer = self.ask('Do you want to continue?', 'y', ['y','n']) 437 if answer != 'y': 438 raise self.InvalidCmd('Stopped by user request') 439 else: 440 try: 441 shutil.rmtree(self._export_dir) 442 except OSError: 443 raise self.InvalidCmd('Could not remove directory %s.'\ 444 %str(self._export_dir)) 445 446 if self._export_format == 'standalone': 447 output_type = 'madloop' 448 elif self._export_format == 'matchbox': 449 output_type = 'madloop_matchbox' 450 451 self._curr_exporter = export_v4.ExportV4Factory(self, \ 452 noclean, output_type=output_type) 453 454 if self._export_format in ['standalone', 'matchbox']: 455 self._curr_exporter.copy_v4template(modelname=self._curr_model.get('name')) 456 457 # Reset _done_export, since we have new directory 458 self._done_export = False 459 460 # Perform export and finalize right away 461 self.ML5export(nojpeg, main_file_name) 462 463 # Automatically run finalize 464 self.ML5finalize(nojpeg) 465 466 # Remember that we have done export 467 self._done_export = (self._export_dir, self._export_format) 468 469 # Reset _export_dir, so we don't overwrite by mistake later 470 self._export_dir = None 471 472 # Put aloha back in its original mode. 473 aloha.mp_precision = aloha_original_quad_mode
474 475 # Export a matrix element 476
477 - def ML5export(self, nojpeg = False, main_file_name = ""):
478 """Export a generated amplitude to file""" 479 480 def generate_matrix_elements(self): 481 """Helper function to generate the matrix elements before exporting""" 482 483 # Sort amplitudes according to number of diagrams, 484 # to get most efficient multichannel output 485 self._curr_amps.sort(lambda a1, a2: a2.get_number_of_diagrams() - \ 486 a1.get_number_of_diagrams()) 487 488 cpu_time1 = time.time() 489 ndiags = 0 490 if not self._curr_matrix_elements.get_matrix_elements(): 491 self._curr_matrix_elements = \ 492 loop_helas_objects.LoopHelasProcess(self._curr_amps, 493 optimized_output = self.options['loop_optimized_output']) 494 ndiags = sum([len(me.get('diagrams')) for \ 495 me in self._curr_matrix_elements.\ 496 get_matrix_elements()]) 497 # assign a unique id number to all process 498 uid = 0 499 for me in self._curr_matrix_elements.get_matrix_elements(): 500 uid += 1 # update the identification number 501 me.get('processes')[0].set('uid', uid) 502 503 cpu_time2 = time.time() 504 return ndiags, cpu_time2 - cpu_time1
505 506 # Start of the actual routine 507 ndiags, cpu_time = generate_matrix_elements(self) 508 509 calls = 0 510 511 path = self._export_dir 512 if self._export_format in ['standalone','matchbox']: 513 path = pjoin(path, 'SubProcesses') 514 515 cpu_time1 = time.time() 516 517 # Pick out the matrix elements in a list 518 matrix_elements = \ 519 self._curr_matrix_elements.get_matrix_elements() 520 521 # Fortran MadGraph5_aMC@NLO Standalone 522 if self._export_format in ['standalone', 'matchbox']: 523 for me in matrix_elements: 524 calls = calls + \ 525 self._curr_exporter.generate_subprocess_directory_v4(\ 526 me, self._curr_fortran_model) 527 # If all ME's do not share the same maximum loop vertex rank and the 528 # same loop maximum wavefunction size, we need to set the maximum 529 # in coef_specs.inc of the HELAS Source and warn the user that this 530 # might be a problem 531 if self.options['loop_optimized_output'] and len(matrix_elements)>1: 532 max_lwfspins = [m.get_max_loop_particle_spin() for m in \ 533 matrix_elements] 534 max_loop_vert_ranks = [me.get_max_loop_vertex_rank() for me in \ 535 matrix_elements] 536 if len(set(max_lwfspins))>1 or len(set(max_loop_vert_ranks))>1: 537 self._curr_exporter.fix_coef_specs(max(max_lwfspins),\ 538 max(max_loop_vert_ranks)) 539 logger.warning('ML5 has just output processes which do not'+\ 540 ' share the same maximum loop wavefunction size or the '+\ 541 ' same maximum loop vertex rank. This is potentially '+\ 542 ' dangerous. Please prefer to output them separately.') 543 544 # Just the matrix.f files 545 if self._export_format == 'matrix': 546 for me in matrix_elements: 547 filename = pjoin(path, 'matrix_' + \ 548 me.get('processes')[0].shell_string() + ".f") 549 if os.path.isfile(filename): 550 logger.warning("Overwriting existing file %s" % filename) 551 else: 552 logger.info("Creating new file %s" % filename) 553 calls = calls + self._curr_exporter.write_matrix_element_v4(\ 554 writers.FortranWriter(filename),\ 555 me, self._curr_fortran_model) 556 557 cpu_time2 = time.time() - cpu_time1 558 559 logger.info(("Generated helas calls for %d subprocesses " + \ 560 "(%d diagrams) in %0.3f s") % \ 561 (len(matrix_elements), 562 ndiags, cpu_time)) 563 564 if calls: 565 if "cpu_time2" in locals(): 566 logger.info("Wrote files for %d OPP calls in %0.3f s" % \ 567 (calls, cpu_time2)) 568 else: 569 logger.info("Wrote files for %d OPP calls" % \ 570 (calls)) 571 572 # Replace the amplitudes with the actual amplitudes from the 573 # matrix elements, which allows proper diagram drawing also of 574 # decay chain processes 575 self._curr_amps = diagram_generation.AmplitudeList(\ 576 [me.get('base_amplitude') for me in \ 577 matrix_elements])
578
579 - def ML5finalize(self, nojpeg, online = False):
580 """Copy necessary sources and output the ps representation of 581 the diagrams, if needed""" 582 583 if self._export_format in ['standalone','matchbox']: 584 logger.info('Export UFO model to MG4 format') 585 # wanted_lorentz are the lorentz structures which are 586 # actually used in the wavefunctions and amplitudes in 587 # these processes 588 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 589 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 590 # For a unique output of multiple type of exporter model information 591 # are save in memory 592 if hasattr(self, 'previous_lorentz'): 593 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz)) 594 wanted_couplings = list(set(self.previous_couplings + wanted_couplings)) 595 del self.previous_lorentz 596 del self.previous_couplings 597 598 self._curr_exporter.convert_model_to_mg4(self._curr_model, 599 wanted_lorentz, 600 wanted_couplings) 601 602 if self._export_format in ['standalone', 'matchbox']: 603 self._curr_exporter.finalize_v4_directory( \ 604 self._curr_matrix_elements, 605 self.history, 606 not nojpeg, 607 online, 608 self.options['fortran_compiler']) 609 610 if self._export_format in ['standalone','matchbox']: 611 logger.info('Output to directory ' + self._export_dir + ' done.')
612
613 - def do_launch(self, line, *args,**opt):
614 """Main commands: Check that the type of launch is fine before proceeding with the 615 mother function. """ 616 617 args = self.split_arg(line) 618 # check argument validity and normalise argument 619 (options, args) = mg_interface._launch_parser.parse_args(args) 620 621 self.check_launch(args, options) 622 623 if not args[0].startswith('standalone'): 624 raise self.InvalidCmd('ML5 can only launch standalone runs.') 625 626 start_cwd = os.getcwd() 627 options = options.__dict__ 628 # args is now MODE PATH 629 630 ext_program = launch_ext.MadLoopLauncher(self, args[1], \ 631 options=self.options, **options) 632 ext_program.run() 633 os.chdir(start_cwd) #ensure to go to the initial path
634
635 - def do_check(self, line, *args,**opt):
636 """Check a given process or set of processes""" 637 638 argss = self.split_arg(line, *args,**opt) 639 # Check args validity 640 perturbation_couplings_pattern = \ 641 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 642 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 643 perturbation_couplings="" 644 if perturbation_couplings_re: 645 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 646 QED_found=re.search("QED",perturbation_couplings) 647 if QED_found: 648 self.validate_model(coupling_type='QED') 649 else: 650 self.validate_model() 651 652 param_card = self.check_check(argss) 653 reuse = argss[1]=="-reuse" 654 argss = argss[:1]+argss[2:] 655 # For the stability check the user can specify the statistics (i.e 656 # number of trial PS points) as a second argument 657 if argss[0] in ['stability', 'profile']: 658 stab_statistics = int(argss[1]) 659 argss = argss[:1]+argss[2:] 660 # Remove the extra options 661 i=-1 662 while argss[i].startswith('--'): 663 i=i-1 664 # Now make sure the process is acceptable 665 proc = " ".join(argss[1:i+1]) 666 myprocdef = self.extract_process(proc) 667 self.proc_validity(myprocdef,'ML5_check') 668 669 return mg_interface.MadGraphCmd.do_check(self, line, *args,**opt)
670
671 - def do_add(self, line, *args,**opt):
672 """Generate an amplitude for a given process and add to 673 existing amplitudes 674 """ 675 args = self.split_arg(line) 676 # Check the validity of the arguments 677 self.check_add(args) 678 perturbation_couplings_pattern = \ 679 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 680 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 681 perturbation_couplings="" 682 if perturbation_couplings_re: 683 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 684 QED_found=re.search('QED',perturbation_couplings) 685 if QED_found: 686 self.validate_model(coupling_type='QED') 687 else: 688 self.validate_model() 689 690 if args[0] == 'process': 691 # Rejoin line 692 line = ' '.join(args[1:]) 693 694 # store the first process (for the perl script) 695 if not self._generate_info: 696 self._generate_info = line 697 698 # Reset Helas matrix elements 699 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 700 701 # Extract process from process definition 702 703 myprocdef = self.extract_process(line) 704 705 # If it is a process for MadLoop standalone, make sure it has a 706 # unique ID. It is important for building a BLHA library which 707 # contains unique entry point for each process generated. 708 all_ids = [amp.get('process').get('id') for amp in self._curr_amps] 709 if myprocdef.get('id') in all_ids: 710 myprocdef.set('id',max(all_ids)+1) 711 712 self.proc_validity(myprocdef,'ML5') 713 714 cpu_time1 = time.time() 715 716 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 717 multiprocessclass=None 718 if myprocdef['perturbation_couplings']!=[]: 719 multiprocessclass=loop_diagram_generation.LoopMultiProcess 720 else: 721 multiprocessclass=diagram_generation.MultiProcess 722 723 myproc = multiprocessclass(myprocdef, collect_mirror_procs = False, 724 ignore_six_quark_processes = False) 725 726 for amp in myproc.get('amplitudes'): 727 if amp not in self._curr_amps: 728 self._curr_amps.append(amp) 729 else: 730 warning = "Warning: Already in processes:\n%s" % \ 731 amp.nice_string_processes() 732 logger.warning(warning) 733 734 # Reset _done_export, since we have new process 735 self._done_export = False 736 737 cpu_time2 = time.time() 738 739 ndiags = sum([len(amp.get('loop_diagrams')) for \ 740 amp in myproc.get('amplitudes')]) 741 logger.info("Process generated in %0.3f s" % \ 742 (cpu_time2 - cpu_time1))
743
744 -class LoopInterfaceWeb(mg_interface.CheckValidForCmdWeb, LoopInterface):
745 pass
746