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