1
2
3
4
5
6
7
8
9
10
11
12
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 logging
21 import pydoc
22 import sys
23 import time
24 import optparse
25 import subprocess
26 import shutil
27
28 import madgraph
29 from madgraph import MG4DIR, MG5DIR, MadGraph5Error
30 import madgraph.interface.extended_cmd as cmd
31 import madgraph.interface.madgraph_interface as mg_interface
32 import madgraph.interface.madevent_interface as me_interface
33 import madgraph.interface.amcatnlo_run_interface as run_interface
34 import madgraph.interface.launch_ext_program as launch_ext
35 import madgraph.interface.loop_interface as Loop_interface
36 import madgraph.fks.fks_base as fks_base
37 import madgraph.fks.fks_helas_objects as fks_helas
38 import madgraph.iolibs.export_fks as export_fks
39 import madgraph.iolibs.export_v4 as export_v4
40 import madgraph.loop.loop_base_objects as loop_base_objects
41 import madgraph.core.diagram_generation as diagram_generation
42 import madgraph.core.helas_objects as helas_objects
43 import madgraph.various.cluster as cluster
44 import madgraph.various.misc as misc
45
46
47 pjoin = os.path.join
48
49
50 logger = logging.getLogger('cmdprint')
51 logger_stderr = logging.getLogger('fatalerror')
52
53 -class CheckFKS(mg_interface.CheckValidForCmd):
54
55
57 """ Check the arguments of the display diagrams command in the context
58 of the Loop interface."""
59
60 mg_interface.MadGraphCmd.check_display(self,args)
61
62 if args[0] in ['diagrams', 'processes'] and len(args)>=3 \
63 and args[1] not in ['born','loop','virt','real']:
64 raise self.InvalidCmd("Can only display born, loop (virt) or real diagrams, not %s."%args[1])
65
66 if len(args) > 1:
67 if args[1] == 'virt':
68 args[1] = 'loop'
69
75
83
85 """ check the validity of the line"""
86
87 self._export_format = 'NLO'
88 forbidden_formats = ['madevent', 'standalone']
89
90
91 if not hasattr(self, '_fks_multi_proc') or not self._fks_multi_proc:
92 text = 'No processes generated. Please generate a process first.'
93 raise self.InvalidCmd(text)
94
95 if not self._curr_model:
96 text = 'No model found. Please import a model first and then retry.'
97 raise self.InvalidCmd(text)
98
99 if args and args[0][0] != '-':
100 if args[0] in forbidden_formats:
101 text = 'You generated a NLO process, which cannot be exported in %s mode.\n' % args[0]
102 text+= 'Please use the command "output DIR_NAME".\n'
103 raise self.InvalidCmd(text)
104
105
106 path = args.pop(0)
107
108 if path == 'auto':
109 self.get_default_path()
110 elif path != 'auto':
111 self._export_dir = path
112 else:
113
114 self.get_default_path()
115
116 self._export_dir = os.path.realpath(self._export_dir)
117
118
120 """check the validity of the line. args are DIR and MODE
121 MODE being LO, NLO, aMC@NLO or aMC@LO. If no mode is passed, aMC@NLO is used"""
122
123
124
125 if not args:
126 if self._done_export:
127 args.append(self._done_export[0])
128 args.append('auto')
129
130 return
131 else:
132 self.help_launch()
133 raise self.InvalidCmd, \
134 'No default location available, please specify location.'
135
136 if len(args) > 2:
137 self.help_launch()
138 return self.InvalidCmd, 'Invalid Syntax: Too many argument'
139
140 elif len(args) == 2:
141 if not args[1] in ['LO', 'NLO', 'aMC@NLO', 'aMC@LO', 'auto']:
142 raise self.InvalidCmd, '%s is not a valid mode, please use "LO", "NLO", "aMC@NLO" or "aMC@LO"' % args[1]
143 else:
144
145 if args[0] in ['LO', 'NLO', 'aMC@NLO', 'aMC@LO', 'auto'] and self._done_export:
146 args.insert(0, self._done_export[0])
147 elif os.path.isdir(args[0]) or os.path.isdir(pjoin(MG5DIR, args[0]))\
148 or os.path.isdir(pjoin(MG4DIR, args[0])):
149 args.append('auto')
150 else:
151 self.help_launch()
152 raise self.InvalidCmd, '%s is not a valid process directory nor run mode' % args[0]
153
154 mode = args[1]
155
156
157 if os.path.isdir(args[0]):
158 path = os.path.realpath(args[0])
159 elif os.path.isdir(pjoin(MG5DIR,args[0])):
160 path = pjoin(MG5DIR,args[0])
161 elif MG4DIR and os.path.isdir(pjoin(MG4DIR,args[0])):
162 path = pjoin(MG4DIR,args[0])
163 else:
164 raise self.InvalidCmd, '%s is not a valid directory' % args[0]
165 args[0] = path
166
167
168 self._done_export = [path, mode]
169
170
171 if options['multicore'] and options['cluster']:
172 raise self.InvalidCmd, 'options -m (--multicore) and -c (--cluster)' + \
173 ' are not compatible. Please choose one.'
174 if mode == 'NLO' and options['reweightonly']:
175 raise self.InvalidCmd, 'option -r (--reweightonly) needs mode "aMC@NLO" or "aMC@LO"'
176
177
178 -class CheckFKSWeb(mg_interface.CheckValidForCmdWeb, CheckFKS):
180
182
184 """Complete the display command in the context of the FKS interface"""
185
186 args = self.split_arg(line[0:begidx])
187
188 if len(args) == 2 and args[1] in ['diagrams', 'processes']:
189 return self.list_completion(text, ['born', 'loop', 'virt', 'real'])
190 else:
191 return mg_interface.MadGraphCmd.complete_display(self, text, line,
192 begidx, endidx)
193
194
196 """Complete the output command in the context of the FKS interface"""
197
198 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS',
199 'Calculators', 'MadAnalysis', 'SimpleAnalysis',
200 'mg5', 'DECAY', 'EventConverter', 'Models',
201 'ExRootAnalysis', 'HELAS', 'Transfer_Fct', 'aloha',
202 'madgraph', 'bin', 'tests', 'input', 'vendor', 'models']
203
204
205 args = self.split_arg(line[0:begidx])
206 if len(args) >= 1:
207 if len(args) > 1 and args[1] == 'aloha':
208 try:
209 return self.aloha_complete_output(text, line, begidx, endidx)
210 except Exception, error:
211 print error
212
213 if args[-1].endswith(os.path.sep):
214 return [name for name in self.path_completion(text,
215 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
216 only_dirs = True) if name not in forbidden_names]
217
218
219 content = [name for name in self.path_completion(text, '.', only_dirs = True) \
220 if name not in forbidden_names]
221 return self.list_completion(text, content)
222
223
225 """ complete the launch command"""
226 args = self.split_arg(line[0:begidx])
227
228
229 if args[-1].endswith(os.path.sep):
230 return self.path_completion(text,
231 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
232 only_dirs = True)
233
234 if len(args) == 1:
235 out = {'Path from ./': self.path_completion(text, '.', only_dirs = True)}
236 if MG5DIR != os.path.realpath('.'):
237 out['Path from %s' % MG5DIR] = self.path_completion(text,
238 MG5DIR, only_dirs = True, relative=False)
239 if MG4DIR and MG4DIR != os.path.realpath('.') and MG4DIR != MG5DIR:
240 out['Path from %s' % MG4DIR] = self.path_completion(text,
241 MG4DIR, only_dirs = True, relative=False)
242
243 if len(args) == 2:
244 modes = ['aMC@NLO', 'NLO', 'aMC@LO', 'LO']
245 return self.list_completion(text, modes, line)
246
247
248 if len(args) >= 3:
249 out={}
250
251 if line[0:begidx].endswith('--laststep='):
252 opt = ['parton', 'pythia', 'pgs','delphes','auto']
253 out['Options'] = self.list_completion(text, opt, line)
254 else:
255
256 opt = ['-f', '-c', '-m', '-i', '-x', '-r', '-p', '-o', '-n', 'a',
257 '--force', '--cluster', '--multicore', '--interactive',
258 '--nocompile', '--reweightonly', '--parton', '--only_generation', '--name', '--appl_start_grid']
259 out['Options'] = self.list_completion(text, opt, line)
260
261
262 return self.deal_multiple_categories(out)
263
264 -class HelpFKS(mg_interface.HelpToCmd):
265
267 mg_interface.MadGraphCmd.help_display(self)
268 logger.info(" In aMC@NLO5, after display diagrams, the user can add the option")
269 logger.info(" \"born\", \"virt\" or \"real\" to display only the corresponding diagrams.")
270
274
275 -class aMCatNLOInterface(CheckFKS, CompleteFKS, HelpFKS, Loop_interface.CommonLoopInterface):
276
277 _fks_display_opts = ['real_diagrams', 'born_diagrams', 'virt_diagrams',
278 'real_processes', 'born_processes', 'virt_processes']
279
280 _nlo_modes_for_completion = ['all','real']
281
282 - def __init__(self, mgme_dir = '', *completekey, **stdin):
288
290 """ Special tasks when switching to this interface """
291
292
293
294
295
296
297 self.history.clean(remove_bef_last='import',
298 to_keep=['set','load','import', 'define'])
299
300 self._done_export=False
301 self._curr_amps = diagram_generation.AmplitudeList()
302 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
303 self._v4_export_formats = []
304 self._nlo_modes_for_completion = ['all','real']
305 self._export_formats = [ 'madevent', 'aloha' ]
306
307
308 self.validate_model(loop_type='real_init', stop=False)
309
310
311
312 self._cuttools_dir=str(pjoin(self._mgme_dir,'vendor','CutTools'))
313 if not os.path.isdir(pjoin(self._cuttools_dir, 'src','cts')):
314 logger.warning(('Warning: Directory %s is not a valid CutTools directory.'+\
315 'Using default CutTools instead.') % \
316 self._cuttools_dir)
317 self._cuttools_dir=str(pjoin(self._mgme_dir,'vendor','CutTools'))
318
319 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
320 if not os.path.isdir(self._iregi_dir):
321 logger.warning(('Warning: Directory %s is not a valid IREGI directory.'+\
322 'Using default IREGI instead.')%\
323 self._iregi_dir)
324 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
325
327
328 args = self.split_arg(line)
329
330 self.check_display(args)
331
332 if args[0] in ['diagrams', 'processes', 'diagrams_text']:
333 get_amps_dict = {'real': self._fks_multi_proc.get_real_amplitudes,
334 'born': self._fks_multi_proc.get_born_amplitudes,
335 'loop': self._fks_multi_proc.get_virt_amplitudes}
336 if args[0] == 'diagrams':
337 if len(args)>=2 and args[1] in get_amps_dict.keys():
338 get_amps = get_amps_dict[args[1]]
339 self._curr_amps = get_amps()
340
341 if args[1] == 'loop' and len(self._curr_amps) == 0:
342 raise self.InvalidCmd('No virtuals have been generated')
343 self.draw(' '.join(args[2:]),type = args[1])
344 else:
345 for diag_type, get_amps in get_amps_dict.items():
346 self._curr_amps = get_amps()
347 self.draw(' '.join(args[1:]), type=diag_type)
348
349 self._curr_amps = diagram_generation.AmplitudeList()
350
351 if args[0] == 'diagrams_text':
352 if len(args)>=2 and args[1] in get_amps_dict.keys():
353 get_amps = get_amps_dict[args[1]]
354 self._curr_amps = get_amps()
355
356 if args[1] in ['virt', 'loop'] and len(self._curr_amps) == 0:
357 raise self.InvalidCmd('No virtuals have been generated')
358 text = "\n".join([amp.nice_string() for amp in self._curr_amps])
359 else:
360 text = 'Born diagrams:\n'
361 text += '\n'.join(amp.nice_string() for amp in get_amps_dict['born']())
362 text += '\n\nReal diagrams:'
363 text += '\n'.join(amp.nice_string() for amp in get_amps_dict['real']())
364 text += '\n\nLoop diagrams:\n'
365 text += '\n'.join(amp.nice_string() for amp in get_amps_dict['virt']())
366 pydoc.pager(text)
367
368
369 self._curr_amps = diagram_generation.AmplitudeList()
370
371 elif args[0] == 'processes':
372 if len(args)>=2 and args[1] in get_amps_dict.keys():
373 get_amps = get_amps_dict[args[1]]
374 self._curr_amps = get_amps()
375
376 if args[1] in ['virt', 'loop'] and len(self._curr_amps) == 0:
377 raise self.InvalidCmd('No virtuals have been generated')
378 print '\n'.join(amp.nice_string_processes() for amp in self._curr_amps)
379 else:
380 print 'Born processes:'
381 print '\n'.join(amp.nice_string_processes() for amp in get_amps_dict['born']())
382 print 'Real processes:'
383 print '\n'.join(amp.nice_string_processes() for amp in get_amps_dict['real']())
384 print 'Loop processes:'
385 print '\n'.join(amp.nice_string_processes() for amp in get_amps_dict['loop']())
386
387 self._curr_amps = diagram_generation.AmplitudeList()
388
389 else:
390 mg_interface.MadGraphCmd.do_display(self,line,output)
391
392 - def do_add(self, line, *args,**opt):
393
394 args = self.split_arg(line)
395
396 self.check_add(args)
397
398 if args[0] == 'model':
399 return self.add_model(args[1:])
400 elif args[0] != 'process':
401 raise self.InvalidCmd("The add command can only be used with process or model")
402 else:
403 line = ' '.join(args[1:])
404
405 proc_type=self.extract_process_type(line)
406 if proc_type[1] != 'real':
407 run_interface.check_compiler(self.options, block=False)
408 self.validate_model(proc_type[1])
409
410
411
412 collect_mirror_procs = False
413 ignore_six_quark_processes = self.options['ignore_six_quark_processes']
414 if ',' in line:
415 myprocdef, line = mg_interface.MadGraphCmd.extract_decay_chain_process(self,line)
416 if myprocdef.are_decays_perturbed():
417 raise MadGraph5Error("Decay processes cannot be perturbed")
418 else:
419 myprocdef = mg_interface.MadGraphCmd.extract_process(self,line)
420 self.proc_validity(myprocdef,'aMCatNLO_%s'%proc_type[1])
421
422 if myprocdef['perturbation_couplings']!=['QCD']:
423 raise self.InvalidCmd("FKS for reals only available in QCD for now, you asked %s" \
424 % ', '.join(myprocdef['perturbation_couplings']))
425 try:
426 self._fks_multi_proc.add(fks_base.FKSMultiProcess(myprocdef,
427 collect_mirror_procs,
428 ignore_six_quark_processes,
429 OLP=self.options['OLP']))
430
431 except AttributeError:
432 self._fks_multi_proc = fks_base.FKSMultiProcess(myprocdef,
433 collect_mirror_procs,
434 ignore_six_quark_processes,
435 OLP=self.options['OLP'])
436
437
439 """Main commands: Initialize a new Template or reinitialize one"""
440
441 args = self.split_arg(line)
442
443 self.check_output(args)
444
445 noclean = '-noclean' in args
446 force = '-f' in args
447 nojpeg = '-nojpeg' in args
448 main_file_name = ""
449 try:
450 main_file_name = args[args.index('-name') + 1]
451 except Exception:
452 pass
453
454 self.options['group_subprocesses'] = False
455
456 if self._export_format in ['NLO']:
457 self._curr_exporter = export_v4.ExportV4Factory(\
458 self, noclean, output_type='amcatnlo')
459
460 if not force and not noclean and os.path.isdir(self._export_dir)\
461 and self._export_format in ['NLO']:
462
463 logger.info('INFO: directory %s already exists.' % self._export_dir)
464 logger.info('If you continue this directory will be deleted and replaced.')
465 answer = self.ask('Do you want to continue?', 'y', ['y','n'],
466 timeout=self.options['timeout'])
467 if answer != 'y':
468 raise self.InvalidCmd('Stopped by user request')
469
470
471
472 if os.path.exists(self._export_dir):
473 shutil.rmtree(self._export_dir)
474
475
476 if self._export_format in ['NLO']:
477 self._curr_exporter.copy_fkstemplate()
478
479
480 self._done_export = False
481
482
483 self.export(nojpeg, main_file_name)
484
485
486 self.finalize(nojpeg)
487
488
489 if self.options['OLP']!='MadLoop':
490 self._curr_exporter.generate_virtuals_from_OLP(
491 self._curr_matrix_elements,self._export_dir,self.options['OLP'])
492
493
494 self._done_export = (self._export_dir, self._export_format)
495
496
497 self._export_dir = None
498
499
500 - def export(self, nojpeg = False, main_file_name = ""):
557
558
559
560 ndiags, cpu_time = generate_matrix_elements(self)
561 calls = 0
562
563 path = self._export_dir
564
565 if self._export_format in ['NLO']:
566 path = os.path.join(path, 'SubProcesses')
567
568
569 self._fks_directories = []
570 proc_characteristics = ''
571 for charac in ['has_isr', 'has_fsr', 'has_loops']:
572 if self._curr_matrix_elements[charac]:
573 proc_characteristics += '%s=true\n' % charac
574 else:
575 proc_characteristics += '%s=false\n' % charac
576
577 open(pjoin(path, 'proc_characteristics'),'w').write(proc_characteristics)
578
579 for ime, me in \
580 enumerate(self._curr_matrix_elements.get('matrix_elements')):
581
582 calls = calls + \
583 self._curr_exporter.generate_directories_fks(me,
584 self._curr_fortran_model,
585 ime, len(self._curr_matrix_elements.get('matrix_elements')),
586 path,self.options['OLP'])
587 self._fks_directories.extend(self._curr_exporter.fksdirs)
588 card_path = os.path.join(path, os.path.pardir, 'SubProcesses', \
589 'procdef_mg5.dat')
590
591 if self.options['loop_optimized_output'] and \
592 len(self._curr_matrix_elements.get_virt_matrix_elements()) > 0:
593 self._curr_exporter.write_coef_specs_file(\
594 self._curr_matrix_elements.get_virt_matrix_elements())
595 if self._generate_info:
596 self._curr_exporter.write_procdef_mg5(card_path,
597 self._curr_model['name'],
598 self._generate_info)
599 try:
600 cmd.Cmd.onecmd(self, 'history .')
601 except Exception:
602 logger.debug('fail to run command \"history cmd\"')
603 pass
604 subproc_path = os.path.join(path, os.path.pardir, 'SubProcesses', \
605 'initial_states_map.dat')
606 self._curr_exporter.write_init_map(subproc_path,
607 self._curr_matrix_elements.get('initial_states'))
608
609 cpu_time1 = time.time()
610
611
613 """Main commands: Ask for editing the parameters and then execute the code (NLO or aMC@(N)LO)
614 """
615 old_cwd = os.getcwd()
616 argss = self.split_arg(line)
617
618 (options, argss) = _launch_parser.parse_args(argss)
619 options = options.__dict__
620 self.check_launch(argss, options)
621 if not os.path.isdir(os.path.join(os.getcwd(), argss[0], 'Events')):
622 self.do_switch('ML5')
623 return mg_interface.MadGraphCmd.do_launch(self,line)
624
625
626
627
628 if options['interactive']:
629 if hasattr(self, 'do_shell'):
630 ME = run_interface.aMCatNLOCmdShell(me_dir=argss[0], options=self.options)
631 else:
632 ME = run_interface.aMCatNLOCmd(me_dir=argss[0],options=self.options)
633 ME.pass_in_web_mode()
634
635 config_line = [l for l in self.history if l.strip().startswith('set')]
636 for line in config_line:
637 ME.exec_cmd(line)
638 stop = self.define_child_cmd_interface(ME)
639 return stop
640
641 ext_program = launch_ext.aMCatNLOLauncher(argss[0], self, run_mode=argss[1], **options)
642 ext_program.run()
643
644
645
648
649 _launch_usage = "launch [DIRPATH] [MODE] [options]\n" + \
650 "-- execute the aMC@NLO output present in DIRPATH\n" + \
651 " By default DIRPATH is the latest created directory\n" + \
652 " MODE can be either LO, NLO, aMC@NLO or aMC@LO (if omitted, it is asked in a separate question)\n" + \
653 " If mode is set to LO/NLO, no event generation will be performed, but only the \n" + \
654 " computation of the total cross-section and the filling of parton-level histograms \n" + \
655 " specified in the DIRPATH/SubProcesses/madfks_plot.f file.\n" + \
656 " If mode is set to aMC@LO/aMC@NLO, after the cross-section computation, a .lhe \n" + \
657 " event file is generated which will be showered with the MonteCarlo specified \n" + \
658 " in the run_card.dat\n"
659
660 _launch_parser = misc.OptionParser(usage=_launch_usage)
661 _launch_parser.add_option("-f", "--force", default=False, action='store_true',
662 help="Use the card present in the directory for the launch, without editing them")
663 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true',
664 help="Submit the jobs on the cluster")
665 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true',
666 help="Use interactive consol")
667 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true',
668 help="Submit the jobs on multicore mode")
669 _launch_parser.add_option("-x", "--nocompile", default=False, action='store_true',
670 help="Skip compilation. Ignored if no executable is found")
671 _launch_parser.add_option("-r", "--reweightonly", default=False, action='store_true',
672 help="Skip integration and event generation, just run reweight on the" + \
673 " latest generated event files (see list in SubProcesses/nevents_unweighted)")
674 _launch_parser.add_option("-p", "--parton", default=False, action='store_true',
675 help="Stop the run after the parton level file generation (you need " + \
676 "to shower the file in order to get physical results)")
677 _launch_parser.add_option("-o", "--only_generation", default=False, action='store_true',
678 help="Skip grid set up, just generate events starting from " + \
679 "the last available results")
680
681
682 _launch_parser.add_option("-n", "--name", default=False, dest='name',
683 help="Provide a name to the run")
684 _launch_parser.add_option("-a", "--appl_start_grid", default=False, dest='appl_start_grid',
685 help="For use with APPLgrid only: start from existing grids")
686