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 from __future__ import absolute_import
20 import os
21 import shutil
22 import time
23 import logging
24 import re
25 import sys
26
27 import madgraph
28 from madgraph import MG4DIR, MG5DIR, MadGraph5Error
29 import madgraph.interface.madgraph_interface as mg_interface
30 import madgraph.interface.extended_cmd as cmd
31 import madgraph.interface.launch_ext_program as launch_ext
32 import madgraph.interface.extended_cmd as extended_cmd
33 import madgraph.core.base_objects as base_objects
34 import madgraph.core.diagram_generation as diagram_generation
35 import madgraph.loop.loop_diagram_generation as loop_diagram_generation
36 import madgraph.loop.loop_base_objects as loop_base_objects
37 import madgraph.loop.loop_helas_objects as loop_helas_objects
38 import madgraph.core.helas_objects as helas_objects
39 import madgraph.iolibs.export_v4 as export_v4
40 import madgraph.iolibs.helas_call_writers as helas_call_writers
41 import madgraph.iolibs.file_writers as writers
42 import madgraph.interface.launch_ext_program as launch_ext
43 import madgraph.various.misc as misc
44 import madgraph.fks.fks_base as fks_base
45 import aloha
46
47
48 logger = logging.getLogger('cmdprint')
49
50
51 pjoin = os.path.join
52
53 -class CheckLoop(mg_interface.CheckValidForCmd):
54
56 """ Check the arguments of the display diagrams command in the context
57 of the Loop interface."""
58
59 mg_interface.MadGraphCmd.check_display(self,args)
60
61 if all([not amp['process']['has_born'] for amp in self._curr_amps]):
62 if args[0]=='diagrams' and len(args)>=2 and args[1]=='born':
63 raise self.InvalidCmd("Processes generated do not have born diagrams.")
64
65 if args[0]=='diagrams' and len(args)>=3 and args[1] not in ['born','loop']:
66 raise self.InvalidCmd("Can only display born or loop diagrams, not %s."%args[1])
67
75
77 """ If no model is defined yet, make sure to load the right loop one """
78
79 if not self._curr_model:
80 pert_coupl_finder = re.compile(r"^(?P<proc>.+)\s*\[\s*((?P<option>\w+)"+
81 r"\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
82 pert_coupl = pert_coupl_finder.match(' '.join(args))
83 model_name = 'loop_sm'
84 if pert_coupl:
85 pert_coupls = pert_coupl.group("pertOrders")
86 if "QED" in pert_coupls:
87 model_name = 'loop_qcd_qed_sm'
88 self.do_import('model %s'%model_name)
89
90 mg_interface.MadGraphCmd.check_add(self,args)
91
100
101
103 """ Further check that only valid options are given to the MadLoop
104 default launcher."""
105
106 mg_interface.MadGraphCmd.check_launch(self,args,options)
107 if int(options.cluster) != 0 :
108 return self.InvalidCmd, 'MadLoop standalone runs cannot be '+\
109 'performed on a cluster.'
110
111 if int(options.multicore) != 0 :
112 logger.warning('MadLoop standalone can only run on a single core,'+\
113 ' so the -m option is ignored.')
114 options.multicore = '0'
115
116 if options.laststep != '' :
117 logger.warning('The -laststep option is only used for Madevent.'+\
118 'Ignoring this option')
119 options.multicore = ''
120
121 if options.interactive :
122 logger.warning('No interactive mode for MadLoop standalone runs.')
123 options.interactive = False
124
125 -class CheckLoopWeb(mg_interface.CheckValidForCmdWeb, CheckLoop):
127
129
131 "Complete the display command in the context of the Loop interface"
132
133 args = self.split_arg(line[0:begidx])
134
135 if len(args) == 2 and args[1] == 'diagrams':
136 return self.list_completion(text, ['born', 'loop'])
137 else:
138 return mg_interface.MadGraphCmd.complete_display(self, text, line,
139 begidx, endidx)
140
142
144 mg_interface.MadGraphCmd.help_display(self)
145 logger.info(" In ML5, after display diagrams, the user can add the option")
146 logger.info(" \"born\" or \"loop\" to display only the corresponding diagrams.")
147
150 """ An additional layer between MadGraphInterface and LoopInterface as well
151 as aMCatNLO interface, to put the common feature of these two here."""
152
154 """ Gives an integer more or less representing the difficulty of the process.
155 For now it is very basic and such that "difficult" processes start at
156 a value of about 35."""
157
158 def pdg_difficulty(pdg):
159 """ Gives a score from the pdg of a leg to state how it increases the
160 difficulty of the process """
161
162
163 part=self._curr_model.get_particle(pdg)
164 if abs(part.get_color())==1:
165 return 2
166 elif abs(part.get_color())==3:
167 return 3
168 elif abs(part.get_color())==6:
169 return 4
170 elif abs(part.get_color())==8:
171 return 6
172
173 score = 0
174 for leg in proc.get('legs'):
175 if isinstance(leg,base_objects.MultiLeg):
176 score += max([pdg_difficulty(id) for id in leg['ids']])
177
178 if len(leg['ids'])>1:
179 score += 1
180 else:
181 score += pdg_difficulty(leg.get('id'))
182
183
184 if proc['NLO_mode']=='virt':
185 score = score - 6
186
187 if proc['NLO_mode']=='real':
188 score = score - 6
189
190 if proc['NLO_mode']=='tree':
191 return 0
192 return score
193
194 - def do_set(self, line, log=True):
195 """Set the loop optimized output while correctly switching to the
196 Feynman gauge if necessary.
197 """
198
199 mg_interface.MadGraphCmd.do_set(self,line,log)
200
201 args = self.split_arg(line)
202 self.check_set(args)
203
204 if args[0] == 'gauge' and args[1] == 'unitary' and \
205 not self.options['gauge']=='unitary' and \
206 isinstance(self._curr_model,loop_base_objects.LoopModel) and \
207 not self._curr_model['perturbation_couplings'] in [[],['QCD']]:
208 if log: logger.warning('You will only be able to do tree level and QCD'+\
209 ' corrections in the unitary gauge.')
210
212 """ Check that the process or processDefinition describes a process that
213 ML5 can handle. Mode specifies who called the function,
214 typically ML5, ML5_check or aMCatNLO. This allows to relieve some limitation
215 depending on the functionality."""
216
217 tool = 'MadLoop' if mode.startswith('ML5') else 'aMC@NLO'
218
219
220 difficulty_threshold = 100
221
222 if not proc:
223 raise self.InvalidCmd("Empty or wrong format process, please try again.")
224
225
226
227 if self._curr_amps and self._curr_amps[0].get_ninitial() != \
228 proc.get_ninitial():
229 raise self.InvalidCmd("Can not mix processes with different number of initial states.")
230
231
232
233
234
235
236
237
238
239 if isinstance(proc, base_objects.ProcessDefinition) and mode=='ML5':
240 if proc.has_multiparticle_label():
241 raise self.InvalidCmd(
242 "When running ML5 standalone, multiparticle labels cannot be"+\
243 " employed.")
244
245 if proc['decay_chains']:
246 raise self.InvalidCmd(
247 "ML5 cannot yet decay a core process including loop corrections.")
248
249 if proc.are_decays_perturbed():
250 raise self.InvalidCmd(
251 "The processes defining the decay of the core process cannot"+\
252 " include loop corrections.")
253
254 if not proc['perturbation_couplings'] and mode.startswith('ML5'):
255 raise self.InvalidCmd(
256 "Please perform tree-level generations within default MG5 interface.")
257 if not 'real':
258 if not isinstance(self._curr_model,loop_base_objects.LoopModel) or \
259 not proc['perturbation_couplings']:
260 raise self.InvalidCmd(
261 "The current model does not allow for loop computations.")
262
263 miss_order = [ p_order for p_order in proc['perturbation_couplings'] \
264 if p_order not in self._curr_model.get('perturbation_couplings')]
265 if len(miss_order)>0 and not 'real' in mode:
266 raise self.InvalidCmd(
267 "Perturbation orders %s not among"%str(miss_order) + \
268 " the perturbation orders allowed for by the loop model.")
269
270 if proc['perturbation_couplings'] not in [[],['QCD']]:
271 raise self.InvalidCmd(
272 "The process perturbation coupling orders %s are beyond "+\
273 "tree level or only QCD corrections. MadLoop can only work"+\
274 " in the Feynman gauge for these. Please set the gauge to "+\
275 " Feynman and try again.")
276
277 proc_diff = self.rate_proc_difficulty(proc, mode)
278 logger.debug('Process difficulty estimation: %d'%proc_diff)
279 if proc_diff >= difficulty_threshold:
280 msg = """
281 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.
282 """
283 logger.warning(msg%proc.nice_string().replace('Process:','process'))
284
285 - def validate_model(self, loop_type='virtual',coupling_type=['QCD'], stop=True):
286 """ Upgrade the model sm to loop_sm if needed """
287
288
289
290 if isinstance(coupling_type,str):
291 coupling_type = [coupling_type,]
292
293 if coupling_type!= ['QCD'] and loop_type not in ['virtual','noborn']:
294 c = ' '.join(coupling_type)
295 raise self.InvalidCmd('MG5aMC can only handle QCD at NLO accuracy.\n We can however compute loop with [virt=%s].\n We can also compute cross-section for loop-induced processes with [noborn=%s]' % (c,c))
296
297
298 if not isinstance(self._curr_model,loop_base_objects.LoopModel) or \
299 self._curr_model['perturbation_couplings']==[] or \
300 any((coupl not in self._curr_model['perturbation_couplings']) \
301 for coupl in coupling_type):
302 if loop_type.startswith('real') or loop_type == 'LOonly':
303 if loop_type == 'real':
304 logger.info(\
305 "Beware that real corrections are generated from a tree-level model.")
306 if loop_type == 'real_init' and \
307 self._curr_model.get('name').split('-')[0]!='sm':
308 logger.info(\
309 "You are entering aMC@NLO with a model which does not "+\
310 " support loop corrections.")
311 else:
312 logger.info(\
313 "The current model %s does not allow to generate"%self._curr_model.get('name')+
314 " loop corrections of type %s."%str(coupling_type))
315 model_path = self._curr_model.get('modelpath')
316 model_name = self._curr_model.get('name')
317 if model_name.split('-')[0]=='loop_sm':
318 model_name = model_name[5:]
319 if model_name.split('-')[0]=='sm':
320
321 if not self.options['gauge']=='Feynman' and 'QED' in coupling_type:
322 logger.info('Switch to Feynman gauge because '+\
323 'model loop_qcd_qed_sm is restricted only to Feynman gauge.')
324 self._curr_model = None
325 mg_interface.MadGraphCmd.do_set(self,'gauge Feynman')
326 if coupling_type == ['QCD',]:
327 add_on = ''
328 elif coupling_type in [['QED'],['QCD','QED']]:
329 add_on = 'qcd_qed_'
330 else:
331 raise MadGraph5Error(
332 "The pertubation coupling cannot be '%s'"\
333 %str(coupling_type)+" in SM loop processes")
334
335 logger.info("MG5_aMC now loads 'loop_%s%s'."%(add_on,model_name))
336
337
338 self.history.move_to_last('generate')
339 last_command = self.history[-1]
340 self.exec_cmd(" import model loop_%s%s" % (add_on,model_name), precmd=True)
341 self.history.append(last_command)
342 elif stop:
343 raise self.InvalidCmd(
344 "The model %s cannot handle loop processes"%model_name)
345
346 if loop_type and not loop_type.startswith('real') and \
347 not self.options['gauge']=='Feynman' and \
348 not self._curr_model['perturbation_couplings'] in [[],['QCD']]:
349 if 1 in self._curr_model.get('gauge'):
350 logger.info("Setting gauge to Feynman in order to process all"+\
351 " possible loop computations available in the model.")
352 mg_interface.MadGraphCmd.do_set(self,'gauge Feynman')
353 else:
354 logger.warning("You will only be able to do tree level and QCD"+\
355 " corrections with this model because it does not support Feynman gauge.")
356
357 -class LoopInterface(CheckLoop, CompleteLoop, HelpLoop, CommonLoopInterface):
358
359 supported_ML_format = ['standalone', 'standalone_rw', 'matchbox']
360
361 - def __init__(self, mgme_dir = '', *completekey, **stdin):
362 """ Special init tasks for the Loop Interface """
363
364 mg_interface.MadGraphCmd.__init__(self, mgme_dir = '', *completekey, **stdin)
365 self.setup()
366
368 """ Special tasks when switching to this interface """
369
370
371
372
373
374
375 self.history.clean(remove_bef_last='import',
376 to_keep=['set','load','import', 'define'])
377
378 self._done_export=False
379 self._curr_amps = diagram_generation.AmplitudeList()
380 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
381 self._v4_export_formats = []
382 self._export_formats = [ 'matrix', 'standalone' ]
383 self._nlo_modes_for_completion = ['virt']
384 self.validate_model()
385
386
387
388 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools'))
389 if not os.path.isdir(os.path.join(self._cuttools_dir, 'src','cts')):
390 logger.warning(('Warning: Directory %s is not a valid CutTools directory.'+\
391 'Using default CutTools instead.') % \
392 self._cuttools_dir)
393 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools'))
394
395 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
396 if not os.path.isdir(self._iregi_dir):
397 logger.warning(('Warning: Directory %s is not a valid IREGI directory.'+\
398 'Using default IREGI instead.')%\
399 self._iregi_dir)
400 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
401
417
419 """Main commands:Initialize a new Template or reinitialize one"""
420
421 args = self.split_arg(line)
422
423 self.check_output(args)
424
425 noclean = '-noclean' in args
426 force = '-f' in args
427 nojpeg = '-nojpeg' in args
428 main_file_name = ""
429 try:
430 main_file_name = args[args.index('-name') + 1]
431 except Exception:
432 pass
433 line_options = dict(arg[2:].split('=') for arg in args if arg.startswith('--') and '=' in arg)
434
435
436
437 aloha_original_quad_mode = aloha.mp_precision
438 aloha.mp_precision = True
439
440 if self._export_format not in self.supported_ML_format:
441 raise self.InvalidCmd('ML5 only support "%s" as export format.' % \
442 ''.join(self.supported_ML_format))
443
444 if not os.path.isdir(self._export_dir) and self._export_format in ['matrix']:
445 raise self.InvalidCmd('Specified export directory %s does not exist.'\
446 %str(self._export_dir))
447
448 if not force and not noclean and os.path.isdir(self._export_dir)\
449 and self._export_format.startswith('standalone'):
450
451 logger.info('INFO: directory %s already exists.' % self._export_dir)
452 logger.info('If you continue this directory will be cleaned')
453 answer = self.ask('Do you want to continue?', 'y', ['y','n'])
454 if answer != 'y':
455 raise self.InvalidCmd('Stopped by user request')
456 else:
457 try:
458 shutil.rmtree(self._export_dir)
459 except OSError:
460 raise self.InvalidCmd('Could not remove directory %s.'\
461 %str(self._export_dir))
462
463 if self._export_format.startswith('standalone'):
464 output_type = 'madloop'
465 elif self._export_format == 'matchbox':
466 output_type = 'madloop_matchbox'
467
468 self._curr_exporter = export_v4.ExportV4Factory(self, \
469 noclean, output_type=output_type, group_subprocesses=False,
470 cmd_options=line_options)
471
472 if self._export_format in ['standalone', 'matchbox']:
473 self._curr_exporter.copy_template(self._curr_model)
474
475 if self._export_format == "standalone_rw":
476 self._export_format = "standalone"
477 self._curr_exporter.copy_template(self._curr_model)
478 self._export_format = "standalone_rw"
479
480
481 self._done_export = False
482
483
484 self.ML5export(nojpeg, main_file_name)
485
486
487 self.ML5finalize(nojpeg)
488
489
490 self._done_export = (self._export_dir, self._export_format)
491
492
493 self._export_dir = None
494
495
496 aloha.mp_precision = aloha_original_quad_mode
497
498
500 """Code to install the reduction library if needed"""
501
502 opt = self.options
503
504
505 if not force and ((opt['ninja'] is None) or (os.path.isfile(pjoin(MG5DIR, opt['ninja'],'libninja.a')))):
506 return
507
508
509 if 'test_manager.py' in sys.argv[0]:
510 from unittest.case import SkipTest
511 raise SkipTest
512
513 logger.info("First output using loop matrix-elements has been detected. Now asking for loop reduction:", '$MG:BOLD')
514 to_install = self.ask('install', '0', ask_class=AskLoopInstaller, timeout=300,
515 path_msg=' ')
516
517
518 for key, value in to_install.items():
519 if key in ['cuttools', 'iregi']:
520 if os.path.sep not in value:
521 continue
522 import madgraph.iolibs.files as files
523 if key == 'cuttools':
524 if os.path.exists(pjoin(value, 'includects')):
525 path = pjoin(value, 'includects')
526 elif os.path.exists(pjoin(value, 'CutTools','includects')):
527 path = pjoin(value, 'CutTools', 'includects')
528 elif os.path.exists(pjoin(value, 'vendor','CutTools','includects')):
529 path = pjoin(value, 'vendor','CutTools', 'includects')
530 else:
531 logger.warning('invalid path for cuttools import')
532 continue
533
534 target = pjoin(MG5DIR,'vendor','CutTools','includects')
535 if not os.path.exists(target):
536 os.mkdir(target)
537 files.cp(pjoin(path,'libcts.a'), target)
538 files.cp(pjoin(path,'mpmodule.mod'), target, log=True)
539 if os.path.exists(pjoin(path,'compiler_version.log')):
540 files.cp(pjoin(path,'compiler_version.log'), target)
541
542 if key == 'iregi':
543 if os.path.exists(pjoin(value, 'src','IREGI4ML5_interface.f90')):
544 path = pjoin(value, 'src')
545 elif os.path.exists(pjoin(value, 'IREGI','src','IREGI4ML5_interface.f90')):
546 path = pjoin(value, 'IREGI', 'src')
547 elif os.path.exists(pjoin(value, 'vendor','IREGI','src','IREGI4ML5_interface.f90')):
548 path = pjoin(value, 'vendor', 'IREGI', 'src')
549 else:
550 logger.warning('invalid path for IREGI import')
551 continue
552
553 target = pjoin(MG5DIR,'vendor','IREGI','src')
554 files.cp(pjoin(path,'libiregi.a'), target, log=True)
555 elif value == 'local':
556
557 logger.info(
558 """MG5aMC will now install the loop reduction tool '%(p)s' from the local offline installer.
559 Use the command 'install $(p)s' if you want to update to the latest online version.
560 This installation can take some time but only needs to be performed once.""" %{'p': key},'$MG:color:GREEN')
561 additional_options = ['--ninja_tarball=%s'%pjoin(MG5DIR,'vendor','%s.tar.gz' % key)]
562 if key == 'ninja':
563 additional_options.append('--oneloop_tarball=%s'%pjoin(MG5DIR,'vendor','oneloop.tar.gz'))
564
565 try:
566 self.do_install(key,paths={'HEPToolsInstaller':
567 pjoin(MG5DIR,'vendor','OfflineHEPToolsInstaller.tar.gz')},
568 additional_options=additional_options)
569 except self.InvalidCmd:
570 logger.warning(
571 """The offline installation of %(p)s was unsuccessful, and MG5aMC disabled it.
572 In the future, if you want to reactivate Ninja, you can do so by re-attempting
573 its online installation with the command 'install %(p)s' or install it on your
574 own and set the path to its library in the MG5aMC option '%(p)s'.""" % {'p': key})
575 self.exec_cmd("set %s ''" % key)
576 self.exec_cmd('save options %s' % key)
577
578
579 elif value == 'install':
580 prog = {'golem': 'Golem95'}
581 if key in prog:
582 self.exec_cmd('install %s' % prog[key])
583 else:
584 self.exec_cmd('install %s' % key)
585
586 elif value == 'off':
587 self.exec_cmd("set %s ''" % key)
588 self.exec_cmd('save options %s' % key)
589 else:
590 self.exec_cmd("set %s %s" % (key,value))
591 self.exec_cmd('save options %s' % key)
592
593
594
595
596 - def ML5export(self, nojpeg = False, main_file_name = ""):
634
635
636 ndiags, cpu_time = generate_matrix_elements(self)
637
638 calls = 0
639
640 path = self._export_dir
641 if self._export_format in self.supported_ML_format:
642 path = pjoin(path, 'SubProcesses')
643
644 cpu_time1 = time.time()
645
646
647 matrix_elements = \
648 self._curr_matrix_elements.get_matrix_elements()
649
650
651 if self._export_format in self.supported_ML_format:
652 for unique_id, me in enumerate(matrix_elements):
653 calls = calls + \
654 self._curr_exporter.generate_subprocess_directory(\
655 me, self._curr_helas_model)
656
657
658
659
660 if self.options['loop_optimized_output'] and len(matrix_elements)>1:
661 max_lwfspins = [m.get_max_loop_particle_spin() for m in \
662 matrix_elements]
663 max_loop_vert_ranks = [me.get_max_loop_vertex_rank() for me in \
664 matrix_elements]
665 if len(set(max_lwfspins))>1 or len(set(max_loop_vert_ranks))>1:
666 self._curr_exporter.fix_coef_specs(max(max_lwfspins),\
667 max(max_loop_vert_ranks))
668
669
670 if self._export_format == 'matrix':
671 for me in matrix_elements:
672 filename = pjoin(path, 'matrix_' + \
673 me.get('processes')[0].shell_string() + ".f")
674 if os.path.isfile(filename):
675 logger.warning("Overwriting existing file %s" % filename)
676 else:
677 logger.info("Creating new file %s" % filename)
678 calls = calls + self._curr_exporter.write_matrix_element_v4(\
679 writers.FortranWriter(filename),\
680 me, self._curr_helas_model)
681
682 cpu_time2 = time.time() - cpu_time1
683
684 logger.info(("Generated helas calls for %d subprocesses " + \
685 "(%d diagrams) in %0.3f s") % \
686 (len(matrix_elements),
687 ndiags, cpu_time))
688
689 if calls:
690 if "cpu_time2" in locals():
691 logger.info("Wrote files for %d OPP calls in %0.3f s" % \
692 (calls, cpu_time2))
693 else:
694 logger.info("Wrote files for %d OPP calls" % \
695 (calls))
696
697
698
699
700 self._curr_amps = diagram_generation.AmplitudeList(\
701 [me.get('base_amplitude') for me in \
702 matrix_elements])
703
742
744 """Main commands: Check that the type of launch is fine before proceeding with the
745 mother function. """
746
747 args = self.split_arg(line)
748
749 (options, args) = mg_interface._launch_parser.parse_args(args)
750
751 self.check_launch(args, options)
752
753 if not args[0].startswith('standalone'):
754 raise self.InvalidCmd('ML5 can only launch standalone runs.')
755
756 start_cwd = os.getcwd()
757 options = options.__dict__
758
759
760 ext_program = launch_ext.MadLoopLauncher(self, args[1], \
761 options=self.options, **options)
762 ext_program.run()
763 os.chdir(start_cwd)
764
766 """Check a given process or set of processes"""
767
768 argss = self.split_arg(line, *args,**opt)
769
770 perturbation_couplings_pattern = \
771 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
772 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
773 perturbation_couplings=""
774 if perturbation_couplings_re:
775 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
776 QED_found=re.search("QED",perturbation_couplings)
777 if QED_found:
778 self.validate_model(coupling_type='QED')
779 else:
780 self.validate_model()
781
782 param_card = self.check_check(argss)
783 reuse = argss[1]=="-reuse"
784 argss = argss[:1]+argss[2:]
785
786
787 if argss[0] in ['stability', 'profile']:
788 stab_statistics = int(argss[1])
789 argss = argss[:1]+argss[2:]
790
791 i=-1
792 while argss[i].startswith('--'):
793 i=i-1
794
795 proc = " ".join(argss[1:i+1])
796 myprocdef = self.extract_process(proc)
797 self.proc_validity(myprocdef,'ML5_check_cms' if argss[0]=='cms' else \
798 'ML5_check')
799
800 return mg_interface.MadGraphCmd.do_check(self, line, *args,**opt)
801
802 - def do_add(self, line, *args,**opt):
803 """Generate an amplitude for a given process and add to
804 existing amplitudes
805 """
806 args = self.split_arg(line)
807
808 self.check_add(args)
809 perturbation_couplings_pattern = \
810 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
811 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
812 perturbation_couplings=""
813 if perturbation_couplings_re:
814 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
815 QED_found=re.search('QED',perturbation_couplings)
816 if QED_found:
817 self.validate_model(coupling_type='QED')
818 else:
819 self.validate_model()
820
821 loop_filter=None
822 if args[0] == 'process':
823
824
825 for arg in args:
826 if arg.startswith('--loop_filter='):
827 start = arg[14]
828 end = arg[-1]
829 if start == end and start in ["'", '"']:
830 loop_filter = arg[15:-1]
831 else:
832 loop_filter = arg[14:]
833 if not isinstance(self, extended_cmd.CmdShell):
834 raise self.InvalidCmd("loop_filter is not allowed in web mode")
835 args = [a for a in args if not a.startswith('--loop_filter=')]
836
837
838 line = ' '.join(args[1:])
839
840
841 if not self._generate_info:
842 self._generate_info = line
843
844
845 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
846
847
848 myprocdef = self.extract_process(line)
849
850 if myprocdef.has_multiparticle_label():
851
852 succes, failed = 0, 0
853 for base_proc in myprocdef:
854 command = "add process %s" % base_proc.nice_string(prefix=False, print_weighted=True)
855 if '@' not in command:
856 command += ' @%s' % base_proc.get('id')
857 try:
858 self.exec_cmd(command)
859 succes += 1
860 except Exception:
861 failed +=1
862 logger.info("%s/%s processes succeeded" % (succes, failed+succes))
863 if succes == 0:
864 raise
865 else:
866 return
867
868
869
870
871
872
873
874
875
876
877
878 self.proc_validity(myprocdef,'ML5')
879
880 cpu_time1 = time.time()
881
882
883 multiprocessclass=None
884 if myprocdef['perturbation_couplings']!=[]:
885 multiprocessclass=loop_diagram_generation.LoopMultiProcess
886 else:
887 multiprocessclass=diagram_generation.MultiProcess
888
889 myproc = multiprocessclass(myprocdef, collect_mirror_procs = False,
890 ignore_six_quark_processes = False,
891 loop_filter = loop_filter)
892
893 for amp in myproc.get('amplitudes'):
894 if amp not in self._curr_amps:
895 self._curr_amps.append(amp)
896 else:
897 warning = "Warning: Already in processes:\n%s" % \
898 amp.nice_string_processes()
899 logger.warning(warning)
900
901
902 self._done_export = False
903
904 cpu_time2 = time.time()
905
906 ndiags = sum([len(amp.get('loop_diagrams')) for \
907 amp in myproc.get('amplitudes')])
908 logger.info("Process generated in %0.3f s" % \
909 (cpu_time2 - cpu_time1))
910
913
916
917 local_installer = ['ninja', 'collier']
918 required = ['cuttools', 'iregi']
919 order = ['cuttools', 'iregi', 'ninja', 'collier', 'golem']
920 bypassed = ['pjfry']
921
922 @property
925
926
927 - def __init__(self, question, *args, **opts):
928
929 import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
930 try:
931 response=six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/F1.html', timeout=3)
932 self.online=True
933 except six.moves.urllib.error.URLError as err:
934 self.online=False
935
936 self.code = {'ninja': 'install',
937 'collier': 'install',
938 'golem': 'off',
939 'cuttools': 'required',
940 'iregi': 'required'}
941 if not self.online:
942 self.code['ninja'] = 'local'
943 self.code['collier'] = 'local'
944 self.code['golem'] = 'fail'
945 if not misc.which('cmake'):
946 self.code['collier'] = 'off'
947
948
949 if 'mother_interface' in opts:
950 mother = opts['mother_interface']
951 if 'heptools_install_dir' in mother.options:
952 install_dir1 = mother.options['heptools_install_dir']
953 install_dir2 = mother.options['heptools_install_dir']
954 if os.path.exists(pjoin(install_dir1, 'CutTools')):
955 self.code['cuttools'] = mother.options['heptools_install_dir']
956 if os.path.exists(pjoin(install_dir1, 'IREGI')):
957 self.code['iregi'] = mother.options['heptools_install_dir']
958 else:
959 install_dir1 = pjoin(MG5DIR, 'HEPTools')
960 install_dir2 = MG5DIR
961 if os.path.exists(pjoin(install_dir1, 'collier')):
962 self.code['collier'] = pjoin(install_dir1, 'collier')
963 if os.path.exists(pjoin(install_dir2, 'golem95')):
964 self.code['glem'] = pjoin(install_dir2, 'golem95')
965 if os.path.exists(pjoin(install_dir1, 'ninja')):
966 self.code['ninja'] = pjoin(install_dir2, 'ninja','lib')
967
968
969 question, allowed_answer = self.create_question(first=True)
970
971 opts['allow_arg'] = allowed_answer
972
973 cmd.OneLinePathCompletion.__init__(self, question, *args, **opts)
974
975
977 """ """
978
979 question = "For loop computations, MadLoop requires dedicated tools to"+\
980 " perform the reduction of loop Feynman diagrams using OPP-based and/or TIR approaches.\n"+\
981 "\nWhich one do you want to install? (this needs to be done only once)\n"
982
983 allowed_answer = set(['0','done'])
984
985 descript = {'cuttools': ['cuttools','(OPP)','[0711.3596]'],
986 'iregi': ['iregi','(TIR)','[1405.0301]'],
987 'ninja': ['ninja','(OPP)','[1403.1229]'],
988 'golem': ['golem','(TIR)','[0807.0605]'],
989 'collier': ['collier','(TIR)','[1604.06792]']}
990
991
992 status = {'off': '%(start_red)sdo not install%(stop)s',
993 'install': '%(start_green)swill be installed %(stop)s',
994 'local': '%(start_green)swill be installed %(stop)s(offline installation from local repository)',
995 'fail': 'not available without internet connection',
996 'required': 'will be installed (required)'}
997
998 for i,key in enumerate(self.order,1):
999 if key in self.bypassed and self.code[key] == 'off':
1000 continue
1001 if os.path.sep not in self.code[key]:
1002 question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s%s\n' % \
1003 tuple([i,]+descript[key]+[status[self.code[key]],]+\
1004 ['(recommended)' if key in ['ninja','collier'] and self.code[key] in ['install'] else ''])
1005 else:
1006 question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s\n' % tuple([i,]+descript[key]+[self.code[key],])
1007 if key in self.required:
1008 continue
1009 allowed_answer.update([str(i), key])
1010 if key in self.local_installer:
1011 allowed_answer.update(['key=local','key=off'])
1012 if self.online:
1013 allowed_answer.update(['key=on','key=install', 'key=off'])
1014
1015 question += "You can:\n -> hit 'enter' to proceed\n -> type a number to cycle its options\n -> enter the following command:\n"+\
1016 ' %(start_blue)s{tool_name}%(stop)s [%(start_blue)sinstall%(stop)s|%(start_blue)snoinstall%(stop)s|'+\
1017 '%(start_blue)s{prefixed_installation_path}%(stop)s]\n'
1018 if first:
1019 question += '\n%(start_bold)s%(start_red)sIf you are unsure about what this question means, just type enter to proceed. %(stop)s'
1020
1021 question = question % {'start_green' : '\033[92m',
1022 'start_red' : '\033[91m',
1023 'start_blue' : '\033[34m',
1024 'stop': '\033[0m',
1025 'start_bold':'\033[1m',
1026 }
1027 return question, allowed_answer
1028
1030 """Default action if line is not recognized"""
1031
1032 line = line.strip()
1033 args = line.split()
1034
1035 if line in ['0', 'done','','EOF']:
1036 self.value = 'done'
1037 return self.answer
1038 self.value = 'repeat'
1039 if args:
1040 if len(args) ==1 and '=' in args[0]:
1041 args = args[0].split('=')
1042 args[0] = args[0].lower()
1043 if len(args) == 1:
1044
1045 if args[0].isdigit():
1046 if len(self.order) < int(args[0]):
1047 logger.warning('Invalid integer %s. Please Retry' % args[0])
1048 return
1049 args[0] = self.order[int(args[0])-1]
1050 key = args[0]
1051 if key in self.code:
1052 if self.code[key] in ['off']:
1053 if self.online:
1054 self.code[key] = 'install'
1055 elif key in self.local_installer:
1056 self.code[key] = 'local'
1057 elif self.code[key] == 'install':
1058 if key in self.local_installer:
1059 self.code[key] = 'local'
1060 else:
1061 self.code[key] = 'off'
1062 elif self.code[key] == 'local':
1063 self.code[key] = 'off'
1064 else:
1065 logger.warning('Unknown entry \'%s\'. Please retry' % key)
1066 return
1067 elif len(args) == 2:
1068 key = args[0]
1069 if key not in self.code:
1070 logger.warning('unknown %s type of entry. Bypass command.')
1071 return
1072 if os.path.sep not in args[1]:
1073 value = args[1].lower()
1074 if value in ['off', 'not','noinstall']:
1075 self.code[key] = 'off'
1076 elif value in ['on', 'install']:
1077 if self.online:
1078 self.code[key] = 'install'
1079 elif key in self.local_installer:
1080 self.code[key] = 'local'
1081 else:
1082 logger.warning('offline installer not available for %s', key)
1083 self.code[key] = 'off'
1084 elif value in ['local']:
1085 if key in self.local_installer:
1086 self.code[key] = 'local'
1087 else:
1088 logger.warning('offline installer not available for %s', key)
1089 self.code[key] = 'off'
1090 else:
1091 self.code[key] = args[1]
1092 else:
1093 self.value = 0
1094 self.question,self.allow_arg = self.create_question()
1095 return self.answer
1096
1098
1099 if line.startswith('='):
1100 line = line[1:]
1101 return self.default('%s %s' % (name,line))
1102
1103
1104 do_ninja = lambda self,line : self.apply_name('ninja', line)
1105 do_collier = lambda self,line : self.apply_name('collier', line)
1106 do_golem = lambda self,line : self.apply_name('golem', line)
1107 do_cuttools = lambda self,line : self.apply_name('cuttools', line)
1108 do_iregi = lambda self,line : self.apply_name('iregi', line)
1109
1110
1111 - def complete_prog(self, text, line, begidx, endidx, formatting=True):
1112
1113 if os.path.sep in line:
1114 args = line[0:begidx].split()
1115 if args[-1].endswith(os.path.sep):
1116 return self.path_completion(text,
1117 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
1118 only_dirs = True)
1119 else:
1120 return self.path_completion(text, '.', only_dirs = True)
1121 else:
1122 return self.list_completion(text, ['install', 'noinstall', 'local'], line)
1123
1124 complete_ninja = complete_prog
1125 complete_collier = complete_prog
1126 complete_golem = complete_prog
1127 complete_cuttools = complete_prog
1128 complete_iregi = complete_prog
1129