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

Source Code for Module madgraph.interface.amcatnlo_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  from __future__ import absolute_import 
  20  from __future__ import print_function 
  21  import os 
  22  import logging 
  23  import pydoc 
  24  import sys 
  25  import time 
  26  import optparse 
  27  import subprocess 
  28  import shutil 
  29  import copy 
  30  import multiprocessing 
  31  import signal 
  32  import tempfile 
  33  import itertools 
  34  import os 
  35  import six.moves.cPickle 
  36   
  37   
  38  import madgraph 
  39  from madgraph import MG4DIR, MG5DIR, MadGraph5Error 
  40  import madgraph.interface.extended_cmd as cmd 
  41  import madgraph.interface.madgraph_interface as mg_interface 
  42  import madgraph.interface.madevent_interface as me_interface 
  43  import madgraph.interface.extended_cmd as extended_cmd 
  44  import madgraph.interface.amcatnlo_run_interface as run_interface 
  45  import madgraph.interface.launch_ext_program as launch_ext 
  46  import madgraph.interface.loop_interface as Loop_interface 
  47  import madgraph.fks.fks_common as fks_common 
  48  import madgraph.fks.fks_base as fks_base 
  49  import madgraph.fks.fks_helas_objects as fks_helas 
  50  import madgraph.iolibs.export_fks as export_fks 
  51  import madgraph.iolibs.export_v4 as export_v4 
  52  import madgraph.iolibs.helas_call_writers as helas_call_writers 
  53  import madgraph.loop.loop_base_objects as loop_base_objects 
  54  import madgraph.core.diagram_generation as diagram_generation 
  55  import madgraph.core.helas_objects as helas_objects 
  56   
  57  import madgraph.various.cluster as cluster 
  58  import madgraph.various.misc as misc 
  59  import madgraph.various.banner as banner_mod 
  60  from six.moves import range 
  61   
  62  #usefull shortcut 
  63  pjoin = os.path.join 
  64   
  65   
  66  logger = logging.getLogger('cmdprint') # -> stdout 
  67  logger_stderr = logging.getLogger('fatalerror') # ->stderr 
  68   
  69  # a new function for the improved NLO generation 
  70  glob_directories_map = [] 
