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