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
432
433
434 aloha_original_quad_mode = aloha.mp_precision
435 aloha.mp_precision = True
436
437 if self._export_format not in self.supported_ML_format:
438 raise self.InvalidCmd('ML5 only support "%s" as export format.' % \
439 ''.join(self.supported_ML_format))
440
441 if not os.path.isdir(self._export_dir) and self._export_format in ['matrix']:
442 raise self.InvalidCmd('Specified export directory %s does not exist.'\
443 %str(self._export_dir))
444
445 if not force and not noclean and os.path.isdir(self._export_dir)\
446 and self._export_format.startswith('standalone'):
447
448 logger.info('INFO: directory %s already exists.' % self._export_dir)
449 logger.info('If you continue this directory will be cleaned')
450 answer = self.ask('Do you want to continue?', 'y', ['y','n'])
451 if answer != 'y':
452 raise self.InvalidCmd('Stopped by user request')
453 else:
454 try:
455 shutil.rmtree(self._export_dir)
456 except OSError:
457 raise self.InvalidCmd('Could not remove directory %s.'\
458 %str(self._export_dir))
459
460 if self._export_format.startswith('standalone'):
461 output_type = 'madloop'
462 elif self._export_format == 'matchbox':
463 output_type = 'madloop_matchbox'
464
465 self._curr_exporter = export_v4.ExportV4Factory(self, \
466 noclean, output_type=output_type, group_subprocesses=False)
467
468 if self._export_format in ['standalone', 'matchbox']:
469 self._curr_exporter.copy_template(self._curr_model)
470
471 if self._export_format == "standalone_rw":
472 self._export_format = "standalone"
473 self._curr_exporter.copy_template(self._curr_model)
474 self._export_format = "standalone_rw"
475
476
477 self._done_export = False
478
479
480 self.ML5export(nojpeg, main_file_name)
481
482
483 self.ML5finalize(nojpeg)
484
485
486 self._done_export = (self._export_dir, self._export_format)
487
488
489 self._export_dir = None
490
491
492 aloha.mp_precision = aloha_original_quad_mode
493
494
496 """Code to install the reduction library if needed"""
497
498 opt = self.options
499
500
501 if (opt['ninja'] is None) or (os.path.isfile(pjoin(MG5DIR, opt['ninja'],'libninja.a'))):
502 return
503
504 logger.info("First output using loop matrix-elements has been detected. Now asking for loop reduction:", '$MG:color:BLACK')
505 to_install = self.ask('install', '0', ask_class=AskLoopInstaller, timeout=300,
506 path_msg=' ')
507
508
509 for key, value in to_install.items():
510 if key in ['cuttools', 'iregi']:
511 if os.path.sep not in value:
512 continue
513 import madgraph.iolibs.files as files
514 if key == 'cuttools':
515 if os.path.exists(pjoin(value, 'includects')):
516 path = pjoin(value, 'includects')
517 elif os.path.exists(pjoin(value, 'CutTools','includects')):
518 path = pjoin(value, 'CutTools', 'includects')
519 elif os.path.exists(pjoin(value, 'vendor','CutTools','includects')):
520 path = pjoin(value, 'vendor','CutTools', 'includects')
521 else:
522 logger.warning('invalid path for cuttools import')
523 continue
524
525 target = pjoin(MG5DIR,'vendor','CutTools','includects')
526 if not os.path.exists(target):
527 os.mkdir(target)
528 files.cp(pjoin(path,'libcts.a'), target)
529 files.cp(pjoin(path,'mpmodule.mod'), target, log=True)
530 if os.path.exists(pjoin(path,'compiler_version.log')):
531 files.cp(pjoin(path,'compiler_version.log'), target)
532
533 if key == 'iregi':
534 if os.path.exists(pjoin(value, 'src','IREGI4ML5_interface.f90')):
535 path = pjoin(value, 'src')
536 elif os.path.exists(pjoin(value, 'IREGI','src','IREGI4ML5_interface.f90')):
537 path = pjoin(value, 'IREGI', 'src')
538 elif os.path.exists(pjoin(value, 'vendor','IREGI','src','IREGI4ML5_interface.f90')):
539 path = pjoin(value, 'vendor', 'IREGI', 'src')
540 else:
541 logger.warning('invalid path for IREGI import')
542 continue
543
544 target = pjoin(MG5DIR,'vendor','IREGI','src')
545 files.cp(pjoin(path,'libiregi.a'), target, log=True)
546 elif value == 'local':
547
548 logger.info(
549 """MG5aMC will now install the loop reduction tool '%(p)s' from the local offline installer.
550 Use the command 'install $(p)s' if you want to update to the latest online version.
551 This installation can take some time but only needs to be performed once.""" %{'p': key},'$MG:color:GREEN')
552 additional_options = ['--ninja_tarball=%s'%pjoin(MG5DIR,'vendor','%s.tar.gz' % key)]
553 if key == 'ninja':
554 additional_options.append('--oneloop_tarball=%s'%pjoin(MG5DIR,'vendor','oneloop.tar.gz'))
555
556 try:
557 self.do_install(key,paths={'HEPToolsInstaller':
558 pjoin(MG5DIR,'vendor','OfflineHEPToolsInstaller.tar.gz')},
559 additional_options=additional_options)
560 except self.InvalidCmd:
561 logger.warning(
562 """The offline installation of %(p)s was unsuccessful, and MG5aMC disabled it.
563 In the future, if you want to reactivate Ninja, you can do so by re-attempting
564 its online installation with the command 'install %(p)s' or install it on your
565 own and set the path to its library in the MG5aMC option '%(p)s'.""" % {'p': key})
566 self.exec_cmd("set %s ''" % key)
567 self.exec_cmd('save options %s' % key)
568
569
570 elif value == 'install':
571 prog = {'pjfry': 'PJFry', 'golem': 'Golem95'}
572 if key in prog:
573 self.exec_cmd('install %s' % prog[key])
574 else:
575 self.exec_cmd('install %s' % key)
576
577 elif value == 'off':
578 self.exec_cmd("set %s ''" % key)
579 self.exec_cmd('save options %s' % key)
580 else:
581 self.exec_cmd("set %s %s" % (key,value))
582 self.exec_cmd('save options %s' % key)
583
584
585
586
587 - def ML5export(self, nojpeg = False, main_file_name = ""):
617
618
619 ndiags, cpu_time = generate_matrix_elements(self)
620
621 calls = 0
622
623 path = self._export_dir
624 if self._export_format in self.supported_ML_format:
625 path = pjoin(path, 'SubProcesses')
626
627 cpu_time1 = time.time()
628
629
630 matrix_elements = \
631 self._curr_matrix_elements.get_matrix_elements()
632
633
634 if self._export_format in self.supported_ML_format:
635 for unique_id, me in enumerate(matrix_elements):
636 calls = calls + \
637 self._curr_exporter.generate_subprocess_directory(\
638 me, self._curr_helas_model)
639
640
641
642
643 if self.options['loop_optimized_output'] and len(matrix_elements)>1:
644 max_lwfspins = [m.get_max_loop_particle_spin() for m in \
645 matrix_elements]
646 max_loop_vert_ranks = [me.get_max_loop_vertex_rank() for me in \
647 matrix_elements]
648 if len(set(max_lwfspins))>1 or len(set(max_loop_vert_ranks))>1:
649 self._curr_exporter.fix_coef_specs(max(max_lwfspins),\
650 max(max_loop_vert_ranks))
651
652
653 if self._export_format == 'matrix':
654 for me in matrix_elements:
655 filename = pjoin(path, 'matrix_' + \
656 me.get('processes')[0].shell_string() + ".f")
657 if os.path.isfile(filename):
658 logger.warning("Overwriting existing file %s" % filename)
659 else:
660 logger.info("Creating new file %s" % filename)
661 calls = calls + self._curr_exporter.write_matrix_element_v4(\
662 writers.FortranWriter(filename),\
663 me, self._curr_helas_model)
664
665 cpu_time2 = time.time() - cpu_time1
666
667 logger.info(("Generated helas calls for %d subprocesses " + \
668 "(%d diagrams) in %0.3f s") % \
669 (len(matrix_elements),
670 ndiags, cpu_time))
671
672 if calls:
673 if "cpu_time2" in locals():
674 logger.info("Wrote files for %d OPP calls in %0.3f s" % \
675 (calls, cpu_time2))
676 else:
677 logger.info("Wrote files for %d OPP calls" % \
678 (calls))
679
680
681
682
683 self._curr_amps = diagram_generation.AmplitudeList(\
684 [me.get('base_amplitude') for me in \
685 matrix_elements])
686
725
727 """Main commands: Check that the type of launch is fine before proceeding with the
728 mother function. """
729
730 args = self.split_arg(line)
731
732 (options, args) = mg_interface._launch_parser.parse_args(args)
733
734 self.check_launch(args, options)
735
736 if not args[0].startswith('standalone'):
737 raise self.InvalidCmd('ML5 can only launch standalone runs.')
738
739 start_cwd = os.getcwd()
740 options = options.__dict__
741
742
743 ext_program = launch_ext.MadLoopLauncher(self, args[1], \
744 options=self.options, **options)
745 ext_program.run()
746 os.chdir(start_cwd)
747
749 """Check a given process or set of processes"""
750
751 argss = self.split_arg(line, *args,**opt)
752
753 perturbation_couplings_pattern = \
754 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
755 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
756 perturbation_couplings=""
757 if perturbation_couplings_re:
758 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
759 QED_found=re.search("QED",perturbation_couplings)
760 if QED_found:
761 self.validate_model(coupling_type='QED')
762 else:
763 self.validate_model()
764
765 param_card = self.check_check(argss)
766 reuse = argss[1]=="-reuse"
767 argss = argss[:1]+argss[2:]
768
769
770 if argss[0] in ['stability', 'profile']:
771 stab_statistics = int(argss[1])
772 argss = argss[:1]+argss[2:]
773
774 i=-1
775 while argss[i].startswith('--'):
776 i=i-1
777
778 proc = " ".join(argss[1:i+1])
779 myprocdef = self.extract_process(proc)
780 self.proc_validity(myprocdef,'ML5_check_cms' if argss[0]=='cms' else \
781 'ML5_check')
782
783 return mg_interface.MadGraphCmd.do_check(self, line, *args,**opt)
784
785 - def do_add(self, line, *args,**opt):
786 """Generate an amplitude for a given process and add to
787 existing amplitudes
788 """
789 args = self.split_arg(line)
790
791 self.check_add(args)
792 perturbation_couplings_pattern = \
793 re.compile("^(?P<proc>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
794 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
795 perturbation_couplings=""
796 if perturbation_couplings_re:
797 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
798 QED_found=re.search('QED',perturbation_couplings)
799 if QED_found:
800 self.validate_model(coupling_type='QED')
801 else:
802 self.validate_model()
803
804 loop_filter=None
805 if args[0] == 'process':
806
807
808 for arg in args:
809 if arg.startswith('--loop_filter='):
810 loop_filter = arg[14:]
811 if not isinstance(self, extended_cmd.CmdShell):
812 raise InvalidCmd, "loop_filter is not allowed in web mode"
813 args = [a for a in args if not a.startswith('--loop_filter=')]
814
815
816 line = ' '.join(args[1:])
817
818
819 if not self._generate_info:
820 self._generate_info = line
821
822
823 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
824
825
826 myprocdef = self.extract_process(line)
827
828 if myprocdef.has_multiparticle_label():
829
830 succes, failed = 0, 0
831 for base_proc in myprocdef:
832 try:
833 self.exec_cmd("add process %s" % base_proc.nice_string(prefix=False, print_weighted=True))
834 succes += 1
835 except Exception:
836 failed +=1
837 logger.info("%s/%s processes succeeded" % (succes, failed+succes))
838 if succes == 0:
839 raise
840 else:
841 return
842
843
844
845
846
847 all_ids = [amp.get('process').get('id') for amp in self._curr_amps]
848 if myprocdef.get('id') in all_ids:
849 myprocdef.set('id',max(all_ids)+1)
850
851 self.proc_validity(myprocdef,'ML5')
852
853 cpu_time1 = time.time()
854
855
856 multiprocessclass=None
857 if myprocdef['perturbation_couplings']!=[]:
858 multiprocessclass=loop_diagram_generation.LoopMultiProcess
859 else:
860 multiprocessclass=diagram_generation.MultiProcess
861
862 myproc = multiprocessclass(myprocdef, collect_mirror_procs = False,
863 ignore_six_quark_processes = False,
864 loop_filter = loop_filter)
865
866 for amp in myproc.get('amplitudes'):
867 if amp not in self._curr_amps:
868 self._curr_amps.append(amp)
869 else:
870 warning = "Warning: Already in processes:\n%s" % \
871 amp.nice_string_processes()
872 logger.warning(warning)
873
874
875 self._done_export = False
876
877 cpu_time2 = time.time()
878
879 ndiags = sum([len(amp.get('loop_diagrams')) for \
880 amp in myproc.get('amplitudes')])
881 logger.info("Process generated in %0.3f s" % \
882 (cpu_time2 - cpu_time1))
883
886
889
890 local_installer = ['ninja', 'collier']
891 required = ['cuttools', 'iregi']
892 order = ['cuttools', 'iregi', 'ninja', 'collier', 'golem', 'pjfry']
893
894 @property
897
898
899 - def __init__(self, question, *args, **opts):
900
901 import urllib2
902 try:
903 response=urllib2.urlopen('http://madgraph.phys.ucl.ac.be/F1.html', timeout=3)
904 self.online=True
905 except urllib2.URLError as err:
906 self.online=False
907
908 self.code = {'ninja': 'install',
909 'collier': 'install',
910 'golem': 'off',
911 'pjfry':'off',
912 'cuttools': 'required',
913 'iregi': 'required'}
914 if not self.online:
915 self.code['ninja'] = 'local'
916 self.code['collier'] = 'local'
917 self.code['pjfry'] = 'fail'
918 self.code['golem'] = 'fail'
919 if not misc.which('cmake'):
920 self.code['collier'] = 'off'
921
922
923 if 'mother_interface' in opts:
924 mother = opts['mother_interface']
925 if 'heptools_install_dir' in mother.options:
926 install_dir1 = mother.options['heptools_install_dir']
927 install_dir2 = mother.options['heptools_install_dir']
928 if os.path.exists(pjoin(install_dir1, 'CutTools')):
929 self.code['cuttools'] = mother.options['heptools_install_dir']
930 if os.path.exists(pjoin(install_dir1, 'IREGI')):
931 self.code['iregi'] = mother.options['heptools_install_dir']
932 else:
933 install_dir1 = pjoin(MG5DIR, 'HEPTools')
934 install_dir2 = MG5DIR
935 if os.path.exists(pjoin(install_dir1, 'collier')):
936 self.code['collier'] = pjoin(install_dir1, 'collier')
937 if os.path.exists(pjoin(install_dir2, 'PJFry','bin','qd-config')):
938 self.code['collier'] = pjoin(install_dir2, 'PJFry')
939 if os.path.exists(pjoin(install_dir2, 'golem95')):
940 self.code['collier'] = pjoin(install_dir2, 'golem95')
941
942
943 question, allowed_answer = self.create_question(first=True)
944
945 opts['allow_arg'] = allowed_answer
946
947 cmd.OneLinePathCompletion.__init__(self, question, *args, **opts)
948
949
951 """ """
952
953 question = "For loop computations, MadLoop requires dedicated tools to"+\
954 " perform the reduction of loop Feynman diagrams using OPP-based and/or TIR approaches.\n"+\
955 "\nWhich one do you want to install? (this needs to be done only once)\n"
956
957 allowed_answer = set(['0','done'])
958
959 descript = {'cuttools': ['cuttools','(OPP)','[0711.3596]'],
960 'iregi': ['iregi','(TIR)','[1405.0301]'],
961 'ninja': ['ninja','(OPP)','[1403.1229]'],
962 'pjfry': ['pjfry','(TIR)','[1112.0500]'],
963 'golem': ['golem','(TIR)','[0807.0605]'],
964 'collier': ['collier','(TIR)','[1604.06792]']}
965
966
967 status = {'off': '%(start_red)sdo not install%(stop)s',
968 'install': '%(start_green)swill be installed %(stop)s',
969 'local': '%(start_green)swill be installed %(stop)s(offline installation from local repository)',
970 'fail': 'not available without internet connection',
971 'required': 'will be installed (required)'}
972
973 for i,key in enumerate(self.order,1):
974 if os.path.sep not in self.code[key]:
975 question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s%s\n' % \
976 tuple([i,]+descript[key]+[status[self.code[key]],]+\
977 ['(recommended)' if key in ['ninja','collier'] and self.code[key] in ['install'] else ''])
978 else:
979 question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s\n' % tuple([i,]+descript[key]+[self.code[key],])
980 if key in self.required:
981 continue
982 allowed_answer.update([str(i), key])
983 if key in self.local_installer:
984 allowed_answer.update(['key=local','key=off'])
985 if self.online:
986 allowed_answer.update(['key=on','key=install', 'key=off'])
987
988 question += "You can:\n -> hit 'enter' to proceed\n -> type a number to cycle its options\n -> enter the following command:\n"+\
989 ' %(start_blue)s{tool_name}%(stop)s [%(start_blue)sinstall%(stop)s|%(start_blue)snoinstall%(stop)s|'+\
990 '%(start_blue)s{prefixed_installation_path}%(stop)s]\n'
991 if first:
992 question += '\n%(start_bold)s%(start_red)sIf you are unsure about what this question means, just type enter to proceed. %(stop)s'
993
994 question = question % {'start_green' : '\033[92m',
995 'start_red' : '\033[91m',
996 'start_blue' : '\033[34m',
997 'stop': '\033[0m',
998 'start_bold':'\033[1m',
999 }
1000 return question, allowed_answer
1001
1003 """Default action if line is not recognized"""
1004
1005 line = line.strip()
1006 args = line.split()
1007
1008 if line in ['0', 'done','','EOF']:
1009 self.value = 'done'
1010 return self.answer
1011 self.value = 'repeat'
1012 if args:
1013 if len(args) ==1 and '=' in args[0]:
1014 args = args[0].split('=')
1015 args[0] = args[0].lower()
1016 if len(args) == 1:
1017
1018 if args[0].isdigit():
1019 if len(self.order) < int(args[0]):
1020 logger.warning('Invalid integer %s. Please Retry' % args[0])
1021 return
1022 args[0] = self.order[int(args[0])-1]
1023 key = args[0]
1024 if key in self.code:
1025 if self.code[key] in ['off']:
1026 if self.online:
1027 self.code[key] = 'install'
1028 elif key in self.local_installer:
1029 self.code[key] = 'local'
1030 elif self.code[key] == 'install':
1031 if key in self.local_installer:
1032 self.code[key] = 'local'
1033 else:
1034 self.code[key] = 'off'
1035 elif self.code[key] == 'local':
1036 self.code[key] = 'off'
1037 else:
1038 logger.warning('Unknown entry \'%s\'. Please retry' % key)
1039 return
1040 elif len(args) == 2:
1041 key = args[0]
1042 if key not in self.code:
1043 logger.warning('unknown %s type of entry. Bypass command.')
1044 return
1045 if os.path.sep not in args[1]:
1046 value = args[1].lower()
1047 if value in ['off', 'not','noinstall']:
1048 self.code[key] = 'off'
1049 elif value in ['on', 'install']:
1050 if self.online:
1051 self.code[key] = 'install'
1052 elif key in self.local_installer:
1053 self.code[key] = 'local'
1054 else:
1055 logger.warning('offline installer not available for %s', key)
1056 self.code[key] = 'off'
1057 elif value in ['local']:
1058 if key in self.local_installer:
1059 self.code[key] = 'local'
1060 else:
1061 logger.warning('offline installer not available for %s', key)
1062 self.code[key] = 'off'
1063 else:
1064 self.code[key] = args[1]
1065 else:
1066 self.value = 0
1067 self.question,self.allow_arg = self.create_question()
1068 return self.answer
1069
1071
1072 if line.startswith('='):
1073 line = line[1:]
1074 return self.default('%s %s' % (name,line))
1075
1076
1077 do_ninja = lambda self,line : self.apply_name('ninja', line)
1078 do_pjfry = lambda self,line : self.apply_name('pjfry', line)
1079 do_collier = lambda self,line : self.apply_name('collier', line)
1080 do_golem = lambda self,line : self.apply_name('golem', line)
1081 do_cuttools = lambda self,line : self.apply_name('cuttools', line)
1082 do_iregi = lambda self,line : self.apply_name('iregi', line)
1083
1084
1085 - def complete_prog(self, text, line, begidx, endidx, formatting=True):
1086
1087 if os.path.sep in line:
1088 args = line[0:begidx].split()
1089 if args[-1].endswith(os.path.sep):
1090 return self.path_completion(text,
1091 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
1092 only_dirs = True)
1093 else:
1094 return self.path_completion(text, '.', only_dirs = True)
1095 else:
1096 return self.list_completion(text, ['install', 'noinstall', 'local'], line)
1097
1098 complete_ninja = complete_prog
1099 complete_pjfry = complete_prog
1100 complete_collier = complete_prog
1101 complete_golem = complete_prog
1102 complete_cuttools = complete_prog
1103 complete_iregi = complete_prog
1104