71 -def generate_directories_fks_async(i):
72 73 arglist = glob_directories_map[i] 74 75 curr_exporter = arglist[0] 76 mefile = arglist[1] 77 curr_fortran_model = arglist[2] 78 ime = arglist[3] 79 nme = arglist[4] 80 path = arglist[5] 81 olpopts = arglist[6] 82 83 infile = open(mefile,'rb') 84 me = six.moves.cPickle.load(infile) 85 infile.close() 86 87 calls = curr_exporter.generate_directories_fks(me, curr_fortran_model, ime, nme, path, olpopts) 88 89 nexternal = curr_exporter.proc_characteristic['nexternal'] 90 ninitial = curr_exporter.proc_characteristic['ninitial'] 91 max_n_matched_jets = curr_exporter.proc_characteristic['max_n_matched_jets'] 92 splitting_types = curr_exporter.proc_characteristic['splitting_types'] 93 #processes = me.born_matrix_element.get('processes') 94 processes = me.born_me.get('processes') 95 96 #only available after export has been done, so has to be returned from here 97 max_loop_vertex_rank = -99 98 if me.virt_matrix_element: 99 max_loop_vertex_rank = me.virt_matrix_element.get_max_loop_vertex_rank() 100 if six.PY2: 101 return [calls, curr_exporter.fksdirs, max_loop_vertex_rank, ninitial, nexternal, processes, max_n_matched_jets, splitting_types] 102 else: 103 return [calls, curr_exporter.fksdirs, max_loop_vertex_rank, ninitial, nexternal, None,max_n_matched_jets, splitting_types]
104
105 -class CheckFKS(mg_interface.CheckValidForCmd):
106 107
108 - def check_display(self, args):
109 """ Check the arguments of the display diagrams command in the context 110 of the Loop interface.""" 111 112 mg_interface.MadGraphCmd.check_display(self,args) 113 114 if args[0] in ['diagrams', 'processes'] and len(args)>=3 \ 115 and args[1] not in ['born','loop','virt','real']: 116 raise self.InvalidCmd("Can only display born, loop (virt) or real diagrams, not %s."%args[1]) 117 # rename args[1] if it is 'virt' 118 if len(args) > 1: 119 if args[1] == 'virt': 120 args[1] = 'loop'
121
122 - def check_add(self, args):
123 124 super(CheckFKS, self).check_add(args) 125 if '$' in args: 126 raise self.InvalidCmd('$ syntax not valid for aMC@NLO. $$ syntax is on the other hand a valid syntax.')
127
128 - def check_tutorial(self, args):
129 """check the validity of the line""" 130 if len(args) == 0: 131 #this means mg5 tutorial 132 args.append('aMCatNLO') 133 else: 134 return mg_interface.CheckValidForCmd.check_tutorial(self,args)
135
136 - def check_output(self, args):
137 """ check the validity of the line""" 138 139 self._export_format = 'NLO' 140 forbidden_formats = ['madevent', 'standalone'] 141 142 143 if not hasattr(self, '_fks_multi_proc') or not self._fks_multi_proc: 144 text = 'No processes generated. Please generate a process first.' 145 raise self.InvalidCmd(text) 146 147 if not self._curr_model: 148 text = 'No model found. Please import a model first and then retry.' 149 raise self.InvalidCmd(text) 150 151 if args and args[0][0] != '-': 152 if args[0] in forbidden_formats: 153 text = 'You generated a NLO process, which cannot be exported in %s mode.\n' % args[0] 154 text+= 'Please use the command "output DIR_NAME".\n' 155 raise self.InvalidCmd(text) 156 157 # This is a path 158 path = args.pop(0) 159 # Check for special directory treatment 160 if path == 'auto': 161 self.get_default_path() 162 elif path != 'auto': 163 self._export_dir = path 164 else: 165 # No valid path 166 self.get_default_path() 167 168 self._export_dir = os.path.realpath(self._export_dir)
169 170
171 - def check_launch(self, args, options):
172 """check the validity of the line. args are DIR and MODE 173 MODE being LO, NLO, aMC@NLO or aMC@LO. If no mode is passed, aMC@NLO is used""" 174 # modify args in order to be DIR 175 # mode being either standalone or madevent 176 177 if not args: 178 if self._done_export: 179 args.append(self._done_export[0]) 180 args.append('auto') 181 182 return 183 else: 184 self.help_launch() 185 raise self.InvalidCmd('No default location available, please specify location.') 186 187 if len(args) > 2: 188 self.help_launch() 189 return self.InvalidCmd, 'Invalid Syntax: Too many argument' 190 191 elif len(args) == 2: 192 if not args[1] in ['LO', 'NLO', 'aMC@NLO', 'aMC@LO', 'auto']: 193 raise self.InvalidCmd('%s is not a valid mode, please use "LO", "NLO", "aMC@NLO" or "aMC@LO"' % args[1]) 194 else: 195 #check if args[0] is path or mode 196 if args[0] in ['LO', 'NLO', 'aMC@NLO', 'aMC@LO', 'auto'] and self._done_export: 197 args.insert(0, self._done_export[0]) 198 elif os.path.isdir(args[0]) or os.path.isdir(pjoin(MG5DIR, args[0]))\ 199 or os.path.isdir(pjoin(MG4DIR, args[0])): 200 args.append('auto') 201 else: 202 self.help_launch() 203 raise self.InvalidCmd('%s is not a valid process directory nor run mode' % args[0]) 204 205 mode = args[1] 206 207 # search for a valid path 208 if os.path.isdir(args[0]): 209 path = os.path.realpath(args[0]) 210 elif os.path.isdir(pjoin(MG5DIR,args[0])): 211 path = pjoin(MG5DIR,args[0]) 212 elif MG4DIR and os.path.isdir(pjoin(MG4DIR,args[0])): 213 path = pjoin(MG4DIR,args[0]) 214 else: 215 raise self.InvalidCmd('%s is not a valid directory' % args[0]) 216 args[0] = path 217 218 # inform where we are for future command 219 self._done_export = [path, mode] 220 221 # check for incompatible options/modes 222 if options['multicore'] and options['cluster']: 223 raise self.InvalidCmd('options -m (--multicore) and -c (--cluster)' + \ 224 ' are not compatible. Please choose one.') 225 if mode == 'NLO' and options['reweightonly']: 226 raise self.InvalidCmd('option -r (--reweightonly) needs mode "aMC@NLO" or "aMC@LO"')
227 228
229 -class CheckFKSWeb(mg_interface.CheckValidForCmdWeb, CheckFKS):
230 pass
231
232 -class CompleteFKS(mg_interface.CompleteForCmd):
233
234 - def complete_display(self, text, line, begidx, endidx):
235 """Complete the display command in the context of the FKS interface""" 236 237 args = self.split_arg(line[0:begidx]) 238 239 if len(args) == 2 and args[1] in ['diagrams', 'processes']: 240 return self.list_completion(text, ['born', 'loop', 'virt', 'real']) 241 else: 242 return mg_interface.MadGraphCmd.complete_display(self, text, line, 243 begidx, endidx)
244 245
246 - def complete_output(self, text, line, begidx, endidx):
247 """Complete the output command in the context of the FKS interface""" 248 #don't propose directory use by MG_ME 249 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS', 250 'Calculators', 'MadAnalysis', 'SimpleAnalysis', 251 'mg5', 'DECAY', 'EventConverter', 'Models', 252 'ExRootAnalysis', 'HELAS', 'Transfer_Fct', 'aloha', 253 'madgraph', 'bin', 'tests', 'input', 'vendor', 'models'] 254 255 #name of the run =>proposes old run name 256 args = self.split_arg(line[0:begidx]) 257 if len(args) >= 1: 258 if len(args) > 1 and args[1] == 'aloha': 259 try: 260 return self.aloha_complete_output(text, line, begidx, endidx) 261 except Exception as error: 262 print(error) 263 # Directory continuation 264 if args[-1].endswith(os.path.sep): 265 return [name for name in self.path_completion(text, 266 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 267 only_dirs = True) if name not in forbidden_names] 268 269 # directory names 270 content = [name for name in self.path_completion(text, '.', only_dirs = True) \ 271 if name not in forbidden_names] 272 return self.list_completion(text, content)
273 274
275 - def complete_launch(self, text, line, begidx, endidx, formatting=True):
276 """ complete the launch command""" 277 args = self.split_arg(line[0:begidx]) 278 279 # Directory continuation 280 if args[-1].endswith(os.path.sep): 281 return self.path_completion(text, 282 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 283 only_dirs = True) 284 # Format 285 if len(args) == 1: 286 out = {'Path from ./': self.path_completion(text, '.', only_dirs = True)} 287 if MG5DIR != os.path.realpath('.'): 288 out['Path from %s' % MG5DIR] = self.path_completion(text, 289 MG5DIR, only_dirs = True, relative=False) 290 if MG4DIR and MG4DIR != os.path.realpath('.') and MG4DIR != MG5DIR: 291 out['Path from %s' % MG4DIR] = self.path_completion(text, 292 MG4DIR, only_dirs = True, relative=False) 293 294 if len(args) == 2: 295 modes = ['aMC@NLO', 'NLO', 'aMC@LO', 'LO'] 296 return self.list_completion(text, modes, line) 297 298 #option 299 if len(args) >= 3: 300 out={} 301 302 if line[0:begidx].endswith('--laststep='): 303 opt = ['parton', 'pythia', 'pgs','delphes','auto'] 304 out['Options'] = self.list_completion(text, opt, line) 305 else: 306 307 opt = ['-f', '-c', '-m', '-i', '-x', '-r', '-p', '-o', '-n', 'a', 308 '--force', '--cluster', '--multicore', '--interactive', 309 '--nocompile', '--reweightonly', '--parton', '--only_generation', '--name', '--appl_start_grid'] 310 out['Options'] = self.list_completion(text, opt, line) 311 312 313 return self.deal_multiple_categories(out, formatting)
314
315 -class HelpFKS(mg_interface.HelpToCmd):
316
317 - def help_display(self):
318 mg_interface.MadGraphCmd.help_display(self) 319 logger.info(" In aMC@NLO5, after display diagrams, the user can add the option") 320 logger.info(" \"born\", \"virt\" or \"real\" to display only the corresponding diagrams.")
321
322 - def help_launch(self):
323 """help for launch command""" 324 _launch_parser.print_help()
325
326 -class aMCatNLOInterface(CheckFKS, CompleteFKS, HelpFKS, Loop_interface.CommonLoopInterface):
327 328 _fks_display_opts = ['real_diagrams', 'born_diagrams', 'virt_diagrams', 329 'real_processes', 'born_processes', 'virt_processes'] 330 331 _nlo_modes_for_completion = ['all','real'] 332 display_expansion = False 333
334 - def __init__(self, mgme_dir = '', *completekey, **stdin):
335 """ Special init tasks for the Loop Interface """ 336 mg_interface.MadGraphCmd.__init__(self, mgme_dir = '', *completekey, **stdin) 337 self.setup()
338
339 - def setup(self):
340 """ Special tasks when switching to this interface """ 341 342 # Refresh all the interface stored value as things like generated 343 # processes and amplitudes are not to be reused in between different 344 # interfaces 345 # Clear history, amplitudes and matrix elements when a model is imported 346 # Remove previous imports, generations and outputs from history 347 self.history.clean(remove_bef_last='import', 348 to_keep=['set','load','import', 'define']) 349 # Reset amplitudes and matrix elements 350 self._done_export=False 351 self._curr_amps = diagram_generation.AmplitudeList() 352 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 353 self._v4_export_formats = [] 354 self._nlo_modes_for_completion = ['all','real'] 355 self._export_formats = [ 'madevent', 'aloha' ] 356 # Do not force NLO model as the user might have asked for reals only. 357 # It will anyway be forced later if he attempts virt= or all=. 358 self.validate_model(loop_type='real_init', stop=False) 359 # Set where to look for CutTools installation. 360 # In further versions, it will be set in the same manner as _mgme_dir so that 361 # the user can chose its own CutTools distribution. 362 self._cuttools_dir=str(pjoin(self._mgme_dir,'vendor','CutTools')) 363 if not os.path.isdir(pjoin(self._cuttools_dir, 'src','cts')): 364 logger.warning(('Warning: Directory %s is not a valid CutTools directory.'+\ 365 'Using default CutTools instead.') % \ 366 self._cuttools_dir) 367 self._cuttools_dir=str(pjoin(self._mgme_dir,'vendor','CutTools')) 368 # Set where to look for IREGI installation 369 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src')) 370 if not os.path.isdir(self._iregi_dir): 371 logger.warning(('Warning: Directory %s is not a valid IREGI directory.'+\ 372 'Using default IREGI instead.')%\ 373 self._iregi_dir) 374 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
375
376 - def do_display(self, line, output=sys.stdout):
377 # if we arrive here it means that a _fks_display_opts has been chosen 378 args = self.split_arg(line) 379 #check the validity of the arguments 380 self.check_display(args) 381 382 if args[0] in ['diagrams', 'processes', 'diagrams_text']: 383 get_amps_dict = {'real': self._fks_multi_proc.get_real_amplitudes, 384 'born': self._fks_multi_proc.get_born_amplitudes, 385 'loop': self._fks_multi_proc.get_virt_amplitudes} 386 if args[0] == 'diagrams': 387 if len(args)>=2 and args[1] in list(get_amps_dict.keys()): 388 get_amps = get_amps_dict[args[1]] 389 self._curr_amps = get_amps() 390 #check that if one requests the virt diagrams, there are virt_amplitudes 391 if args[1] == 'loop' and len(self._curr_amps) == 0: 392 raise self.InvalidCmd('No virtuals have been generated') 393 self.draw(' '.join(args[2:]), Dtype = args[1]) 394 else: 395 for diag_type, get_amps in get_amps_dict.items(): 396 self._curr_amps = get_amps() 397 if self._curr_amps: 398 self.draw(' '.join(args[1:]), Dtype=diag_type) 399 400 # set _curr_amps back to empty 401 self._curr_amps = diagram_generation.AmplitudeList() 402 403 if args[0] == 'diagrams_text': 404 if len(args)>=2 and args[1] in list(get_amps_dict.keys()): 405 get_amps = get_amps_dict[args[1]] 406 self._curr_amps = get_amps() 407 #check that if one requests the virt diagrams, there are virt_amplitudes 408 if args[1] in ['virt', 'loop'] and len(self._curr_amps) == 0: 409 raise self.InvalidCmd('No virtuals have been generated') 410 text = "\n".join([amp.nice_string() for amp in self._curr_amps]) 411 else: 412 text = 'Born diagrams:\n' 413 text += '\n'.join(amp.nice_string() for amp in get_amps_dict['born']()) 414 text += '\n\nReal diagrams:' 415 text += '\n'.join(amp.nice_string() for amp in get_amps_dict['real']()) 416 text += '\n\nLoop diagrams:\n' 417 text += '\n'.join(amp.nice_string() for amp in get_amps_dict['loop']()) 418 pydoc.pager(text) 419 420 # set _curr_amps back to empty 421 self._curr_amps = diagram_generation.AmplitudeList() 422 423 elif args[0] == 'processes': 424 if len(args)>=2 and args[1] in list(get_amps_dict.keys()): 425 get_amps = get_amps_dict[args[1]] 426 self._curr_amps = get_amps() 427 #check that if one requests the virt diagrams, there are virt_amplitudes 428 if args[1] in ['virt', 'loop'] and len(self._curr_amps) == 0: 429 raise self.InvalidCmd('No virtuals have been generated') 430 print('\n'.join(amp.nice_string_processes() for amp in self._curr_amps)) 431 else: 432 print('Born processes:') 433 print('\n'.join(amp.nice_string_processes() for amp in get_amps_dict['born']())) 434 print('Real processes:') 435 print('\n'.join(amp.nice_string_processes() for amp in get_amps_dict['real']())) 436 print('Loop processes:') 437 print('\n'.join(amp.nice_string_processes() for amp in get_amps_dict['loop']())) 438 # set _curr_amps back to empty 439 self._curr_amps = diagram_generation.AmplitudeList() 440 441 else: 442 mg_interface.MadGraphCmd.do_display(self,line,output)
443
444 - def do_add(self, line, *args,**opt):
445 446 args = self.split_arg(line) 447 # Check the validity of the arguments 448 self.check_add(args) 449 450 if args[0] == 'model': 451 return self.add_model(args[1:]) 452 elif args[0] != 'process': 453 raise self.InvalidCmd("The add command can only be used with process or model") 454 else: 455 line = ' '.join(args[1:]) 456 457 proc_type=self.extract_process_type(line) 458 if proc_type[1] not in ['real', 'LOonly']: 459 run_interface.check_compiler(self.options, block=False) 460 #validate_model will reset self._generate_info; to avoid 461 #this store it 462 463 if not aMCatNLOInterface.display_expansion: 464 if proc_type[2] != ['QCD'] and proc_type[1] == 'all': 465 aMCatNLOInterface.display_expansion = True 466 if 'QED' in proc_type[2]: 467 logger.info( 468 """------------------------------------------------------------------------ 469 This computation involves NLO EW corrections. 470 Please also cite ref. 'arXiv:1804.10017' when using results from this code. 471 ------------------------------------------------------------------------ 472 """, '$MG:BOLD') 473 else: 474 logger.info( 475 """------------------------------------------------------------------------ 476 This computation involve not SM-QCD corrections at NLO. 477 Please also cite ref. 'arXiv:1804.10017' when using results from this code. 478 ------------------------------------------------------------------------ 479 """, '$MG:BOLD') 480 481 482 geninfo = self._generate_info 483 self.validate_model(proc_type[1], coupling_type=proc_type[2]) 484 self._generate_info = geninfo 485 486 #now generate the amplitudes as usual 487 #self.options['group_subprocesses'] = 'False' 488 collect_mirror_procs = False 489 ignore_six_quark_processes = self.options['ignore_six_quark_processes'] 490 if ',' in line: 491 myprocdef, line = mg_interface.MadGraphCmd.extract_decay_chain_process(self,line) 492 if myprocdef.are_decays_perturbed(): 493 raise MadGraph5Error("Decay processes cannot be perturbed") 494 else: 495 myprocdef = mg_interface.MadGraphCmd.extract_process(self,line) 496 497 self.proc_validity(myprocdef,'aMCatNLO_%s'%proc_type[1]) 498 499 # set the orders 500 # if some orders have been set by the user, 501 # check that all the orders of the model have been specified 502 # set to default those which have not been specified and warn the user 503 if myprocdef['orders'] and not all([o in list(myprocdef['orders'].keys()) for o in myprocdef['model'].get_coupling_orders()]): 504 for o in myprocdef['model'].get_coupling_orders(): 505 if o not in list(myprocdef['orders'].keys()): 506 myprocdef['orders'][o] = self.options['default_unset_couplings'] 507 logger.warning(('%s order is missing in the process definition. It will be set to "default unser couplings": %s\n' + \ 508 'If this is not what you need, please regenerate with the correct orders.') % (o,myprocdef['orders'][o])) 509 510 # this is in case no orders have been passed 511 if not myprocdef['squared_orders'] and not myprocdef['orders']: 512 # find the minimum weighted order, then extract the values for the varius 513 # couplings in the model 514 weighted = diagram_generation.MultiProcess.find_optimal_process_orders(myprocdef) 515 if not weighted: 516 raise MadGraph5Error('\nProcess orders cannot be determined automatically. \n' + \ 517 'Please specify them from the command line.') 518 519 # this is a very rough attempt, and works only to guess QED/QCD 520 qed, qcd = fks_common.get_qed_qcd_orders_from_weighted(len(myprocdef['legs']), 521 self._curr_model.get('order_hierarchy'), 522 weighted['WEIGHTED']) 523 524 if qed < 0 or qcd < 0: 525 raise MadGraph5Error('\nAutomatic process-order determination lead to negative constraints:\n' + \ 526 ('QED: %d, QCD: %d\n' % (qed, qcd)) + \ 527 'Please specify the coupling orders from the command line.') 528 if self.options['nlo_mixed_expansion']: 529 orders = {'QED': 2*qed, 'QCD': 2*qcd} 530 # set all the other coupling to zero 531 for o in myprocdef['model'].get_coupling_orders(): 532 if o not in ['QED', 'QCD']: 533 orders[o] = 0 534 535 myprocdef.set('squared_orders', orders) 536 # warn the user of what happened 537 logger.info(('Setting the born squared orders automatically in the process definition to %s.\n' + \ 538 'If this is not what you need, please regenerate with the correct orders.'), 539 ' '.join(['%s^2<=%s' %(k,v) if v else '%s=%s' % (k,v) for k,v in myprocdef['squared_orders'].items()]), 540 '$MG:BOLD') 541 else: 542 orders = {'QED': qed, 'QCD': qcd} 543 sqorders = {'QED': 2*qed, 'QCD': 2*qcd} 544 # set all the other coupling to zero 545 for o in myprocdef['model'].get_coupling_orders(): 546 if o not in ['QED', 'QCD']: 547 orders[o] = 0 548 sqorders[o] = 0 549 550 myprocdef.set('orders', orders) 551 myprocdef.set('squared_orders', sqorders) 552 # warn the user of what happened 553 logger.info(('Setting the born orders automatically in the process definition to %s.\n' + \ 554 'If this is not what you need, please regenerate with the correct orders.'), 555 ' '.join(['%s<=%s' %(k,v) if v else '%s=%s' % (k,v) for k,v in myprocdef['orders'].items()]), 556 '$MG:BOLD') 557 558 # now check that all couplings that are there in orders also appear 559 # in squared_orders. If not, set the corresponding one 560 for k, v in myprocdef['orders'].items(): 561 if k not in myprocdef['squared_orders'].keys(): 562 myprocdef['squared_orders'][k] = 2*v 563 logger.warning('Order %s is not constrained as squared_orders. Using: %s^2=%d' % (k,k,2*v) ) 564 565 # check that all the couplings of the model have been constrained 566 # in the squared orders, otherwise set the others to zero 567 for o in myprocdef['model'].get('coupling_orders'): 568 if o not in myprocdef['squared_orders'].keys(): 569 logger.warning('No squared order constraint for order %s. Setting to 0' % o) 570 myprocdef['squared_orders'][o] = 0 571 572 myprocdef['born_sq_orders'] = copy.copy(myprocdef['squared_orders']) 573 # split all orders in the model, for the moment it's the simplest solution 574 # mz02/2014 575 #if proc_type[1] != 'only': 576 myprocdef['split_orders'] += [o for o in myprocdef['model'].get('coupling_orders') \ 577 if o not in myprocdef['split_orders']] 578 579 # now set the squared orders 580 if not myprocdef['squared_orders']: 581 logger.warning('No squared orders have been provided, will be guessed by the order constraints') 582 for ord, val in myprocdef['orders'].items(): 583 myprocdef['squared_orders'][ord] = 2 * val 584 585 # then increase the orders which are perturbed 586 for pert in myprocdef['perturbation_couplings']: 587 588 if not self.options['nlo_mixed_expansion'] and pert not in proc_type[2]: 589 continue 590 591 592 # if orders have been specified increase them 593 if list(myprocdef['orders'].keys()) != ['WEIGHTED']: 594 try: 595 myprocdef['orders'][pert] += 1 596 except KeyError: 597 # if the order is not specified 598 # then MG does not put any bound on it 599 ###myprocdef['orders'][pert] = 99 600 pass 601 try: 602 myprocdef['squared_orders'][pert] += 2 603 except KeyError: 604 # the order is not provided, assume 605 # it is originally zero 606 myprocdef['squared_orders'][pert] = 2 607 608 # update also the WEIGHTED entry 609 if 'WEIGHTED' in list(myprocdef['orders'].keys()): 610 myprocdef['orders']['WEIGHTED'] += 1 * \ 611 max([myprocdef.get('model').get('order_hierarchy')[ord] for \ 612 ord in myprocdef['perturbation_couplings']]) 613 614 myprocdef['squared_orders']['WEIGHTED'] += 2 * \ 615 max([myprocdef.get('model').get('order_hierarchy')[ord] for \ 616 ord in myprocdef['perturbation_couplings']]) 617 # if [orders] have not been specified, 618 # finally set perturbation_couplings to **all** the coupling orders 619 # avaliable in the model. 620 # This is necessary because when doing EW corrections one only specifies 621 # squared-orders constraints. In that case, all kind of splittings/loop-particles 622 # must be included 623 if not myprocdef['orders'] and self.options['nlo_mixed_expansion']: 624 myprocdef['perturbation_couplings'] = list(myprocdef['model']['coupling_orders']) 625 626 self._curr_proc_defs.append(myprocdef) 627 628 # if the new nlo process generation mode is enabled, the number of cores to be 629 # used has to be passed 630 # ncores_for_proc_gen has the following meaning 631 # 0 : do things the old way 632 # > 0 use ncores_for_proc_gen 633 # -1 : use all cores 634 if self.options['low_mem_multicore_nlo_generation']: 635 if self.options['nb_core']: 636 self.ncores_for_proc_gen = int(self.options['nb_core']) 637 else: 638 self.ncores_for_proc_gen = -1 639 else: 640 self.ncores_for_proc_gen = 0 641 642 # this is the options dictionary to pass to the FKSMultiProcess 643 fks_options = {'OLP': self.options['OLP'], 644 'ignore_six_quark_processes': self.options['ignore_six_quark_processes'], 645 'init_lep_split': self.options['include_lepton_initiated_processes'], 646 'ncores_for_proc_gen': self.ncores_for_proc_gen, 647 'nlo_mixed_expansion': self.options['nlo_mixed_expansion']} 648 649 fksproc =fks_base.FKSMultiProcess(myprocdef,fks_options) 650 try: 651 self._fks_multi_proc.add(fksproc) 652 except AttributeError: 653 self._fks_multi_proc = fksproc 654 655 if not aMCatNLOInterface.display_expansion and self.options['nlo_mixed_expansion']: 656 base = {} 657 for amp in self._fks_multi_proc.get_born_amplitudes(): 658 nb_part = len(amp['process']['legs']) 659 for diag in amp['diagrams']: 660 if nb_part not in base: 661 base[nb_part] = diag.get('orders') 662 elif base[nb_part] != diag.get('orders'): 663 aMCatNLOInterface.display_expansion = True 664 logger.info( 665 """------------------------------------------------------------------------ 666 This computation can involve not only purely SM-QCD corrections at NLO. 667 Please also cite ref. 'arXiv:1804.10017' when using results from this code. 668 ------------------------------------------------------------------------ 669 """, '$MG:BOLD') 670 break 671 else: 672 continue 673 break
674 675 676 677
678 - def do_output(self, line):
679 """Main commands: Initialize a new Template or reinitialize one""" 680 681 args = self.split_arg(line) 682 # Check Argument validity 683 self.check_output(args) 684 685 noclean = '-noclean' in args 686 force = '-f' in args 687 nojpeg = '-nojpeg' in args 688 main_file_name = "" 689 try: 690 main_file_name = args[args.index('-name') + 1] 691 except Exception: 692 pass 693 694 # For NLO, the group_subprocesses is automatically set to false 695 group_processes = False 696 # initialize the writer 697 if self._export_format in ['NLO']: 698 self._curr_exporter = export_v4.ExportV4Factory(self, noclean, 699 output_type='amcatnlo',group_subprocesses=group_processes) 700 701 self._curr_exporter.pass_information_from_cmd(self) 702 703 # check if a dir with the same name already exists 704 if not force and not noclean and os.path.isdir(self._export_dir)\ 705 and self._export_format in ['NLO']: 706 # Don't ask if user already specified force or noclean 707 logger.info('INFO: directory %s already exists.' % self._export_dir) 708 logger.info('If you continue this directory will be deleted and replaced.') 709 answer = self.ask('Do you want to continue?', 'y', ['y','n'], 710 timeout=self.options['timeout']) 711 if answer != 'y': 712 raise self.InvalidCmd('Stopped by user request') 713 714 # if one gets here either used -f or answered yes to the question about 715 # removing the dir 716 if os.path.exists(self._export_dir): 717 shutil.rmtree(self._export_dir) 718 719 # Make a Template Copy 720 if self._export_format in ['NLO']: 721 self._curr_exporter.copy_fkstemplate() 722 723 # Reset _done_export, since we have new directory 724 self._done_export = False 725 726 # Perform export and finalize right away 727 self.export(nojpeg, main_file_name, group_processes=group_processes) 728 729 # Pass potential new information generated during the export. 730 self._curr_exporter.pass_information_from_cmd(self) 731 732 # Automatically run finalize 733 self.finalize(nojpeg) 734 735 # Generate the virtuals if from OLP 736 if self.options['OLP']!='MadLoop': 737 self._curr_exporter.generate_virtuals_from_OLP( 738 self.born_processes_for_olp,self._export_dir,self.options['OLP']) 739 740 # Remember that we have done export 741 self._done_export = (self._export_dir, self._export_format) 742 743 # Reset _export_dir, so we don't overwrite by mistake later 744 self._export_dir = None
745 746 # Export a matrix element
747 - def export(self, nojpeg = False, main_file_name = "", group_processes=False):
748 """Export a generated amplitude to file""" 749 750 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 751 def generate_matrix_elements(self, group=False): 752 """Helper function to generate the matrix elements before 753 exporting""" 754 755 # Sort amplitudes according to number of diagrams, 756 # to get most efficient multichannel output 757 self._curr_amps.sort(key = lambda a: a.get_number_of_diagrams(), reverse=True) 758 759 cpu_time1 = time.time() 760 ndiags = 0 761 if not self._curr_matrix_elements.get_matrix_elements(): 762 if group: 763 raise MadGraph5Error("Cannot group subprocesses when "+\ 764 "exporting to NLO") 765 else: 766 self._curr_matrix_elements = \ 767 fks_helas.FKSHelasMultiProcess(\ 768 self._fks_multi_proc, 769 loop_optimized= self.options['loop_optimized_output']) 770 771 if not self.options['low_mem_multicore_nlo_generation']: 772 # generate the code the old way 773 ndiags = sum([len(me.get('diagrams')) for \ 774 me in self._curr_matrix_elements.\ 775 get_matrix_elements()]) 776 # assign a unique id number to all process and 777 # generate a list of possible PDF combinations 778 uid = 0 779 initial_states=[] 780 for me in self._curr_matrix_elements.get_matrix_elements(): 781 uid += 1 # update the identification number 782 me.get('processes')[0].set('uid', uid) 783 try: 784 initial_states.append(sorted(list(set((p.get_initial_pdg(1),p.get_initial_pdg(2)) for \ 785 p in me.born_me.get('processes'))))) 786 except IndexError: 787 initial_states.append(sorted(list(set((p.get_initial_pdg(1)) for \ 788 p in me.born_me.get('processes'))))) 789 790 for fksreal in me.real_processes: 791 # Pick out all initial state particles for the two beams 792 try: 793 initial_states.append(sorted(list(set((p.get_initial_pdg(1),p.get_initial_pdg(2)) for \ 794 p in fksreal.matrix_element.get('processes'))))) 795 except IndexError: 796 initial_states.append(sorted(list(set((p.get_initial_pdg(1)) for \ 797 p in fksreal.matrix_element.get('processes'))))) 798 799 800 # remove doubles from the list 801 checked = [] 802 for e in initial_states: 803 if e not in checked: 804 checked.append(e) 805 initial_states=checked 806 807 self._curr_matrix_elements.set('initial_states',initial_states) 808 809 else: 810 #new NLO generation 811 if self._curr_matrix_elements['has_loops']: 812 self._curr_exporter.opt['mp'] = True 813 self._curr_exporter.model = self._curr_model 814 ndiags = 0 815 816 cpu_time2 = time.time() 817 return ndiags, cpu_time2 - cpu_time1
818 819 # Start of the actual routine 820 821 ndiags, cpu_time = generate_matrix_elements(self, group=group_processes) 822 calls = 0 823 824 path = self._export_dir 825 826 if self._export_format in ['NLO']: 827 path = os.path.join(path, 'SubProcesses') 828 829 #_curr_matrix_element is a FKSHelasMultiProcess Object 830 self._fks_directories = [] 831 proc_charac = self._curr_exporter.proc_characteristic 832 for charac in ['has_isr', 'has_fsr', 'has_loops']: 833 proc_charac[charac] = self._curr_matrix_elements[charac] 834 835 # prepare for the generation 836 # glob_directories_map is for the new NLO generation 837 global glob_directories_map 838 glob_directories_map = [] 839 840 # Save processes instances generated 841 self.born_processes_for_olp = [] 842 self.born_processes = [] 843 for ime, me in \ 844 enumerate(self._curr_matrix_elements.get('matrix_elements')): 845 if not self.options['low_mem_multicore_nlo_generation']: 846 #me is a FKSHelasProcessFromReals 847 calls = calls + \ 848 self._curr_exporter.generate_directories_fks(me, 849 self._curr_helas_model, 850 ime, len(self._curr_matrix_elements.get('matrix_elements')), 851 path,self.options['OLP']) 852 self._fks_directories.extend(self._curr_exporter.fksdirs) 853 self.born_processes_for_olp.append(me.born_me.get('processes')[0]) 854 self.born_processes.append(me.born_me.get('processes')) 855 else: 856 glob_directories_map.append(\ 857 [self._curr_exporter, me, self._curr_helas_model, 858 ime, len(self._curr_matrix_elements.get('matrix_elements')), 859 path, self.options['OLP']]) 860 861 if self.options['low_mem_multicore_nlo_generation']: 862 # start the pool instance with a signal instance to catch ctr+c 863 logger.info('Writing directories...') 864 if six.PY3: 865 ctx = multiprocessing.get_context('fork') # spawn is default for 3.8 and does not work 866 else: 867 ctx = multiprocessing 868 original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) 869 if self.ncores_for_proc_gen < 0: # use all cores 870 pool = ctx.Pool(maxtasksperchild=1) 871 else: 872 pool = ctx.Pool(processes=self.ncores_for_proc_gen,maxtasksperchild=1) 873 signal.signal(signal.SIGINT, original_sigint_handler) 874 try: 875 # the very large timeout passed to get is to be able to catch 876 # KeyboardInterrupts 877 diroutputmap = pool.map_async(generate_directories_fks_async, 878 list(range(len(glob_directories_map)))).get(9999999) 879 except KeyboardInterrupt: 880 pool.terminate() 881 raise KeyboardInterrupt 882 883 pool.close() 884 pool.join() 885 886 #clean up tmp files containing final matrix elements 887 for mefile in self._curr_matrix_elements.get('matrix_elements'): 888 os.remove(mefile) 889 890 for charac in ['nexternal', 'ninitial', 'splitting_types']: 891 proc_charac[charac] = self._curr_exporter.proc_characteristic[charac] 892 # ninitial and nexternal 893 894 895 proc_charac['nexternal'] = max([diroutput[4] for diroutput in diroutputmap]) 896 ninitial_set = set([diroutput[3] for diroutput in diroutputmap]) 897 if len(ninitial_set) != 1: 898 raise MadGraph5Error("Invalid ninitial values: %s" % ' ,'.join(list(ninitial_set))) 899 proc_charac['ninitial'] = list(ninitial_set)[0] 900 901 # max_n_matched_jets 902 njet_set = set([int(diroutput[6]) for diroutput in diroutputmap]) 903 proc_charac['max_n_matched_jets'] = max(njet_set) 904 905 self.born_processes = [] 906 self.born_processes_for_olp = [] 907 max_loop_vertex_ranks = [] 908 909 # transform proc_charac['splitting_types'] into a set 910 splitting_types = set(proc_charac['splitting_types']) 911 for diroutput in diroutputmap: 912 splitting_types = splitting_types.union(set(diroutput[7])) 913 calls = calls + diroutput[0] 914 self._fks_directories.extend(diroutput[1]) 915 max_loop_vertex_ranks.append(diroutput[2]) 916 if six.PY2: 917 self.born_processes.extend(diroutput[4]) 918 self.born_processes_for_olp.append(diroutput[4][0]) 919 920 # transform proc_charac['splitting_types'] back to a list 921 proc_charac['splitting_types'] = list(splitting_types) 922 923 else: 924 max_loop_vertex_ranks = [me.get_max_loop_vertex_rank() for \ 925 me in self._curr_matrix_elements.get_virt_matrix_elements()] 926 927 card_path = os.path.join(path, os.path.pardir, 'SubProcesses', \ 928 'procdef_mg5.dat') 929 930 if self.options['loop_optimized_output'] and \ 931 len(max_loop_vertex_ranks) > 0: 932 self._curr_exporter.write_coef_specs_file(max_loop_vertex_ranks) 933 if self._generate_info: 934 self._curr_exporter.write_procdef_mg5(card_path, # 935 self._curr_model['name'], 936 self._generate_info) 937 try: 938 cmd.Cmd.onecmd(self, 'history .') 939 except Exception: 940 logger.debug('fail to run command \"history cmd\"') 941 pass 942 subproc_path = os.path.join(path, os.path.pardir, 'SubProcesses', \ 943 'initial_states_map.dat') 944 nmaxpdf = self._curr_exporter.write_init_map(subproc_path, 945 self._curr_matrix_elements.get('initial_states')) 946 self._curr_exporter.write_maxproc_files(nmaxpdf, 947 os.path.join(path, os.path.pardir, 'SubProcesses')) 948 949 cpu_time1 = time.time()
950 951
952 - def do_launch(self, line):
953 """Main commands: Ask for editing the parameters and then execute the code (NLO or aMC@(N)LO) 954 """ 955 old_cwd = os.getcwd() 956 argss = self.split_arg(line) 957 # check argument validity and normalise argument 958 (options, argss) = _launch_parser.parse_args(argss) 959 options = options.__dict__ 960 self.check_launch(argss, options) 961 if not os.path.isdir(os.path.join(os.getcwd(), argss[0], 'Events')): 962 self.do_switch('ML5') 963 return mg_interface.MadGraphCmd.do_launch(self,line) 964 # if self.options['automatic_html_opening']: 965 # misc.open_file(os.path.join(os.getcwd(), argss[0], 'crossx.html')) 966 # self.options['automatic_html_opening'] = False 967 968 if options['interactive']: 969 if isinstance(self, extended_cmd.CmdShell): 970 ME = run_interface.aMCatNLOCmdShell(me_dir=argss[0], options=self.options) 971 else: 972 ME = run_interface.aMCatNLOCmd(me_dir=argss[0],options=self.options) 973 ME.pass_in_web_mode() 974 # transfer interactive configuration 975 config_line = [l for l in self.history if l.strip().startswith('set')] 976 for line in config_line: 977 ME.exec_cmd(line) 978 stop = self.define_child_cmd_interface(ME) 979 return stop 980 981 ext_program = launch_ext.aMCatNLOLauncher(argss[0], self, run_mode=argss[1], 982 shell = isinstance(self, extended_cmd.CmdShell), 983 **options) 984 ext_program.run()
985 986 987
988 -class aMCatNLOInterfaceWeb(mg_interface.CheckValidForCmdWeb, aMCatNLOInterface):
989 pass
990 991 _launch_usage = "launch [DIRPATH] [MODE] [options]\n" + \ 992 "-- execute the aMC@NLO output present in DIRPATH\n" + \ 993 " By default DIRPATH is the latest created directory\n" + \ 994 " MODE can be either LO, NLO, aMC@NLO or aMC@LO (if omitted, it is asked in a separate question)\n" + \ 995 " If mode is set to LO/NLO, no event generation will be performed, but only the \n" + \ 996 " computation of the total cross-section and the filling of parton-level histograms \n" + \ 997 " specified in the DIRPATH/SubProcesses/madfks_plot.f file.\n" + \ 998 " If mode is set to aMC@LO/aMC@NLO, after the cross-section computation, a .lhe \n" + \ 999 " event file is generated which will be showered with the MonteCarlo specified \n" + \ 1000 " in the run_card.dat\n" 1001 1002 _launch_parser = misc.OptionParser(usage=_launch_usage) 1003 _launch_parser.add_option("-f", "--force", default=False, action='store_true', 1004 help="Use the card present in the directory for the launch, without editing them") 1005 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true', 1006 help="Submit the jobs on the cluster") 1007 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true', 1008 help="Use interactive consol") 1009 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true', 1010 help="Submit the jobs on multicore mode") 1011 _launch_parser.add_option("-x", "--nocompile", default=False, action='store_true', 1012 help="Skip compilation. Ignored if no executable is found") 1013 _launch_parser.add_option("-r", "--reweightonly", default=False, action='store_true', 1014 help="Skip integration and event generation, just run reweight on the" + \ 1015 " latest generated event files (see list in SubProcesses/nevents_unweighted)") 1016 _launch_parser.add_option("-p", "--parton", default=False, action='store_true', 1017 help="Stop the run after the parton level file generation (you need " + \ 1018 "to shower the file in order to get physical results)") 1019 _launch_parser.add_option("-o", "--only_generation", default=False, action='store_true', 1020 help="Skip grid set up, just generate events starting from " + \ 1021 "the last available results") 1022 # the last option is different from the corresponding in amcatnlo_run_interface as it stores the 1023 # 'name' entry of the options, not the run_name one 1024 _launch_parser.add_option("-n", "--name", default=False, dest='name', 1025 help="Provide a name to the run") 1026 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true', 1027 help="Run the reweight module (reweighting by different model parameter") 1028 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', 1029 help="Run the madspin package") 1030