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