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
294
295
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
807 args = self.split_arg(line)
808
809 self.check_add(args)
810 perturbation_couplings_pattern = \
811 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
812 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
813 perturbation_couplings=""
814 if perturbation_couplings_re:
815 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
816 QED_found=re.search('QED',perturbation_couplings)
817 if QED_found:
818 self.validate_model(coupling_type='QED')
819 else:
820 self.validate_model()
821
822 loop_filter=None
823 if args[0] == 'process':
824
825
826 for arg in args:
827 if arg.startswith('--loop_filter='):
828 start = arg[14]
829 end = arg[-1]
830 if start == end and start in ["'", '"']:
831 loop_filter = arg[15:-1]
832 else:
833 loop_filter = arg[14:]
834 if not isinstance(self, extended_cmd.CmdShell):
835 raise self.InvalidCmd("loop_filter is not allowed in web mode")
836 args = [a for a in args if not a.startswith('--loop_filter=')]
837
838
839 line = ' '.join(args[1:])
840
841
842 if not self._generate_info:
843 self._generate_info = line
844
845
846 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
847
848
849 myprocdef = self.extract_process(line)
850
851 if myprocdef.has_multiparticle_label():
852
853 succes, failed = 0, 0
854 for base_proc in myprocdef:
855 command = "add process %s" % base_proc.nice_string(prefix=False, print_weighted=True)
856 if '@' not in command:
857 command += ' @%s' % base_proc.get('id')
858 try:
859 self.exec_cmd(command)
860 succes += 1
861 except Exception:
862 failed +=1
863 logger.info("%s/%s processes succeeded" % (succes, failed+succes))
864 if succes == 0:
865 raise
866 else:
867 return
868
869
870
871
872
873
874
875
876
877
878
879 self.proc_validity(myprocdef,'ML5')
880
881 cpu_time1 = time.time()
882
883
884 multiprocessclass=None
885 if myprocdef['perturbation_couplings']!=[]:
886 multiprocessclass=loop_diagram_generation.LoopMultiProcess
887 else:
888 multiprocessclass=diagram_generation.MultiProcess
889
890 myproc = multiprocessclass(myprocdef, collect_mirror_procs = False,
891 ignore_six_quark_processes = False,
892 loop_filter = loop_filter)
893
894 for amp in myproc.get('amplitudes'):
895 if amp not in self._curr_amps:
896 self._curr_amps.append(amp)
897 else:
898 warning = "Warning: Already in processes:\n%s" % \
899 amp.nice_string_processes()
900 logger.warning(warning)
901
902
903 self._done_export = False
904
905 cpu_time2 = time.time()
906
907 ndiags = sum([len(amp.get('loop_diagrams')) for \
908 amp in myproc.get('amplitudes')])
909 logger.info("Process generated in %0.3f s" % \
910 (cpu_time2 - cpu_time1))
911
915
918
919 local_installer = ['ninja', 'collier']
920 required = ['cuttools', 'iregi']
921 order = ['cuttools', 'iregi', 'ninja', 'collier', 'golem']
922 bypassed = ['pjfry']
923
924 @property
927
928
929 - def __init__(self, question, *args, **opts):
930
931 import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
932 try:
933 response=six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/F1.html', timeout=3)
934 self.online=True
935 except six.moves.urllib.error.URLError as err:
936 self.online=False
937
938 self.code = {'ninja': 'install',
939 'collier': 'install',
940 'golem': 'off',
941 'cuttools': 'required',
942 'iregi': 'required'}
943 if not self.online:
944 self.code['ninja'] = 'local'
945 self.code['collier'] = 'local'
946 self.code['golem'] = 'fail'
947 if not misc.which('cmake'):
948 self.code['collier'] = 'off'
949
950
951 if 'mother_interface' in opts:
952 mother = opts['mother_interface']
953 if 'heptools_install_dir' in mother.options:
954 install_dir1 = mother.options['heptools_install_dir']
955 install_dir2 = mother.options['heptools_install_dir']
956 if os.path.exists(pjoin(install_dir1, 'CutTools')):
957 self.code['cuttools'] = mother.options['heptools_install_dir']
958 if os.path.exists(pjoin(install_dir1, 'IREGI')):
959 self.code['iregi'] = mother.options['heptools_install_dir']
960 else:
961 install_dir1 = pjoin(MG5DIR, 'HEPTools')
962 install_dir2 = MG5DIR
963 if os.path.exists(pjoin(install_dir1, 'collier')):
964 self.code['collier'] = pjoin(install_dir1, 'collier')
965 if os.path.exists(pjoin(install_dir2, 'golem95')):
966 self.code['glem'] = pjoin(install_dir2, 'golem95')
967 if os.path.exists(pjoin(install_dir1, 'ninja')):
968 self.code['ninja'] = pjoin(install_dir2, 'ninja','lib')
969
970
971 question, allowed_answer = self.create_question(first=True)
972
973 opts['allow_arg'] = allowed_answer
974
975 cmd.OneLinePathCompletion.__init__(self, question, *args, **opts)
976
977
979 """ """
980
981 question = "For loop computations, MadLoop requires dedicated tools to"+\
982 " perform the reduction of loop Feynman diagrams using OPP-based and/or TIR approaches.\n"+\
983 "\nWhich one do you want to install? (this needs to be done only once)\n"
984
985 allowed_answer = set(['0','done'])
986
987 descript = {'cuttools': ['cuttools','(OPP)','[0711.3596]'],
988 'iregi': ['iregi','(TIR)','[1405.0301]'],
989 'ninja': ['ninja','(OPP)','[1403.1229]'],
990 'golem': ['golem','(TIR)','[0807.0605]'],
991 'collier': ['collier','(TIR)','[1604.06792]']}
992
993
994 status = {'off': '%(start_red)sdo not install%(stop)s',
995 'install': '%(start_green)swill be installed %(stop)s',
996 'local': '%(start_green)swill be installed %(stop)s(offline installation from local repository)',
997 'fail': 'not available without internet connection',
998 'required': 'will be installed (required)'}
999
1000 for i,key in enumerate(self.order,1):
1001 if key in self.bypassed and self.code[key] == 'off':
1002 continue
1003 if os.path.sep not in self.code[key]:
1004 question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s%s\n' % \
1005 tuple([i,]+descript[key]+[status[self.code[key]],]+\
1006 ['(recommended)' if key in ['ninja','collier'] and self.code[key] in ['install'] else ''])
1007 else:
1008 question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s\n' % tuple([i,]+descript[key]+[self.code[key],])
1009 if key in self.required:
1010 continue
1011 allowed_answer.update([str(i), key])
1012 if key in self.local_installer:
1013 allowed_answer.update(['key=local','key=off'])
1014 if self.online:
1015 allowed_answer.update(['key=on','key=install', 'key=off'])
1016
1017 question += "You can:\n -> hit 'enter' to proceed\n -> type a number to cycle its options\n -> enter the following command:\n"+\
1018 ' %(start_blue)s{tool_name}%(stop)s [%(start_blue)sinstall%(stop)s|%(start_blue)snoinstall%(stop)s|'+\
1019 '%(start_blue)s{prefixed_installation_path}%(stop)s]\n'
1020 if first:
1021 question += '\n%(start_bold)s%(start_red)sIf you are unsure about what this question means, just type enter to proceed. %(stop)s'
1022
1023 question = question % {'start_green' : '\033[92m',
1024 'start_red' : '\033[91m',
1025 'start_blue' : '\033[34m',
1026 'stop': '\033[0m',
1027 'start_bold':'\033[1m',
1028 }
1029 return question, allowed_answer
1030
1032 """Default action if line is not recognized"""
1033
1034 line = line.strip()
1035 args = line.split()
1036
1037 if line in ['0', 'done','','EOF']:
1038 self.value = 'done'
1039 return self.answer
1040 self.value = 'repeat'
1041 if args:
1042 if len(args) ==1 and '=' in args[0]:
1043 args = args[0].split('=')
1044 args[0] = args[0].lower()
1045 if len(args) == 1:
1046
1047 if args[0].isdigit():
1048 if len(self.order) < int(args[0]):
1049 logger.warning('Invalid integer %s. Please Retry' % args[0])
1050 return
1051 args[0] = self.order[int(args[0])-1]
1052 key = args[0]
1053 if key in self.code:
1054 if self.code[key] in ['off']:
1055 if self.online:
1056 self.code[key] = 'install'
1057 elif key in self.local_installer:
1058 self.code[key] = 'local'
1059 elif self.code[key] == 'install':
1060 if key in self.local_installer:
1061 self.code[key] = 'local'
1062 else:
1063 self.code[key] = 'off'
1064 elif self.code[key] == 'local':
1065 self.code[key] = 'off'
1066 else:
1067 logger.warning('Unknown entry \'%s\'. Please retry' % key)
1068 return
1069 elif len(args) == 2:
1070 key = args[0]
1071 if key not in self.code:
1072 logger.warning('unknown %s type of entry. Bypass command.')
1073 return
1074 if os.path.sep not in args[1]:
1075 value = args[1].lower()
1076 if value in ['off', 'not','noinstall']:
1077 self.code[key] = 'off'
1078 elif value in ['on', 'install']:
1079 if self.online:
1080 self.code[key] = 'install'
1081 elif key in self.local_installer:
1082 self.code[key] = 'local'
1083 else:
1084 logger.warning('offline installer not available for %s', key)
1085 self.code[key] = 'off'
1086 elif value in ['local']:
1087 if key in self.local_installer:
1088 self.code[key] = 'local'
1089 else:
1090 logger.warning('offline installer not available for %s', key)
1091 self.code[key] = 'off'
1092 else:
1093 self.code[key] = args[1]
1094 else:
1095 self.value = 0
1096 self.question,self.allow_arg = self.create_question()
1097 return self.answer
1098
1100
1101 if line.startswith('='):
1102 line = line[1:]
1103 return self.default('%s %s' % (name,line))
1104
1105
1106 do_ninja = lambda self,line : self.apply_name('ninja', line)
1107 do_collier = lambda self,line : self.apply_name('collier', line)
1108 do_golem = lambda self,line : self.apply_name('golem', line)
1109 do_cuttools = lambda self,line : self.apply_name('cuttools', line)
1110 do_iregi = lambda self,line : self.apply_name('iregi', line)
1111
1112
1113 - def complete_prog(self, text, line, begidx, endidx, formatting=True):
1114
1115 if os.path.sep in line:
1116 args = line[0:begidx].split()
1117 if args[-1].endswith(os.path.sep):
1118 return self.path_completion(text,
1119 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
1120 only_dirs = True)
1121 else:
1122 return self.path_completion(text, '.', only_dirs = True)
1123 else:
1124 return self.list_completion(text, ['install', 'noinstall', 'local'], line)
1125
1126 complete_ninja = complete_prog
1127 complete_collier = complete_prog
1128 complete_golem = complete_prog
1129 complete_cuttools = complete_prog
1130 complete_iregi = complete_prog
1131