1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """A user friendly command line interface to access MadGraph5_aMC@NLO features at LO.
16 Uses the cmd package for command interpretation and tab completion.
17 """
18 from __future__ import division
19
20 import atexit
21 import collections
22 import cmath
23 import glob
24 import logging
25 import optparse
26 import os
27 import pydoc
28 import random
29 import re
30 import signal
31 import subprocess
32 import copy
33 import sys
34 import shutil
35 import StringIO
36 import traceback
37 import time
38 import inspect
39 import urllib
40 import random
41
42
43 pjoin = os.path.join
44
45 try:
46 import readline
47 GNU_SPLITTING = ('GNU' in readline.__doc__)
48 except:
49 GNU_SPLITTING = True
50
51 import aloha
52 import madgraph
53 from madgraph import MG4DIR, MG5DIR, MadGraph5Error
54
55
56 import madgraph.core.base_objects as base_objects
57 import madgraph.core.diagram_generation as diagram_generation
58 import madgraph.loop.loop_diagram_generation as loop_diagram_generation
59 import madgraph.loop.loop_base_objects as loop_base_objects
60 import madgraph.core.drawing as draw_lib
61 import madgraph.core.helas_objects as helas_objects
62
63 import madgraph.iolibs.drawing_eps as draw
64 import madgraph.iolibs.export_cpp as export_cpp
65 import madgraph.iolibs.export_v4 as export_v4
66 import madgraph.iolibs.helas_call_writers as helas_call_writers
67 import madgraph.iolibs.file_writers as writers
68 import madgraph.iolibs.files as files
69 import madgraph.iolibs.group_subprocs as group_subprocs
70 import madgraph.iolibs.import_v4 as import_v4
71 import madgraph.iolibs.save_load_object as save_load_object
72
73 import madgraph.interface.extended_cmd as cmd
74 import madgraph.interface.tutorial_text as tutorial_text
75 import madgraph.interface.tutorial_text_nlo as tutorial_text_nlo
76 import madgraph.interface.tutorial_text_madloop as tutorial_text_madloop
77 import madgraph.interface.launch_ext_program as launch_ext
78 import madgraph.interface.madevent_interface as madevent_interface
79 import madgraph.interface.amcatnlo_run_interface as amcatnlo_run
80
81 import madgraph.loop.loop_exporters as loop_exporters
82 import madgraph.loop.loop_helas_objects as loop_helas_objects
83
84 import madgraph.various.process_checks as process_checks
85 import madgraph.various.banner as banner_module
86 import madgraph.various.misc as misc
87 import madgraph.various.cluster as cluster
88
89 import models as ufomodels
90 import models.import_ufo as import_ufo
91 import models.write_param_card as param_writer
92 import models.check_param_card as check_param_card
93 import models.model_reader as model_reader
94
95 import aloha.aloha_fct as aloha_fct
96 import aloha.create_aloha as create_aloha
97 import aloha.aloha_lib as aloha_lib
98
99 import mg5decay.decay_objects as decay_objects
100
101
102 logger = logging.getLogger('cmdprint')
103 logger_check = logging.getLogger('check')
104 logger_mg = logging.getLogger('madgraph.interface')
105 logger_stderr = logging.getLogger('fatalerror')
106 logger_tuto = logging.getLogger('tutorial')
107
108 logger_tuto_nlo = logging.getLogger('tutorial_aMCatNLO')
109
110
111 logger_tuto_madloop = logging.getLogger('tutorial_MadLoop')
117 """Particularisation of the cmd command for MG5"""
118
119
120 next_possibility = {
121 'start': ['import model ModelName', 'import command PATH',
122 'import proc_v4 PATH', 'tutorial'],
123 'import model' : ['generate PROCESS','define MULTIPART PART1 PART2 ...',
124 'display particles', 'display interactions'],
125 'define': ['define MULTIPART PART1 PART2 ...', 'generate PROCESS',
126 'display multiparticles'],
127 'generate': ['add process PROCESS','output [OUTPUT_TYPE] [PATH]','display diagrams'],
128 'add process':['output [OUTPUT_TYPE] [PATH]', 'display processes'],
129 'output':['launch','open index.html','history PATH', 'exit'],
130 'display': ['generate PROCESS', 'add process PROCESS', 'output [OUTPUT_TYPE] [PATH]'],
131 'import proc_v4' : ['launch','exit'],
132 'launch': ['open index.html','exit'],
133 'tutorial': ['generate PROCESS', 'import model MODEL', 'help TOPIC']
134 }
135
136 debug_output = 'MG5_debug'
137 error_debug = 'Please report this bug on https://bugs.launchpad.net/mg5amcnlo\n'
138 error_debug += 'More information is found in \'%(debug)s\'.\n'
139 error_debug += 'Please attach this file to your report.'
140
141 config_debug = 'If you need help with this issue please contact us on https://answers.launchpad.net/mg5amcnlo\n'
142
143 keyboard_stop_msg = """stopping all operation
144 in order to quit mg5 please enter exit"""
145
146
147 InvalidCmd = madgraph.InvalidCmd
148 ConfigurationError = MadGraph5Error
149
150 intro_banner = "************************************************************\n" + \
151 "* *\n" + \
152 "* W E L C O M E to *\n" + \
153 "* M A D G R A P H 5 _ a M C @ N L O *\n" + \
154 "* *\n" + \
155 "* *\n" + \
156 "* * * *\n" + \
157 "* * * * * *\n" + \
158 "* * * * * 5 * * * * *\n" + \
159 "* * * * * *\n" + \
160 "* * * *\n" + \
161 "* *\n" + \
162 "%s" + \
163 "* *\n" + \
164 "* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \
165 "* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
166 "* and *\n" + \
167 "* http://amcatnlo.web.cern.ch/amcatnlo/ *\n" + \
168 "* *\n" + \
169 "* Type 'help' for in-line help. *\n" + \
170 "* Type 'tutorial' to learn how MG5 works *\n" + \
171 "* Type 'tutorial aMCatNLO' to learn how aMC@NLO works *\n" + \
172 "* Type 'tutorial MadLoop' to learn how MadLoop works *\n" + \
173 "* *\n" + \
174 "************************************************************"
175
176
178 """Init history and line continuation"""
179
180
181
182 info = misc.get_pkg_info()
183 info_line = ""
184
185 if info.has_key('version') and info.has_key('date'):
186 len_version = len(info['version'])
187 len_date = len(info['date'])
188 if len_version + len_date < 30:
189 info_line = "#* VERSION %s %s %s *\n" % \
190 (info['version'],
191 (30 - len_version - len_date) * ' ',
192 info['date'])
193
194 if os.path.exists(pjoin(MG5DIR, '.bzr')):
195 proc = subprocess.Popen(['bzr', 'nick'], stdout=subprocess.PIPE,cwd=MG5DIR)
196 bzrname,_ = proc.communicate()
197 proc = subprocess.Popen(['bzr', 'revno'], stdout=subprocess.PIPE,cwd=MG5DIR)
198 bzrversion,_ = proc.communicate()
199 bzrname, bzrversion = bzrname.strip(), bzrversion.strip()
200 len_name = len(bzrname)
201 len_version = len(bzrversion)
202 info_line += "#* BZR %s %s %s *\n" % \
203 (bzrname,
204 (34 - len_name - len_version) * ' ',
205 bzrversion)
206
207
208
209 self.history_header = banner_module.ProcCard.history_header % {'info_line': info_line}
210 banner_module.ProcCard.history_header = self.history_header
211
212 if info_line:
213 info_line = info_line.replace("#*","*")
214
215
216
217 logger.info(self.intro_banner % info_line)
218
219 cmd.Cmd.__init__(self, *arg, **opt)
220
221 self.history = banner_module.ProcCard()
222
223
225 """Default action if line is not recognized"""
226
227
228 log=True
229 if line.startswith('p') or line.startswith('e'):
230 logger.warning("Command %s not recognized. Did you mean \'generate %s\'?. Please try again" %
231 (line.split()[0], line))
232 log=False
233 return super(CmdExtended,self).default(line, log=log)
234
235 - def postcmd(self,stop, line):
236 """ finishing a command
237 This looks if the command add a special post part.
238 This looks if we have to write an additional text for the tutorial."""
239
240 stop = super(CmdExtended, self).postcmd(stop, line)
241
242 if stop == False:
243 return False
244
245 args=line.split()
246
247 if len(args)==0:
248 return stop
249
250
251
252
253 if len(args)==1:
254 command=args[0]
255 else:
256 command = args[0]+'_'+args[1].split('.')[0]
257
258 try:
259 logger_tuto.info(getattr(tutorial_text, command).replace('\n','\n\t'))
260 except Exception:
261 try:
262 logger_tuto.info(getattr(tutorial_text, args[0]).replace('\n','\n\t'))
263 except Exception:
264 pass
265
266 try:
267 logger_tuto_nlo.info(getattr(tutorial_text_nlo, command).replace('\n','\n\t'))
268 except Exception:
269 try:
270 logger_tuto_nlo.info(getattr(tutorial_text_nlo, args[0]).replace('\n','\n\t'))
271 except Exception:
272 pass
273
274 try:
275 logger_tuto_madloop.info(getattr(tutorial_text_madloop, command).replace('\n','\n\t'))
276 except Exception:
277 try:
278 logger_tuto_madloop.info(getattr(tutorial_text_madloop, args[0]).replace('\n','\n\t'))
279 except Exception:
280 pass
281
282 return stop
283
284
286 """return the history header"""
287 return self.history_header % misc.get_time_info()
288
293 """ The Series of help routine for the MadGraphCmd"""
294
296 logger.info("syntax: save %s FILENAME" % "|".join(self._save_opts),'$MG:color:BLUE')
297 logger.info("-- save information as file FILENAME",'$MG:color:BLACK')
298 logger.info(" FILENAME is optional for saving 'options'.")
299 logger.info(' By default it uses ./input/mg5_configuration.txt')
300 logger.info(' If you put "global" for FILENAME it will use ~/.mg5/mg5_configuration.txt')
301 logger.info(' If this files exists, it is uses by all MG5 on the system but continues')
302 logger.info(' to read the local options files.')
303
305 logger.info("syntax: load %s FILENAME" % "|".join(self._save_opts),'$MG:color:BLUE')
306 logger.info("-- load information from file FILENAME",'$MG:color:BLACK')
307
309 logger.info("syntax: import " + "|".join(self._import_formats) + \
310 " FILENAME",'$MG:color:BLUE')
311 logger.info("-- imports file(s) in various formats",'$MG:color:GREEN')
312 logger.info("")
313 logger.info(" import model MODEL[-RESTRICTION] [OPTIONS]:",'$MG:color:BLACK')
314 logger.info(" Import a UFO model.")
315 logger.info(" MODEL should be a valid UFO model name")
316 logger.info(" Model restrictions are specified by MODEL-RESTRICTION")
317 logger.info(" with the file restrict_RESTRICTION.dat in the model dir.")
318 logger.info(" By default, restrict_default.dat is used.")
319 logger.info(" Specify model_name-full to get unrestricted model.")
320 logger.info(" '--modelname' keeps the original particle names for the model")
321 logger.info("")
322 logger.info(" import model_v4 MODEL [--modelname] :",'$MG:color:BLACK')
323 logger.info(" Import an MG4 model.")
324 logger.info(" Model should be the name of the model")
325 logger.info(" or the path to theMG4 model directory")
326 logger.info(" '--modelname' keeps the original particle names for the model")
327 logger.info("")
328 logger.info(" import proc_v4 [PATH] :",'$MG:color:BLACK')
329 logger.info(" Execute MG5 based on a proc_card.dat in MG4 format.")
330 logger.info(" Path to the proc_card is optional if you are in a")
331 logger.info(" madevent directory")
332 logger.info("")
333 logger.info(" import command PATH :",'$MG:color:BLACK')
334 logger.info(" Execute the list of command in the file at PATH")
335 logger.info("")
336 logger.info(" import banner PATH [--no_launch]:",'$MG:color:BLACK')
337 logger.info(" Rerun the exact same run define in the valid banner.")
338
340 logger.info("syntax: install " + "|".join(self._install_opts),'$MG:color:BLUE')
341 logger.info("-- Download the last version of the program and install it")
342 logger.info(" locally in the current MadGraph5_aMC@NLO version. In order to have")
343 logger.info(" a successful installation, you will need to have an up-to-date")
344 logger.info(" F77 and/or C and Root compiler.")
345 logger.info(" ")
346 logger.info(" When installing any of the following programs:")
347 logger.info(" %s"%(', '.join(self._advanced_install_opts)))
348 logger.info(" The following options are available:")
349 logger.info(" --force Overwrite without asking any existing installation.")
350 logger.info(" --keep_source Keep a local copy of the sources of the tools MG5_aMC installed from.")
351 logger.info(" ")
352 logger.info(" \"install update\"",'$MG:color:BLACK')
353 logger.info(" check if your MG5 installation is the latest one.")
354 logger.info(" If not it load the difference between your current version and the latest one,")
355 logger.info(" and apply it to the code. Two options are available for this command:")
356 logger.info(" -f: didn't ask for confirmation if it founds an update.")
357 logger.info(" --timeout=: Change the maximum time allowed to reach the server.")
358
360 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLUE')
361 logger.info("-- display a the status of various internal state variables")
362 logger.info(" for particles/interactions you can specify the name or id of the")
363 logger.info(" particles/interactions to receive more details information.")
364 logger.info(" Example: display particles e+.",'$MG:color:GREEN')
365 logger.info(" > For \"checks\", can specify only to see failed checks.")
366 logger.info(" > For \"diagrams\", you can specify where the file will be written.")
367 logger.info(" Example: display diagrams ./",'$MG:color:GREEN')
368
369
371 """help for launch command"""
372
373
374
375 logger.info("syntax: launch <dir_path> <options>",'$MG:color:BLUE')
376 logger.info("-- execute the aMC@NLO/madevent/standalone/pythia8 output present in dir_path",'$MG:color:BLACK')
377 logger.info("By default, dir_path points to the last created directory.")
378 logger.info("(for pythia8, it should be the Pythia 8 main directory)")
379 logger.info("")
380 logger.info("Launch on madevent/pythia8/standalone outputs:",'$MG:color:BLACK')
381 logger.info(" o Example: launch PROC_sm_1 --name=run2",'$MG:color:GREEN')
382 logger.info(" o Example: launch ../pythia8",'$MG:color:GREEN')
383 logger.info(" > Options:")
384 logger.info(" -h, --help show this help message and exit")
385 logger.info(" -f, --force Use the card present in the directory in order")
386 logger.info(" to launch the different program")
387 logger.info(" -n NAME, --name=NAME Provide a name to the run (for madevent run)")
388 logger.info(" -c, --cluster submit the job on the cluster")
389 logger.info(" -m, --multicore submit the job on multicore core")
390 logger.info(" -i, --interactive Use Interactive Console [if available]")
391 logger.info(" -s LASTSTEP, --laststep=LASTSTEP")
392 logger.info(" last program run in MadEvent run.")
393 logger.info(" [auto|parton|pythia|pgs|delphes]")
394 logger.info("")
395 logger.info("Launch on MadLoop standalone output:",'$MG:color:BLACK')
396 logger.info(" o Example: launch PROC_loop_sm_1 -f",'$MG:color:GREEN')
397 logger.info(" > Simple check of a single Phase-space points.")
398 logger.info(" > You will be asked whether you want to edit the MadLoop ")
399 logger.info(" and model param card as well as the PS point, unless ")
400 logger.info(" the -f option is specified. All other options are ")
401 logger.info(" irrelevant for this kind of launch.")
402 logger.info("")
403 logger.info("Launch on aMC@NLO output:",'$MG:color:BLACK')
404 logger.info(" > launch <dir_path> <mode> <options>",'$MG:color:BLUE')
405 logger.info(" o Example: launch MyProc aMC@NLO -f -p",'$MG:color:GREEN')
406
408 logger.info("syntax: tutorial [" + "|".join(self._tutorial_opts) + "]",'$MG:color:BLUE')
409 logger.info("-- start/stop the MG5 tutorial mode (or stop any other mode)")
410 logger.info("-- aMCatNLO: start aMC@NLO tutorial mode")
411 logger.info("-- MadLoop: start MadLoop tutorial mode")
412
414 logger.info("syntax: open FILE ",'$MG:color:BLUE')
415 logger.info("-- open a file with the appropriate editor.",'$MG:color:BLACK')
416 logger.info(' If FILE belongs to index.html, param_card.dat, run_card.dat')
417 logger.info(' the path to the last created/used directory is used')
418 logger.info(' The program used to open those files can be chosen in the')
419 logger.info(' configuration file ./input/mg5_configuration.txt')
420
422 logger.info("syntax: customize_model --save=NAME",'$MG:color:BLUE')
423 logger.info("-- Open an invite where you options to tweak the model.",'$MG:color:BLACK')
424 logger.info(" If you specify the option --save=NAME, this tweak will be")
425 logger.info(" available for future import with the command 'import model XXXX-NAME'")
426
428 logger.info("syntax: output [" + "|".join(self._export_formats) + \
429 "] [path|.|auto] [options]",'$MG:color:BLUE')
430 logger.info("-- Output any generated process(es) to file.",'$MG:color:BLACK')
431 logger.info(" Default mode is madevent. Default path is \'.\' or auto.")
432 logger.info(" mode:",'$MG:color:BLACK')
433 logger.info(" - For MadLoop and aMC@NLO runs, there is only one mode and")
434 logger.info(" it is set by default.")
435 logger.info(" - If mode is madevent, create a MadEvent process directory.")
436 logger.info(" - If mode is standalone, create a Standalone directory")
437 logger.info(" - If mode is matrix, output the matrix.f files for all")
438 logger.info(" generated processes in directory \"path\".")
439 logger.info(" - If mode is standalone_cpp, create a standalone C++")
440 logger.info(" directory in \"path\".")
441 logger.info(" - If mode is pythia8, output all files needed to generate")
442 logger.info(" the processes using Pythia 8. The files are written in")
443 logger.info(" the Pythia 8 directory (default).")
444 logger.info(" NOTE: The Pythia 8 directory is set in the ./input/mg5_configuration.txt")
445 logger.info(" - If mode is aloha: Special syntax output:")
446 logger.info(" syntax: aloha [ROUTINE] [--options]" )
447 logger.info(" valid options for aloha output are:")
448 logger.info(" --format=Fortran|Python|Cpp : defining the output language")
449 logger.info(" --output= : defining output directory")
450 logger.info(" path: The path of the process directory.",'$MG:color:BLACK')
451 logger.info(" If you put '.' as path, your pwd will be used.")
452 logger.info(" If you put 'auto', an automatic directory PROC_XX_n will be created.")
453 logger.info(" options:",'$MG:color:BLACK')
454 logger.info(" -f: force cleaning of the directory if it already exists")
455 logger.info(" -d: specify other MG/ME directory")
456 logger.info(" -noclean: no cleaning performed in \"path\".")
457 logger.info(" -nojpeg: no jpeg diagrams will be generated.")
458 logger.info(" -name: the postfix of the main file in pythia8 mode.")
459 logger.info(" Examples:",'$MG:color:GREEN')
460 logger.info(" output",'$MG:color:GREEN')
461 logger.info(" output standalone MYRUN -f",'$MG:color:GREEN')
462 logger.info(" output pythia8 ../pythia8/ -name qcdprocs",'$MG:color:GREEN')
463
465 logger.info("syntax: check [" + "|".join(self._check_opts) + "] [param_card] process_definition [--energy=] [--split_orders=] [--reduction=]",'$MG:color:BLUE')
466 logger.info("-- check a process or set of processes.",'$MG:color:BLACK')
467 logger.info("General options:",'$MG:color:BLACK')
468 logger.info("o full:",'$MG:color:GREEN')
469 logger.info(" Perform all four checks described below:")
470 logger.info(" permutation, brs, gauge and lorentz_invariance.")
471 logger.info("o permutation:",'$MG:color:GREEN')
472 logger.info(" Check that the model and MG5 are working properly")
473 logger.info(" by generating permutations of the process and checking")
474 logger.info(" that the resulting matrix elements give the same value.")
475 logger.info("o gauge:",'$MG:color:GREEN')
476 logger.info(" Check that processes are gauge invariant by ")
477 logger.info(" comparing Feynman and unitary gauges.")
478 logger.info(" This check is, for now, not available for loop processes.")
479 logger.info("o brs:",'$MG:color:GREEN')
480 logger.info(" Check that the Ward identities are satisfied if the ")
481 logger.info(" process has at least one massless gauge boson as an")
482 logger.info(" external particle.")
483 logger.info("o lorentz_invariance:",'$MG:color:GREEN')
484 logger.info(" Check that the amplitude is lorentz invariant by")
485 logger.info(" comparing the amplitiude in different frames")
486 logger.info("o cms:",'$MG:color:GREEN')
487 logger.info(" Check the complex mass scheme consistency by comparing")
488 logger.info(" it to the narrow width approximation in the off-shell")
489 logger.info(" region of detected resonances and by progressively")
490 logger.info(" decreasing the width. Additional options for this check are:")
491 logger.info(" --offshellness=f : f is a positive or negative float specifying ")
492 logger.info(" the distance from the pole as f*particle_mass. Default is 10.0")
493 logger.info(" --seed=i : to force a specific RNG integer seed i (default is fixed to 0)")
494 logger.info(" --cms=order1&order2;...,p1->f(p,lambdaCMS)&p2->f2(p,lambdaCMS);...")
495 logger.info(" 'order_i' specifies the expansion orders considered for the test.")
496 logger.info(" The substitution lists specifies how internal parameter must be modified")
497 logger.info(" with the width scaling 'lambdaCMS'. The default value for this option is:")
498 logger.info(" --cms=QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS ")
499 logger.info(" The number of order and parameters don't have to be the same.")
500 logger.info(" The scaling must be specified so that one occurrence of the coupling order.")
501 logger.info(" brings in exactly one power of lambdaCMS.")
502 logger.info(" --recompute_width= never|first_time|always|auto")
503 logger.info(" Decides when to use MadWidth to automatically recompute the width")
504 logger.info(" 'auto' (default) let MG5 chose the most appropriate behavior.")
505 logger.info(" 'never' uses the default width value for lambdaCMS=1.0.")
506 logger.info(" 'first_time' uses MadWidth to compute the width for lambdaCMS=1.0.")
507 logger.info(" 'first_time' and 'never' assume linear scaling of the widths with lambdaCMS")
508 logger.info(" 'always' uses MadWidth to compute the widths for all values of lambdaCMS")
509 logger.info(" the test relies on linear scaling of the width, so 'always' is ")
510 logger.info(" only for double-checks")
511 logger.info(" --lambdaCMS = <python_list> : specifies the list of lambdaCMS values to ")
512 logger.info(" use for the test. For example: '[(1/2.0)**exp\ for\ exp\ in\ range(0,20)]'")
513 logger.info(" In the list expression, you must escape spaces. Also, this option")
514 logger.info(" *must* appear last in the otpion list. Finally, the default value is '1.0e-6'")
515 logger.info(" for which an optimal list of progressive values is picked up to 1.0e-6")
516 logger.info(" --show_plot = True or False: Whether to show plot during analysis (default is True)")
517 logger.info(" --report = concise or full: Whether return a concise or full report.")
518 logger.info("Comments",'$MG:color:GREEN')
519 logger.info(" > If param_card is given, that param_card is used ")
520 logger.info(" instead of the default values for the model.")
521 logger.info(" If that file is an (LHE) event file. The param_card of the banner")
522 logger.info(" is used and the first event compatible with the requested process")
523 logger.info(" is used for the computation of the square matrix elements")
524 logger.info(" > \"--energy=\" allows to change the default value of sqrt(S).")
525 logger.info(" > Except for the 'gauge' test, all checks above are also")
526 logger.info(" available for loop processes with ML5 ('virt=' mode)")
527 logger.info("Example: check full p p > j j",'$MG:color:GREEN')
528 logger.info("Options for loop processes only:",'$MG:color:BLACK')
529 logger.info("o timing:",'$MG:color:GREEN')
530 logger.info(" Generate and output a process and returns detailed")
531 logger.info(" information about the code and a timing benchmark.")
532 logger.info("o stability:",'$MG:color:GREEN')
533 logger.info(" Generate and output a process and returns detailed")
534 logger.info(" statistics about the numerical stability of the code.")
535 logger.info("o profile:",'$MG:color:GREEN')
536 logger.info(" Performs both the timing and stability analysis at once")
537 logger.info(" and outputs the result in a log file without prompting")
538 logger.info(" it to the user.")
539 logger.info("Comments",'$MG:color:GREEN')
540 logger.info(" > These checks are only available for ML5 ('virt=' mode)")
541 logger.info(" > For the 'profile' and 'stability' checks, you can chose")
542 logger.info(" how many PS points should be used for the statistic by")
543 logger.info(" specifying it as an integer just before the [param_card]")
544 logger.info(" optional argument.")
545 logger.info(" > Notice multiparticle labels cannot be used with these checks.")
546 logger.info(" > \"--reduction=\" allows to change what reduction methods should be used.")
547 logger.info(" > \"--split_orders=\" allows to change what specific combination of coupling orders to consider.")
548 logger.info(" > For process syntax, please see help generate.")
549 logger.info(" > In order to save the directory generated or the reuse an existing one")
550 logger.info(" previously generated with the check command, one can add the '-reuse' ")
551 logger.info(" keyword just after the specification of the type of check desired.")
552 logger.info("Example: check profile g g > t t~ [virt=QCD]",'$MG:color:GREEN')
553
554
556
557 logger.info("-- generate diagrams for a given process",'$MG:color:BLUE')
558 logger.info("General leading-order syntax:",'$MG:color:BLACK')
559 logger.info(" o generate INITIAL STATE > REQ S-CHANNEL > FINAL STATE $ EXCL S-CHANNEL / FORBIDDEN PARTICLES COUP1=ORDER1 COUP2^2=ORDER2 @N")
560 logger.info(" o Example: generate l+ vl > w+ > l+ vl a $ z / a h QED<=3 QCD=0 @1",'$MG:color:GREEN')
561 logger.info(" > Alternative required s-channels can be separated by \"|\":")
562 logger.info(" b b~ > W+ W- | H+ H- > ta+ vt ta- vt~")
563 logger.info(" > If no coupling orders are given, MG5 will try to determine")
564 logger.info(" orders to ensure maximum number of QCD vertices.")
565 logger.info(" > Desired coupling orders combination can be specified directly for")
566 logger.info(" the squared matrix element by appending '^2' to the coupling name.")
567 logger.info(" For example, 'p p > j j QED^2==2 QCD^==2' selects the QED-QCD")
568 logger.info(" interference terms only. The other two operators '<=' and '>' are")
569 logger.info(" supported. Finally, a negative value COUP^2==-I refers to the")
570 logger.info(" N^(-I+1)LO term in the expansion of the COUP order.")
571 logger.info(" > allowed coupling operator are: \"==\", \"=\", \"<=\" and \">\".")
572 logger.info(" \"==\" request exactly that number of coupling while \"=\" is interpreted as \"<=\".")
573 logger.info(" > To generate a second process use the \"add process\" command")
574 logger.info("Decay chain syntax:",'$MG:color:BLACK')
575 logger.info(" o core process, decay1, (decay2, (decay2', ...)), ... etc")
576 logger.info(" o Example: generate p p > t~ t QED=0, (t~ > W- b~, W- > l- vl~), t > j j b @2",'$MG:color:GREEN')
577 logger.info(" > Note that identical particles will all be decayed.")
578 logger.info("Loop processes syntax:",'$MG:color:BLACK')
579 logger.info(" o core process [ <NLO_mode=> LoopOrder1 LoopOrder2 ... ] SQUAREDCOUPi=ORDERi")
580 logger.info(" o Example: generate p p > t~ t QED=0 QCD=2 [ all= QCD ] QCD=6",'$MG:color:GREEN')
581 logger.info(" > Notice that in this format, decay chains are not allowed.")
582 logger.info(" > The LoopOrder(s) defined specify the kind of loops to consider (only QCD for now).")
583 logger.info(" > The coupling restrictions before '[' restrict the orders of born *amplitudes*.")
584 logger.info(" So that in the example above QCD=2 restricts the born amplitude to have at")
585 logger.info(" most QCD=2 and loop amplitudes at most QCD=2+2 (because QCD loops are considered)")
586 logger.info(" > The coupling restrictions after ']' restrict the orders of the matrix element, ")
587 logger.info(" namely the squared amplitudes. In the example above QCD=6 correspond to born")
588 logger.info(" amplitudes with QCD=2 squared against loop amplitudes with QCD=4, adding up to 6.")
589 logger.info(" > The optional <NLO_mode=> can be any of the following ('all=' by default if absent):")
590 logger.info(" all= : Generate all the real-emission and loop diagrams, ready for aMC@NLO runs.")
591 logger.info(" virt= : Generate only the loop diagrams, read for MadLoop standalone checks/runs.")
592 logger.info(" real= : Generate only the real-emission diagrams, for use with alternative OLP. ")
593 logger.info(" > For processes without born amplitudes (i.e. loop-induced like g g > z), please use ")
594 logger.info(" the 'virt=' NLO mode. aMC@NLO cannot integrate these processes, but standalone MadLoop5")
595 logger.info(" can still handle these.")
596
598 logger.info("-- generate diagrams for a process and add to existing processes",'$MG:color:BLUE')
599 logger.info(" OR merge two model",'$MG:color:BLUE')
600 logger.info('')
601 logger.info("-- generate diagrams for a process and add to existing processes",'$MG:color:BLUE')
602 logger.info("General leading-order syntax:",'$MG:color:BLACK')
603 logger.info(" o add process INITIAL STATE > REQ S-CHANNEL > FINAL STATE $ EXCL S-CHANNEL / FORBIDDEN PARTICLES COUP1=ORDER1 COUP2=ORDER2 @N")
604 logger.info(" o Example: add process l+ vl > w+ > l+ vl a $ z / a h QED=3 QCD=0 @1",'$MG:color:GREEN')
605 logger.info(" > Alternative required s-channels can be separated by \"|\":")
606 logger.info(" b b~ > W+ W- | H+ H- > ta+ vt ta- vt~")
607 logger.info(" > If no coupling orders are given, MG5 will try to determine")
608 logger.info(" orders to ensure maximum number of QCD vertices.")
609 logger.info(" > Note that if there are more than one non-QCD coupling type,")
610 logger.info(" coupling orders need to be specified by hand.")
611 logger.info("Decay chain syntax:",'$MG:color:BLACK')
612 logger.info(" o core process, decay1, (decay2, (decay2', ...)), ... etc")
613 logger.info(" o Example: add process p p > t~ t QED=0, (t~ > W- b~, W- > l- vl~), t > j j b @2",'$MG:color:GREEN')
614 logger.info(" > Note that identical particles will all be decayed.")
615 logger.info("Loop processes syntax:",'$MG:color:BLACK')
616 logger.info(" o core process [ <NLO_mode=> LoopOrder1 LoopOrder2 ... ] SQUAREDCOUPi=ORDERi")
617 logger.info(" o Example: add process p p > t~ t QED=0 QCD=2 [ all= QCD ] QCD=6",'$MG:color:GREEN')
618 logger.info(" > Notice that in this format, decay chains are not allowed.")
619 logger.info(" > The LoopOrder(s) defined specify the kind of loops to consider (only QCD for now).")
620 logger.info(" > The coupling restrictions before '[' restrict the orders of born *amplitudes*.")
621 logger.info(" So that in the example above QCD=2 restricts the born amplitude to have at")
622 logger.info(" most QCD=2 and loop amplitudes at most QCD=2+2 (because QCD loops are considered)")
623 logger.info(" > The coupling restrictions after ']' restrict the orders of the matrix element, ")
624 logger.info(" namely the squared amplitudes. In the example above QCD=6 correspond to born")
625 logger.info(" amplitudes with QCD=2 squared against loop amplitudes with QCD=4, adding up to 6.")
626 logger.info(" > The optional <NLO_mode=> can be any of the following ('all=' by default if absent):")
627 logger.info(" all= : Generate all the real-emission and loop diagrams, ready for aMC@NLO runs.")
628 logger.info(" virt= : Generate only the loop diagrams, read for MadLoop standalone checks/runs.")
629 logger.info(" real= : Generate only the real-emission diagrams, for use with alternative OLP. ")
630 logger.info(" > For processes without born amplitudes (i.e. loop-induced like g g > z), please use ")
631 logger.info(" the 'virt=' NLO mode. aMC@NLO cannot integrate these processes, but standalone MadLoop5")
632 logger.info(" can still handle these.")
633
634 logger.info("-- merge two model to create a new one", '$MG:color:BLUE')
635 logger.info("syntax:",'$MG:color:BLACK')
636 logger.info(" o add model MODELNAME [OPTIONS]")
637 logger.info(" o Example: add model taudecay",'$MG:color:GREEN')
638 logger.info(" > Merge the two model in a single one. If that same merge was done before.")
639 logger.info(" > Just reload the previous merge. (WARNING: This doesn't check if those model are modified)")
640 logger.info(" > Options:")
641 logger.info(" --output= : Specify the name of the directory where the merge is done.")
642 logger.info(" This allow to do \"import NAME\" to load that merge.")
643 logger.info(" --recreate : Force to recreated the merge model even if the merge model directory already exists.")
644
646 logger.info("syntax: calculate_width PART [other particles] [OPTIONS]")
647 logger.info(" Computes the width and partial width for a set of particles")
648 logger.info(" Returns a valid param_card with this information.")
649 logger.info(" ")
650 logger.info(" PART: name of the particle you want to calculate width")
651 logger.info(" you can enter either the name or pdg code.\n")
652 logger.info(" Various options:\n")
653 logger.info(" --body_decay=X: Parameter to control the precision of the computation")
654 logger.info(" if X is an integer, we compute all channels up to X-body decay.")
655 logger.info(" if X <1, then we stop when the estimated error is lower than X.")
656 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer")
657 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.")
658 logger.info(" default: 4.0025")
659 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.")
660 logger.info(" default: precision (decimal part of the body_decay options) divided by four")
661 logger.info(" --precision_channel=X: requested numerical precision for each channel")
662 logger.info(" default: 0.01")
663 logger.info(" --path=X: path for param_card")
664 logger.info(" default: take value from the model")
665 logger.info(" --output=X: path where to write the resulting card. ")
666 logger.info(" default: overwrite input file. If no input file, write it in the model directory")
667 logger.info(" --nlo: Compute NLO width [if the model support it]")
668 logger.info("")
669 logger.info(" example: calculate_width h --body_decay=2 --output=./param_card")
670
672 logger.info("syntax: decay_diagram PART [other particles] [OPTIONS]")
673 logger.info(" Returns the amplitude required for the computation of the widths")
674 logger.info(" ")
675 logger.info(" PART: name of the particle you want to calculate width")
676 logger.info(" you can enter either the name or pdg code.\n")
677 logger.info(" Various options:\n")
678 logger.info(" --body_decay=X: Parameter to control the precision of the computation")
679 logger.info(" if X is an integer, we compute all channels up to X-body decay.")
680 logger.info(" if X <1, then we stop when the estimated error is lower than X.")
681 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer")
682 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.")
683 logger.info(" default: 4.0025")
684 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.")
685 logger.info(" default: precision (decimal part of the body_decay options) divided by four")
686 logger.info(" --precision_channel=X: requested numerical precision for each channel")
687 logger.info(" default: 0.01")
688 logger.info(" --path=X: path for param_card")
689 logger.info(" default: take value from the model")
690 logger.info(" --output=X: path where to write the resulting card. ")
691 logger.info(" default: overwrite input file. If no input file, write it in the model directory")
692 logger.info("")
693 logger.info(" example: calculate_width h --body_decay=2 --output=./param_card")
694
696 logger.info("-- define a multiparticle",'$MG:color:BLUE')
697 logger.info("Syntax: define multipart_name [=] part_name_list")
698 logger.info("Example: define p = g u u~ c c~ d d~ s s~ b b~",'$MG:color:GREEN')
699 logger.info("Special syntax: Use | for OR (used for required s-channels)")
700 logger.info("Special syntax: Use / to remove particles. Example: define q = p / g")
701
703 logger.info("-- set options for generation or output.",'$MG:color:BLUE')
704 logger.info("syntax: set <option_name> <option_value>",'$MG:color:BLACK')
705 logger.info("Possible options are: ")
706 for opts in [self._set_options[i*3:(i+1)*3] for i in \
707 range((len(self._set_options)//4)+1)]:
708 logger.info("%s"%(','.join(opts)),'$MG:color:GREEN')
709 logger.info("Details of each option:")
710 logger.info("group_subprocesses True/False/Auto: ",'$MG:color:GREEN')
711 logger.info(" > (default Auto) Smart grouping of subprocesses into ")
712 logger.info(" directories, mirroring of initial states, and ")
713 logger.info(" combination of integration channels.")
714 logger.info(" > Example: p p > j j j w+ gives 5 directories and 184 channels",'$MG:color:BLACK')
715 logger.info(" (cf. 65 directories and 1048 channels for regular output)",'$MG:color:BLACK')
716 logger.info(" > Auto means False for decay computation and True for collisions.")
717 logger.info("ignore_six_quark_processes multi_part_label",'$MG:color:GREEN')
718 logger.info(" > (default none) ignore processes with at least 6 of any")
719 logger.info(" of the quarks given in multi_part_label.")
720 logger.info(" > These processes give negligible contribution to the")
721 logger.info(" cross section but have subprocesses/channels.")
722 logger.info("stdout_level DEBUG|INFO|WARNING|ERROR|CRITICAL",'$MG:color:GREEN')
723 logger.info(" > change the default level for printed information")
724 logger.info("fortran_compiler NAME",'$MG:color:GREEN')
725 logger.info(" > (default None) Force a specific fortran compiler.")
726 logger.info(" If None, it tries first g77 and if not present gfortran")
727 logger.info(" but loop output use gfortran.")
728 logger.info("loop_optimized_output True|False",'$MG:color:GREEN')
729 logger.info(" > Exploits the open loop thechnique for considerable")
730 logger.info(" improvement.")
731 logger.info(" > CP relations among helicites are detected and the helicity")
732 logger.info(" filter has more potential.")
733 logger.info("loop_color_flows True|False",'$MG:color:GREEN')
734 logger.info(" > Only relevant for the loop optimized output.")
735 logger.info(" > Reduces the loop diagrams at the amplitude level")
736 logger.info(" rendering possible the computation of the loop amplitude")
737 logger.info(" for a fixed color flow or color configuration.")
738 logger.info(" > This option can considerably slow down the loop ME")
739 logger.info(" computation time, especially when summing over all color")
740 logger.info(" and helicity configuration, hence turned off by default.")
741 logger.info("gauge unitary|Feynman",'$MG:color:GREEN')
742 logger.info(" > (default unitary) choose the gauge of the non QCD part.")
743 logger.info(" > For loop processes, only Feynman gauge is employable.")
744 logger.info("complex_mass_scheme True|False",'$MG:color:GREEN')
745 logger.info(" > (default False) Set complex mass scheme.")
746 logger.info(" > Complex mass scheme is not yet supported for loop processes.")
747 logger.info("timeout VALUE",'$MG:color:GREEN')
748 logger.info(" > (default 20) Seconds allowed to answer questions.")
749 logger.info(" > Note that pressing tab always stops the timer.")
750 logger.info("cluster_temp_path PATH",'$MG:color:GREEN')
751 logger.info(" > (default None) [Used in Madevent Output]")
752 logger.info(" > Allow to perform the run in PATH directory")
753 logger.info(" > This allow to not run on the central disk. ")
754 logger.info(" > This is not used by condor cluster (since condor has")
755 logger.info(" its own way to prevent it).")
756 logger.info("mg5amc_py8_interface_path PATH",'$MG:color:GREEN')
757 logger.info(" > Necessary when showering events with Pythia8 from Madevent.")
758 logger.info("OLP ProgramName",'$MG:color:GREEN')
759 logger.info(" > (default 'MadLoop') [Used for virtual generation]")
760 logger.info(" > Chooses what One-Loop Program to use for the virtual")
761 logger.info(" > matrix element generation via the BLAH accord.")
762 logger.info("output_dependencies <mode>",'$MG:color:GREEN')
763 logger.info(" > (default 'external') [Use for NLO outputs]")
764 logger.info(" > Choses how the external dependences (such as CutTools)")
765 logger.info(" > of NLO outputs are handled. Possible values are:")
766 logger.info(" o external: Some of the libraries the output depends")
767 logger.info(" on are links to their installation in MG5 root dir.")
768 logger.info(" o internal: All libraries the output depends on are")
769 logger.info(" copied and compiled locally in the output directory.")
770 logger.info(" o environment_paths: The location of all libraries the ")
771 logger.info(" output depends on should be found in your env. paths.")
772
784 """ The Series of help routine for the MadGraphCmd"""
785
787 """a class for read/write errors"""
788
790 """check the validity of line
791 syntax: add process PROCESS | add model MODELNAME
792 """
793
794 if len(args) < 2:
795 self.help_add()
796 raise self.InvalidCmd('\"add\" requires at least two arguments')
797
798 if args[0] not in ['model', 'process']:
799 raise self.InvalidCmd('\"add\" requires the argument \"process\" or \"model\"')
800
801 if args[0] == 'process':
802 return self.check_generate(args)
803
804 if args[0] == 'model':
805 pass
806
807
809 """check the validity of line
810 syntax: define multipart_name [ part_name_list ]
811 """
812
813 if len(args) < 2:
814 self.help_define()
815 raise self.InvalidCmd('\"define\" command requires at least two arguments')
816
817 if args[1] == '=':
818 del args[1]
819 if len(args) < 2:
820 self.help_define()
821 raise self.InvalidCmd('\"define\" command requires at least one particles name after \"=\"')
822
823 if '=' in args:
824 self.help_define()
825 raise self.InvalidCmd('\"define\" command requires symbols \"=\" at the second position')
826
827 if not self._curr_model:
828 logger.info('No model currently active. Try with the Standard Model')
829 self.do_import('model sm')
830
831 if self._curr_model['particles'].find_name(args[0]):
832 raise self.InvalidCmd("label %s is a particle name in this model\n\
833 Please retry with another name." % args[0])
834
836 """check the validity of line
837 syntax: display XXXXX
838 """
839
840 if len(args) < 1:
841 self.help_display()
842 raise self.InvalidCmd, 'display requires an argument specifying what to display'
843 if args[0] not in self._display_opts:
844 self.help_display()
845 raise self.InvalidCmd, 'Invalid arguments for display command: %s' % args[0]
846
847 if not self._curr_model:
848 raise self.InvalidCmd("No model currently active, please import a model!")
849
850
851 if (args[0] in ['processes', 'diagrams'] and not self._curr_amps and not self._fks_multi_proc):
852 raise self.InvalidCmd("No process generated, please generate a process!")
853 if args[0] == 'checks' and not self._comparisons and not self._cms_checks:
854 raise self.InvalidCmd("No check results to display.")
855
856 if args[0] == 'variable' and len(args) !=2:
857 raise self.InvalidCmd('variable need a variable name')
858
859
861 """check the validity of line
862 syntax: draw DIRPATH [option=value]
863 """
864
865 if len(args) < 1:
866 args.append('/tmp')
867
868 if not self._curr_amps:
869 raise self.InvalidCmd("No process generated, please generate a process!")
870
871 if not os.path.isdir(args[0]):
872 raise self.InvalidCmd( "%s is not a valid directory for export file" % args[0])
873
875 """check the validity of args"""
876
877 if not self._curr_model:
878 raise self.InvalidCmd("No model currently active, please import a model!")
879
880 if self._model_v4_path:
881 raise self.InvalidCmd(\
882 "\"check\" not possible for v4 models")
883
884 if len(args) < 2 and not args[0].lower().endswith('options'):
885 self.help_check()
886 raise self.InvalidCmd("\"check\" requires a process.")
887
888 if args[0] not in self._check_opts and \
889 not args[0].lower().endswith('options'):
890 args.insert(0, 'full')
891
892 param_card = None
893 if args[0] not in ['stability','profile','timing'] and \
894 len(args)>1 and os.path.isfile(args[1]):
895 param_card = args.pop(1)
896
897 if len(args)>1:
898 if args[1] != "-reuse":
899 args.insert(1, '-no_reuse')
900 else:
901 args.append('-no_reuse')
902
903 if args[0] in ['timing'] and len(args)>2 and os.path.isfile(args[2]):
904 param_card = args.pop(2)
905 if args[0] in ['stability', 'profile'] and len(args)>1:
906
907
908
909 try:
910 int(args[2])
911 except ValueError:
912 args.insert(2, '100')
913
914 if args[0] in ['stability', 'profile'] and os.path.isfile(args[3]):
915 param_card = args.pop(3)
916 if any([',' in elem for elem in args if not elem.startswith('--')]):
917 raise self.InvalidCmd('Decay chains not allowed in check')
918
919 user_options = {'--energy':'1000','--split_orders':'-1',
920 '--reduction':'1|2|3|4|5|6','--CTModeRun':'-1',
921 '--helicity':'-1','--seed':'-1','--collier_cache':'-1',
922 '--collier_req_acc':'auto',
923 '--collier_internal_stability_test':'False',
924 '--collier_mode':'1'}
925
926 if args[0] in ['cms'] or args[0].lower()=='cmsoptions':
927
928 user_options['--energy']='5000'
929
930
931
932
933 parameters = ['aewm1->10.0/lambdaCMS','as->0.1*lambdaCMS']
934 user_options['--cms']='QED&QCD,'+'&'.join(parameters)
935
936
937 user_options['--recompute_width']='auto'
938
939 user_options['--offshellness']='10.0'
940
941
942
943
944
945
946 user_options['--lambdaCMS']='(1.0e-6,5)'
947
948 user_options['--seed']=666
949
950 user_options['--analyze']='None'
951
952 user_options['--show_plot']='True'
953
954 user_options['--report']='concise'
955
956
957
958
959 user_options['--diff_lambda_power']='1'
960
961 user_options['--lambda_plot_range']='[-1.0,-1.0]'
962
963
964 user_options['--loop_filter']='None'
965
966
967
968 user_options['--tweak']='default()'
969
970 user_options['--name']='auto'
971
972 user_options['--resonances']='1'
973
974 for arg in args[:]:
975 if arg.startswith('--') and '=' in arg:
976 parsed = arg.split('=')
977 key, value = parsed[0],'='.join(parsed[1:])
978 if key not in user_options:
979 raise self.InvalidCmd, "unknown option %s" % key
980 user_options[key] = value
981 args.remove(arg)
982
983
984
985 if not (args[0]=='cms' and '--analyze' in user_options and \
986 user_options['--analyze']!='None') and not \
987 args[0].lower().endswith('options'):
988
989 self.check_process_format(" ".join(args[1:]))
990
991 for option, value in user_options.items():
992 args.append('%s=%s'%(option,value))
993
994 return param_card
995
1020
1021
1060
1061
1074
1075
1076
1122
1123
1124
1126 """check that the install command is valid"""
1127
1128
1129 install_options = {'options_for_HEPToolsInstaller':[],
1130 'update_options':[]}
1131 hidden_prog = ['Delphes2', 'pythia-pgs']
1132
1133 if len(args) < 1:
1134 self.help_install()
1135 raise self.InvalidCmd('install command require at least one argument')
1136
1137 if len(args) > 1:
1138 for arg in args[1:]:
1139 try:
1140 option, value = arg.split('=')
1141 except ValueError:
1142 option = arg
1143 value = None
1144
1145 if args[0]=='update':
1146 if value is None:
1147 install_options['update_options'].append(option)
1148 else:
1149 install_options['update_options'].append('='.join([option,value]))
1150 else:
1151
1152
1153 install_options['options_for_HEPToolsInstaller'].append(arg)
1154
1155
1156 args = args[:1]
1157
1158 if args[0] not in self._install_opts + hidden_prog:
1159 if not args[0].startswith('td'):
1160 self.help_install()
1161 raise self.InvalidCmd('Not recognize program %s ' % args[0])
1162
1163 if args[0] in ["ExRootAnalysis", "Delphes", "Delphes2"]:
1164 if not misc.which('root'):
1165 raise self.InvalidCmd(
1166 '''In order to install ExRootAnalysis, you need to install Root on your computer first.
1167 please follow information on http://root.cern.ch/drupal/content/downloading-root''')
1168 if 'ROOTSYS' not in os.environ:
1169 raise self.InvalidCmd(
1170 '''The environment variable ROOTSYS is not configured.
1171 You can set it by adding the following lines in your .bashrc [.bash_profile for mac]:
1172 export ROOTSYS=%s
1173 export PATH=$PATH:$ROOTSYS/bin
1174 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ROOTSYS/lib
1175 export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$ROOTSYS/lib
1176 This will take effect only in a NEW terminal
1177 ''' % os.path.realpath(pjoin(misc.which('root'), \
1178 os.path.pardir, os.path.pardir)))
1179
1180 return install_options
1181
1183 """check the validity of the line"""
1184
1185
1186 if not( 0 <= int(options.cluster) <= 2):
1187 return self.InvalidCmd, 'cluster mode should be between 0 and 2'
1188
1189 if not args:
1190 if self._done_export:
1191 mode = self.find_output_type(self._done_export[0])
1192 if (self._done_export[1] == 'plugin' and mode not in self._export_formats):
1193 args.append(mode)
1194 args.append(self._done_export[0])
1195 elif self._done_export[1].startswith(mode):
1196 args.append(self._done_export[1])
1197 args.append(self._done_export[0])
1198 else:
1199 raise self.InvalidCmd, \
1200 '%s not valid directory for launch' % self._done_export[0]
1201 return
1202 else:
1203 logger.warning('output command missing, run it automatically (with default argument)')
1204 self.do_output('')
1205 logger.warning('output done: running launch')
1206 return self.check_launch(args, options)
1207
1208 if len(args) != 1:
1209 self.help_launch()
1210 return self.InvalidCmd, 'Invalid Syntax: Too many argument'
1211
1212
1213 if os.path.isdir(args[0]):
1214 path = os.path.realpath(args[0])
1215 elif os.path.isdir(pjoin(MG5DIR,args[0])):
1216 path = pjoin(MG5DIR,args[0])
1217 elif MG4DIR and os.path.isdir(pjoin(MG4DIR,args[0])):
1218 path = pjoin(MG4DIR,args[0])
1219 else:
1220 raise self.InvalidCmd, '%s is not a valid directory' % args[0]
1221
1222 mode = self.find_output_type(path)
1223
1224 args[0] = mode
1225 args.append(path)
1226
1227 self._done_export = [path, mode]
1228
1229
1231 """ identify the import type of a given path
1232 valid output: model/model_v4/proc_v4/command"""
1233
1234 possibility = [pjoin(MG5DIR,'models',path), \
1235 pjoin(MG5DIR,'models',path+'_v4'), path]
1236 if '-' in path:
1237 name = path.rsplit('-',1)[0]
1238 possibility = [pjoin(MG5DIR,'models',name), name] + possibility
1239
1240 for name in possibility:
1241 if os.path.isdir(name):
1242 if os.path.exists(pjoin(name,'particles.py')):
1243 return 'model'
1244 elif os.path.exists(pjoin(name,'particles.dat')):
1245 return 'model_v4'
1246
1247
1248 if os.path.isfile(path):
1249 text = open(path).read()
1250 pat = re.compile('(Begin process|<MGVERSION>)', re.I)
1251 matches = pat.findall(text)
1252 if not matches:
1253 return 'command'
1254 elif len(matches) > 1:
1255 return 'banner'
1256 elif matches[0].lower() == 'begin process':
1257 return 'proc_v4'
1258 else:
1259 return 'banner'
1260 else:
1261 return 'proc_v4'
1262
1263
1264
1265
1267 """ identify the type of output of a given directory:
1268 valid output: madevent/standalone/standalone_cpp"""
1269
1270 card_path = pjoin(path,'Cards')
1271 bin_path = pjoin(path,'bin')
1272 src_path = pjoin(path,'src')
1273 include_path = pjoin(path,'include')
1274 subproc_path = pjoin(path,'SubProcesses')
1275 mw_path = pjoin(path,'Source','MadWeight')
1276
1277 if os.path.isfile(pjoin(include_path, 'Pythia.h')) or \
1278 os.path.isfile(pjoin(include_path, 'Pythia8', 'Pythia.h')):
1279 return 'pythia8'
1280 elif not os.path.isdir(os.path.join(path, 'SubProcesses')):
1281 raise self.InvalidCmd, '%s : Not a valid directory' % path
1282
1283 if os.path.isdir(src_path):
1284 return 'standalone_cpp'
1285 elif os.path.isdir(mw_path):
1286 return 'madweight'
1287 elif os.path.isfile(pjoin(bin_path,'madevent')):
1288 return 'madevent'
1289 elif os.path.isfile(pjoin(bin_path,'aMCatNLO')):
1290 return 'aMC@NLO'
1291 elif os.path.isdir(card_path):
1292 return 'standalone'
1293
1294 raise self.InvalidCmd, '%s : Not a valid directory' % path
1295
1302
1304 """check the validity of the line"""
1305
1306
1307 if len(args) >1 :
1308 self.help_customize_model()
1309 raise self.InvalidCmd('No argument expected for this command')
1310
1311 if len(args):
1312 if not args[0].startswith('--save='):
1313 self.help_customize_model()
1314 raise self.InvalidCmd('Wrong argument for this command')
1315 if '-' in args[0][6:]:
1316 raise self.InvalidCmd('The name given in save options can\'t contain \'-\' symbol.')
1317
1318 if self._model_v4_path:
1319 raise self.InvalidCmd('Restriction of Model is not supported by v4 model.')
1320
1321
1323 """ check the validity of the line"""
1324
1325 if len(args) == 0:
1326 args.append('options')
1327
1328 if args[0] not in self._save_opts and args[0] != 'global':
1329 self.help_save()
1330 raise self.InvalidCmd('wrong \"save\" format')
1331 elif args[0] == 'global':
1332 args.insert(0, 'options')
1333
1334 if args[0] != 'options' and len(args) != 2:
1335 self.help_save()
1336 raise self.InvalidCmd('wrong \"save\" format')
1337 elif args[0] != 'options' and len(args) == 2:
1338 basename = os.path.dirname(args[1])
1339 if not os.path.exists(basename):
1340 raise self.InvalidCmd('%s is not a valid path, please retry' % \
1341 args[1])
1342
1343 if args[0] == 'options':
1344 has_path = None
1345 for arg in args[1:]:
1346 if arg in ['--auto', '--all'] or arg in self.options:
1347 continue
1348 elif arg.startswith('--'):
1349 raise self.InvalidCmd('unknow command for \'save options\'')
1350 elif arg == 'global':
1351 if os.environ.has_key('HOME'):
1352 args.remove('global')
1353 args.insert(1,pjoin(os.environ['HOME'],'.mg5','mg5_configuration.txt'))
1354 has_path = True
1355 else:
1356 basename = os.path.dirname(arg)
1357 if not os.path.exists(basename):
1358 raise self.InvalidCmd('%s is not a valid path, please retry' % \
1359 arg)
1360 elif has_path:
1361 raise self.InvalidCmd('only one path is allowed')
1362 else:
1363 args.remove(arg)
1364 args.insert(1, arg)
1365 has_path = True
1366 if not has_path:
1367 args.insert(1, pjoin(MG5DIR,'input','mg5_configuration.txt'))
1368
1369
1371 """ check the validity of the line"""
1372
1373 if len(args) == 1 and args[0] in ['complex_mass_scheme',\
1374 'loop_optimized_output',\
1375 'loop_color_flows',\
1376 'low_mem_multicore_nlo_generation']:
1377 args.append('True')
1378
1379 if len(args) > 2 and '=' == args[1]:
1380 args.pop(1)
1381
1382 if len(args) < 2:
1383 self.help_set()
1384 raise self.InvalidCmd('set needs an option and an argument')
1385
1386 if args[1] == 'default':
1387 if args[0] in self.options_configuration:
1388 default = self.options_configuration[args[0]]
1389 elif args[0] in self.options_madgraph:
1390 default = self.options_madgraph[args[0]]
1391 elif args[0] in self.options_madevent:
1392 default = self.options_madevent[args[0]]
1393 else:
1394 raise self.InvalidCmd('%s doesn\'t have a valid default value' % args[0])
1395 if log:
1396 logger.info('Pass parameter %s to it\'s default value: %s' %
1397 (args[0], default))
1398 args[1] = str(default)
1399
1400 if args[0] not in self._set_options:
1401 if not args[0] in self.options and not args[0] in self.options:
1402 self.help_set()
1403 raise self.InvalidCmd('Possible options for set are %s' % \
1404 self._set_options)
1405
1406 if args[0] in ['group_subprocesses']:
1407 if args[1] not in ['False', 'True', 'Auto']:
1408 raise self.InvalidCmd('%s needs argument False, True or Auto' % \
1409 args[0])
1410 if args[0] in ['ignore_six_quark_processes']:
1411 if args[1] not in self._multiparticles.keys() and args[1] != 'False':
1412 raise self.InvalidCmd('ignore_six_quark_processes needs ' + \
1413 'a multiparticle name as argument')
1414
1415 if args[0] in ['stdout_level']:
1416 if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] and \
1417 not args[1].isdigit():
1418 raise self.InvalidCmd('output_level needs ' + \
1419 'a valid level')
1420
1421 if args[0] in ['timeout', 'max_npoint_for_channel']:
1422 if not args[1].isdigit():
1423 raise self.InvalidCmd('%s values should be a integer' % args[0])
1424
1425 if args[0] in ['loop_optimized_output', 'loop_color_flows', 'low_mem_multicore_nlo_generation']:
1426 try:
1427 args[1] = banner_module.ConfigFile.format_variable(args[1], bool, args[0])
1428 except Exception:
1429 raise self.InvalidCmd('%s needs argument True or False'%args[0])
1430
1431 if args[0] in ['gauge']:
1432 if args[1] not in ['unitary','Feynman']:
1433 raise self.InvalidCmd('gauge needs argument unitary or Feynman.')
1434
1435 if args[0] in ['timeout']:
1436 if not args[1].isdigit():
1437 raise self.InvalidCmd('timeout values should be a integer')
1438
1439 if args[0] in ['OLP']:
1440 if args[1] not in MadGraphCmd._OLP_supported:
1441 raise self.InvalidCmd('OLP value should be one of %s'\
1442 %str(MadGraphCmd._OLP_supported))
1443
1444 if args[0].lower() in ['ewscheme']:
1445 if not self._curr_model:
1446 raise self.InvalidCmd("ewscheme acts on the current model please load one first.")
1447 if args[1] not in ['external']:
1448 raise self.InvalidCmd('Only valid ewscheme is "external". To restore default, please re-import the model.')
1449
1450 if args[0] in ['output_dependencies']:
1451 if args[1] not in MadGraphCmd._output_dependencies_supported:
1452 raise self.InvalidCmd('output_dependencies value should be one of %s'\
1453 %str(MadGraphCmd._output_dependencies_supported))
1454
1456 """ check the validity of the line """
1457
1458 if len(args) != 1:
1459 self.help_open()
1460 raise self.InvalidCmd('OPEN command requires exactly one argument')
1461
1462 if args[0].startswith('./'):
1463 if not os.path.isfile(args[0]):
1464 raise self.InvalidCmd('%s: not such file' % args[0])
1465 return True
1466
1467
1468 if not self._done_export:
1469 if not os.path.isfile(args[0]):
1470 self.help_open()
1471 raise self.InvalidCmd('No command \"output\" or \"launch\" used. Impossible to associate this name to a file')
1472 else:
1473 return True
1474
1475 path = self._done_export[0]
1476 if os.path.isfile(pjoin(path,args[0])):
1477 args[0] = pjoin(path,args[0])
1478 elif os.path.isfile(pjoin(path,'Cards',args[0])):
1479 args[0] = pjoin(path,'Cards',args[0])
1480 elif os.path.isfile(pjoin(path,'HTML',args[0])):
1481 args[0] = pjoin(path,'HTML',args[0])
1482
1483 elif '_card.dat' in args[0]:
1484 name = args[0].replace('_card.dat','_card_default.dat')
1485 if os.path.isfile(pjoin(path,'Cards', name)):
1486 files.cp(path + '/Cards/' + name, path + '/Cards/'+ args[0])
1487 args[0] = pjoin(path,'Cards', args[0])
1488 else:
1489 raise self.InvalidCmd('No default path for this file')
1490 elif not os.path.isfile(args[0]):
1491 raise self.InvalidCmd('No default path for this file')
1492
1493
1495 """ check the validity of the line"""
1496
1497
1498 if args and args[0] in self._export_formats:
1499 self._export_format = args.pop(0)
1500 elif args:
1501
1502 for plugpath in self.plugin_path:
1503 plugindirname = os.path.basename(plugpath)
1504 for plug in os.listdir(plugpath):
1505 if os.path.exists(pjoin(plugpath, plug, '__init__.py')):
1506 try:
1507 __import__('%s.%s' % (plugindirname,plug))
1508 except Exception, error:
1509 logger.warning("error detected in plugin: %s.", plug)
1510 logger.warning("%s", error)
1511 continue
1512 plugin = sys.modules['%s.%s' % (plugindirname,plug)]
1513 if hasattr(plugin, 'new_output'):
1514 if not misc.is_plugin_supported(plugin):
1515 continue
1516 if args[0] in plugin.new_output:
1517 self._export_format = 'plugin'
1518 self._export_plugin = plugin.new_output[args[0]]
1519 logger.info('Output will be done with PLUGIN: %s' % plug ,'$MG:color:BLACK')
1520 args.pop(0)
1521 break
1522 else:
1523 continue
1524 break
1525 else:
1526 self._export_format = default
1527 else:
1528 self._export_format = default
1529
1530 if not self._curr_model:
1531 text = 'No model found. Please import a model first and then retry.'
1532 raise self.InvalidCmd(text)
1533
1534 if self._model_v4_path and \
1535 (self._export_format not in self._v4_export_formats):
1536 text = " The Model imported (MG4 format) does not contain enough\n "
1537 text += " information for this type of output. In order to create\n"
1538 text += " output for " + args[0] + ", you have to use a UFO model.\n"
1539 text += " Those model can be imported with MG5> import model NAME."
1540 logger.warning(text)
1541 raise self.InvalidCmd('')
1542
1543 if self._export_format == 'aloha':
1544 return
1545
1546
1547 if not self._curr_amps:
1548 text = 'No processes generated. Please generate a process first.'
1549 raise self.InvalidCmd(text)
1550
1551 if args and args[0][0] != '-':
1552
1553 path = args.pop(0)
1554 forbiden_chars = ['>','<',';','&']
1555 for char in forbiden_chars:
1556 if char in path:
1557 raise self.InvalidCmd('%s is not allowed in the output path' % char)
1558
1559 if path == 'auto' and self._export_format in \
1560 ['madevent', 'standalone', 'standalone_cpp', 'matchbox_cpp', 'madweight',
1561 'matchbox', 'plugin']:
1562 self.get_default_path()
1563 if '-noclean' not in args and os.path.exists(self._export_dir):
1564 args.append('-noclean')
1565 elif path != 'auto':
1566 self._export_dir = path
1567 elif path == 'auto':
1568 if self.options['pythia8_path']:
1569 self._export_dir = self.options['pythia8_path']
1570 else:
1571 self._export_dir = '.'
1572 else:
1573 if self._export_format != 'pythia8':
1574
1575 self.get_default_path()
1576 if '-noclean' not in args and os.path.exists(self._export_dir):
1577 args.append('-noclean')
1578
1579 else:
1580 if self.options['pythia8_path']:
1581 self._export_dir = self.options['pythia8_path']
1582 else:
1583 self._export_dir = '.'
1584
1585 self._export_dir = os.path.realpath(self._export_dir)
1586
1587
1589 """ check and format calculate decay width:
1590 Expected format: NAME [other names] [--options]
1591 # fill the options if not present.
1592 # NAME can be either (anti-)particle name, multiparticle, pid
1593 """
1594
1595 if len(args)<1:
1596 self.help_compute_widths()
1597 raise self.InvalidCmd('''compute_widths requires at least the name of one particle.
1598 If you want to compute the width of all particles, type \'compute_widths all\'''')
1599
1600 particles = set()
1601 options = {'path':None, 'output':None,
1602 'min_br':None, 'body_decay':4.0025, 'precision_channel':0.01,
1603 'nlo':False}
1604
1605
1606 for i,arg in enumerate(args):
1607 if arg.startswith('--'):
1608 if arg.startswith('--nlo'):
1609 options['nlo'] =True
1610 continue
1611 elif not '=' in arg:
1612 raise self.InvalidCmd('Options required an equal (and then the value)')
1613 arg, value = arg.split('=')
1614 if arg[2:] not in options:
1615 raise self.InvalidCmd('%s not valid options' % arg)
1616 options[arg[2:]] = value
1617 continue
1618
1619 if arg.isdigit():
1620 p = self._curr_model.get_particle(int(arg))
1621 if not p:
1622 raise self.InvalidCmd('Model doesn\'t have pid %s for any particle' % arg)
1623 particles.add(abs(int(arg)))
1624 elif arg in self._multiparticles:
1625 particles.update([abs(id) for id in self._multiparticles[args[0]]])
1626 else:
1627 if not self._curr_model['case_sensitive']:
1628 arg = arg.lower()
1629 for p in self._curr_model['particles']:
1630 if p['name'] == arg or p['antiname'] == arg:
1631 particles.add(abs(p.get_pdg_code()))
1632 break
1633 else:
1634 if arg == 'all':
1635
1636 particles.update([abs(p.get_pdg_code())
1637 for p in self._curr_model['particles']])
1638 else:
1639 raise self.InvalidCmd('%s invalid particle name' % arg)
1640
1641 if options['path'] and not os.path.isfile(options['path']):
1642
1643 if os.path.exists(pjoin(MG5DIR, options['path'])):
1644 options['path'] = pjoin(MG5DIR, options['path'])
1645 elif self._model_v4_path and os.path.exists(pjoin(self._model_v4_path, options['path'])):
1646 options['path'] = pjoin(self._curr_model_v4_path, options['path'])
1647 elif os.path.exists(pjoin(self._curr_model.path, options['path'])):
1648 options['path'] = pjoin(self._curr_model.path, options['path'])
1649
1650 if os.path.isdir(options['path']) and os.path.isfile(pjoin(options['path'], 'param_card.dat')):
1651 options['path'] = pjoin(options['path'], 'param_card.dat')
1652 elif not os.path.isfile(options['path']):
1653 raise self.InvalidCmd('%s is not a valid path' % args[2])
1654
1655 if madevent_interface.MadEventCmd.detect_card_type(options['path']) != 'param_card.dat':
1656 raise self.InvalidCmd('%s should be a path to a param_card' % options['path'])
1657
1658 if not options['path']:
1659 param_card_text = self._curr_model.write_param_card()
1660 if not options['output']:
1661 dirpath = self._curr_model.get('modelpath')
1662 options['path'] = pjoin(dirpath, 'param_card.dat')
1663 else:
1664 options['path'] = options['output']
1665 ff = open(options['path'],'w')
1666 ff.write(param_card_text)
1667 ff.close()
1668 if not options['output']:
1669 options['output'] = options['path']
1670
1671 if not options['min_br']:
1672 options['min_br'] = (float(options['body_decay']) % 1) / 5
1673 return particles, options
1674
1675
1676 check_decay_diagram = check_compute_widths
1677
1679 """Set self._export_dir to the default (\'auto\') path"""
1680
1681 if self._export_format in ['madevent', 'standalone']:
1682
1683
1684 if 'TemplateVersion.txt' in os.listdir('.'):
1685
1686 self._export_dir = os.path.realpath('.')
1687 return
1688 elif 'TemplateVersion.txt' in os.listdir('..'):
1689
1690 self._export_dir = os.path.realpath('..')
1691 return
1692 elif self.stdin != sys.stdin:
1693
1694 input_path = os.path.realpath(self.stdin.name).split(os.path.sep)
1695 print "Not standard stdin, use input path"
1696 if input_path[-2] == 'Cards':
1697 self._export_dir = os.path.sep.join(input_path[:-2])
1698 if 'TemplateVersion.txt' in self._export_dir:
1699 return
1700
1701
1702 if self._export_format == 'NLO':
1703 name_dir = lambda i: 'PROCNLO_%s_%s' % \
1704 (self._curr_model['name'], i)
1705 auto_path = lambda i: pjoin(self.writing_dir,
1706 name_dir(i))
1707 elif self._export_format.startswith('madevent'):
1708 name_dir = lambda i: 'PROC_%s_%s' % \
1709 (self._curr_model['name'], i)
1710 auto_path = lambda i: pjoin(self.writing_dir,
1711 name_dir(i))
1712 elif self._export_format.startswith('standalone'):
1713 name_dir = lambda i: 'PROC_SA_%s_%s' % \
1714 (self._curr_model['name'], i)
1715 auto_path = lambda i: pjoin(self.writing_dir,
1716 name_dir(i))
1717 elif self._export_format == 'madweight':
1718 name_dir = lambda i: 'PROC_MW_%s_%s' % \
1719 (self._curr_model['name'], i)
1720 auto_path = lambda i: pjoin(self.writing_dir,
1721 name_dir(i))
1722 elif self._export_format == 'standalone_cpp':
1723 name_dir = lambda i: 'PROC_SA_CPP_%s_%s' % \
1724 (self._curr_model['name'], i)
1725 auto_path = lambda i: pjoin(self.writing_dir,
1726 name_dir(i))
1727 elif self._export_format in ['matchbox_cpp', 'matchbox']:
1728 name_dir = lambda i: 'PROC_MATCHBOX_%s_%s' % \
1729 (self._curr_model['name'], i)
1730 auto_path = lambda i: pjoin(self.writing_dir,
1731 name_dir(i))
1732 elif self._export_format in ['plugin']:
1733 name_dir = lambda i: 'PROC_PLUGIN_%s_%s' % \
1734 (self._curr_model['name'], i)
1735 auto_path = lambda i: pjoin(self.writing_dir,
1736 name_dir(i))
1737 elif self._export_format == 'pythia8':
1738 if self.options['pythia8_path']:
1739 self._export_dir = self.options['pythia8_path']
1740 else:
1741 self._export_dir = '.'
1742 return
1743 else:
1744 self._export_dir = '.'
1745 return
1746 for i in range(500):
1747 if os.path.isdir(auto_path(i)):
1748 continue
1749 else:
1750 self._export_dir = auto_path(i)
1751 break
1752 if not self._export_dir:
1753 raise self.InvalidCmd('Can\'t use auto path,' + \
1754 'more than 500 dirs already')
1755
1761 """ Check the validity of input line for web entry
1762 (no explicit path authorized)"""
1763
1765 """class for WebRestriction"""
1766
1768 """check the validity of line
1769 syntax: draw FILEPATH [option=value]
1770 """
1771 raise self.WebRestriction('direct call to draw is forbidden on the web')
1772
1780
1782 """ Not authorize for the Web"""
1783
1784 raise self.WebRestriction('Check call is forbidden on the web')
1785
1786 - def check_history(self, args):
1787 """check the validity of line
1788 No Path authorize for the Web"""
1789
1790 CheckValidForCmd.check_history(self, args)
1791
1792 if len(args) == 2 and args[1] not in ['.', 'clean']:
1793 raise self.WebRestriction('Path can\'t be specify on the web.')
1794
1795
1811
1813 """ No possibility to install new software on the web """
1814 if args == ['update','--mode=mg5_start']:
1815 return
1816
1817 raise self.WebRestriction('Impossible to install program on the cluster')
1818
1820 """ check the validity of the line
1821 No Path authorize for the Web"""
1822
1823 CheckValidForCmd.check_load(self, args)
1824
1825 if len(args) == 2:
1826 if args[0] != 'model':
1827 raise self.WebRestriction('only model can be loaded online')
1828 if 'model.pkl' not in args[1]:
1829 raise self.WebRestriction('not valid pkl file: wrong name')
1830 if not os.path.realpath(args[1]).startswith(pjoin(MG4DIR, \
1831 'Models')):
1832 raise self.WebRestriction('Wrong path to load model')
1833
1835 """ not authorize on web"""
1836 raise self.WebRestriction('\"save\" command not authorize online')
1837
1839 """ not authorize on web"""
1840 raise self.WebRestriction('\"open\" command not authorize online')
1841
1843 """ check the validity of the line"""
1844
1845
1846 CheckValidForCmd.check_output(self, args, default=default)
1847 args[:] = ['.', '-f']
1848
1849 self._export_dir = os.path.realpath(os.getcwd())
1850
1851 if 'madevent' != self._export_format:
1852 raise self.WebRestriction, 'only available output format is madevent (at current stage)'
1853
1858 """ The Series of help routine for the MadGraphCmd"""
1859
1861 """ complete the nlo settings within square brackets. It uses the
1862 allowed_loop_mode for the proposed mode if specified, otherwise, it
1863 uses self._nlo_modes_for_completion"""
1864
1865
1866
1867
1868 nlo_modes = allowed_loop_mode if not allowed_loop_mode is None else \
1869 self._nlo_modes_for_completion
1870 if isinstance(self._curr_model,loop_base_objects.LoopModel):
1871 pert_couplings_allowed = ['all']+self._curr_model['perturbation_couplings']
1872 else:
1873 pert_couplings_allowed = []
1874 if self._curr_model.get('name').startswith('sm'):
1875 pert_couplings_allowed = pert_couplings_allowed + ['QCD']
1876
1877 loop_specs = line[line.index('[')+1:]
1878 try:
1879 loop_orders = loop_specs[loop_specs.index('=')+1:]
1880 except ValueError:
1881 loop_orders = loop_specs
1882 possibilities = []
1883 possible_orders = [order for order in pert_couplings_allowed if \
1884 order not in loop_orders]
1885
1886
1887 single_completion = ''
1888 if len(nlo_modes)==1:
1889 single_completion = '%s= '%nlo_modes[0]
1890 if len(possible_orders)==1:
1891 single_completion = single_completion + possible_orders[0] + ' ] '
1892
1893 if text.endswith('['):
1894 if single_completion != '':
1895 return self.list_completion(text, ['[ '+single_completion])
1896 else:
1897 return self.list_completion(text,['[ '])
1898
1899 if text.endswith('='):
1900 return self.list_completion(text,[' '])
1901
1902 if args[-1]=='[':
1903 possibilities = possibilities + ['%s= '%mode for mode in nlo_modes]
1904 if single_completion != '':
1905 return self.list_completion(text, [single_completion])
1906 else:
1907 if len(possible_orders)==1:
1908 return self.list_completion(text, [poss+' %s ] '%\
1909 possible_orders[0] for poss in possibilities])
1910 return self.list_completion(text, possibilities)
1911
1912 if len(possible_orders)==1:
1913 possibilities.append(possible_orders[0]+' ] ')
1914 else:
1915 possibilities.extend(possible_orders)
1916 if any([(order in loop_orders) for order in pert_couplings_allowed]):
1917 possibilities.append(']')
1918 return self.list_completion(text, possibilities)
1919
1920 - def model_completion(self, text, process, line, categories = True, \
1921 allowed_loop_mode = None,
1922 formatting=True):
1923 """ complete the line with model information. If categories is True,
1924 it will use completion with categories. If allowed_loop_mode is
1925 specified, it will only complete with these loop modes."""
1926
1927
1928
1929 args = self.split_arg(process)
1930 if len(args) > 2 and '>' in line and '[' in line and not ']' in line:
1931 return self.nlo_completion(args,text,line, allowed_loop_mode = \
1932 allowed_loop_mode)
1933
1934 while ',' in process:
1935 process = process[process.index(',')+1:]
1936 args = self.split_arg(process)
1937 couplings = []
1938
1939
1940 if len(args) > 1 and args[-1]=='@':
1941 return
1942
1943
1944
1945 if isinstance(self._curr_model,loop_base_objects.LoopModel):
1946 pert_couplings_allowed = ['all'] + self._curr_model['perturbation_couplings']
1947 else:
1948 pert_couplings_allowed = []
1949 if self._curr_model.get('name').startswith('sm'):
1950 pert_couplings_allowed = pert_couplings_allowed + ['QCD']
1951
1952
1953 particles = list(set(self._particle_names + self._multiparticles.keys()))
1954 n_part_entered = len([1 for a in args if a in particles])
1955
1956
1957 if n_part_entered == 2 and args[-1] != '>':
1958 return self.list_completion(text, '>')
1959
1960
1961 syntax = []
1962 couplings = []
1963 if len(args) > 0 and args[-1] != '>' and n_part_entered > 0:
1964 syntax.append('>')
1965 if '>' in args and args.index('>') < len(args) - 1:
1966 couplings.extend(sum([[c+"<=", c+"==", c+">",c+'^2<=',c+'^2==',c+'^2>' ] for c in \
1967 self._couplings+['WEIGHTED']],[]))
1968 syntax.extend(['@','$','/','>',','])
1969 if '[' not in line and ',' not in line and len(pert_couplings_allowed)>0:
1970 syntax.append('[')
1971
1972
1973
1974 if '[' in line:
1975 syntax = []
1976 particles = []
1977
1978 couplings.append('@')
1979
1980 if not categories:
1981
1982
1983
1984
1985
1986 return self.list_completion(text, particles+syntax+couplings)
1987 else:
1988
1989 poss_particles = self.list_completion(text, particles)
1990 poss_syntax = self.list_completion(text, syntax)
1991 poss_couplings = self.list_completion(text, couplings)
1992 possibilities = {}
1993 if poss_particles != []: possibilities['Particles']=poss_particles
1994 if poss_syntax != []: possibilities['Syntax']=poss_syntax
1995 if poss_couplings != []: possibilities['Coupling orders']=poss_couplings
1996 if len(possibilities.keys())==1:
1997 return self.list_completion(text, possibilities.values()[0])
1998 else:
1999 return self.deal_multiple_categories(possibilities, formatting)
2000
2002 "Complete the generate command"
2003
2004
2005
2006 args = self.split_arg(line[0:begidx])
2007
2008 valid_sqso_operators=['==','<=','>']
2009
2010 if any(line.endswith('^2 %s '%op) for op in valid_sqso_operators):
2011 return
2012 if args[-1].endswith('^2'):
2013 return self.list_completion(text,valid_sqso_operators)
2014 match_op = [o for o in valid_sqso_operators if o.startswith(args[-1])]
2015 if len(args)>2 and args[-2].endswith('^2') and len(match_op)>0:
2016 if args[-1] in valid_sqso_operators:
2017 return self.list_completion(text,' ')
2018 if len(match_op)==1:
2019 return self.list_completion(text,[match_op[0][len(args[-1]):]])
2020 else:
2021 return self.list_completion(text,match_op)
2022 if len(args) > 2 and args[-1] == '@' or ( args[-1].endswith('=') and \
2023 (not '[' in line or ('[' in line and ']' in line))):
2024 return
2025
2026 try:
2027 return self.model_completion(text, ' '.join(args[1:]),line, formatting)
2028 except Exception as error:
2029 print error
2030
2031
2032
2033
2034
2035
2036
2037
2038
2040 "Complete the compute_widths command"
2041
2042 args = self.split_arg(line[0:begidx])
2043
2044 if args[-1] in ['--path=', '--output=']:
2045 completion = {'path': self.path_completion(text)}
2046 elif line[begidx-1] == os.path.sep:
2047 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)])
2048 if current_dir.startswith('--path='):
2049 current_dir = current_dir[7:]
2050 if current_dir.startswith('--output='):
2051 current_dir = current_dir[9:]
2052 completion = {'path': self.path_completion(text, current_dir)}
2053 else:
2054 completion = {}
2055 completion['options'] = self.list_completion(text,
2056 ['--path=', '--output=', '--min_br=0.\$',
2057 '--precision_channel=0.\$', '--body_decay=', '--nlo'])
2058 completion['particles'] = self.model_completion(text, '', line)
2059
2060 return self.deal_multiple_categories(completion,formatting)
2061
2062 complete_decay_diagram = complete_compute_widths
2063
2064 - def complete_add(self, text, line, begidx, endidx, formatting):
2065 "Complete the add command"
2066
2067 args = self.split_arg(line[0:begidx])
2068
2069
2070 if len(args) == 1:
2071 return self.list_completion(text, self._add_opts)
2072
2073 if args[1] == 'process':
2074 return self.complete_generate(text, " ".join(args[1:]), begidx, endidx)
2075
2076 elif args[1] == 'model':
2077 completion_categories = self.complete_import(text, line, begidx, endidx,
2078 allow_restrict=False, formatting=False)
2079 completion_categories['options'] = self.list_completion(text,['--modelname=','--recreate'])
2080 return self.deal_multiple_categories(completion_categories, formatting)
2081
2083 "Complete the customize_model command"
2084
2085 args = self.split_arg(line[0:begidx])
2086
2087
2088 if len(args) == 1:
2089 return self.list_completion(text, ['--save='])
2090
2091
2092 - def complete_check(self, text, line, begidx, endidx, formatting=True):
2093 "Complete the check command"
2094
2095 out = {}
2096 args = self.split_arg(line[0:begidx])
2097
2098
2099 if len(args) == 1:
2100 return self.list_completion(text, self._check_opts)
2101
2102
2103 cms_check_mode = len(args) >= 2 and args[1]=='cms'
2104
2105 cms_options = ['--name=','--tweak=','--seed=','--offshellness=',
2106 '--lambdaCMS=','--show_plot=','--report=','--lambda_plot_range=','--recompute_width=',
2107 '--CTModeRun=','--helicity=','--reduction=','--cms=','--diff_lambda_power=',
2108 '--loop_filter=','--resonances=']
2109
2110 options = ['--energy=']
2111 if cms_options:
2112 options.extend(cms_options)
2113
2114
2115 if args[-1].endswith(os.path.sep):
2116 return self.path_completion(text, pjoin(*[a for a in args \
2117 if a.endswith(os.path.sep)]))
2118
2119 model_comp = self.model_completion(text, ' '.join(args[2:]),line,
2120 categories = True, allowed_loop_mode=['virt'])
2121
2122 model_comp_and_path = self.deal_multiple_categories(\
2123 {'Process completion': self.model_completion(text, ' '.join(args[2:]),
2124 line, categories = False, allowed_loop_mode=['virt']),
2125 'Param_card.dat path completion:':self.path_completion(text),
2126 'options': self.list_completion(text,options)}, formatting)
2127
2128
2129 if cms_check_mode:
2130
2131 if line[-1]!=' ' and line[-2]!='\\' and not '--' in line[begidx:endidx] \
2132 and args[-1].startswith('--') and '=' in args[-1]:
2133 examples = {
2134 '--tweak=':
2135 ['default','alltweaks',"['default','allwidths->1.1*all_withds&seed333(Increased_widths_and_seed_333)','logp->logm&logm->logp(inverted_logs)']"],
2136 '--lambdaCMS=':
2137 ['(1.0e-2,5)',"[float('1.0e-%d'%exp)\\ for\\ exp\\ in\\ range(8)]","[1.0,0.5,0.001]"],
2138 '--lambda_plot_range=':
2139 [' [1e-05,1e-02]','[0.01,1.0]'],
2140 '--reduction=':
2141 ['1','1|2|3|4','1|2','3'],
2142 '--cms=':
2143 ['QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS',
2144 'NP&QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS&newExpansionParameter->newExpansionParameter*lambdaCMS'],
2145 '--loop_filter=':
2146 ['None','n>3','n<4 and 6 in loop_pdgs and 3<=id<=7'],
2147 '--resonances=':
2148 ['1','all','(24,(3,4))','[(24,(3,4)),(24,(4,5))]'],
2149 '--analyze=':
2150 ['my_default_run.pkl',
2151 'default_run.pkl,increased_widths.pkl(Increased_widths),logs_modified.pkl(Inverted_logs),seed_668.pkl(Different_seed)']
2152 }
2153 for name, example in examples.items():
2154 if args[-1].startswith(name):
2155 return self.deal_multiple_categories(
2156 {"Examples of completion for option '%s'"%args[-1].split('=')[0]:
2157
2158 ['%s'%ex for i, ex in enumerate(example)]},formatting,
2159 forceCategory=True)
2160 if args[-1]=='--recompute_width=':
2161 return self.list_completion(text,
2162 ['never','first_time','always','auto'])
2163 elif args[-1]=='--show_plot=':
2164 return self.list_completion(text,['True','False'])
2165 elif args[-1]=='--report=':
2166 return self.list_completion(text,['concise','full'])
2167 elif args[-1]=='--CTModeRun=':
2168 return self.list_completion(text,['-1','1','2','3','4'])
2169 else:
2170 return text
2171 if len(args)==2 or len(args)==3 and args[-1]=='-reuse':
2172 return self.deal_multiple_categories(
2173 {'Process completion': self.model_completion(text, ' '.join(args[2:]),
2174 line, categories = False, allowed_loop_mode=['virt']),
2175 'Param_card.dat path completion:': self.path_completion(text),
2176 'reanalyze result on disk / save output:':self.list_completion(
2177 text,['-reuse','--analyze='])},
2178 formatting)
2179 elif not any(arg.startswith('--') for arg in args):
2180 if '>' in args:
2181 return self.deal_multiple_categories({'Process completion':
2182 self.model_completion(text, ' '.join(args[2:]),
2183 line, categories = False, allowed_loop_mode=['virt']),
2184 'options': self.list_completion(text,options)},
2185 formatting)
2186 else:
2187 return self.deal_multiple_categories({'Process completion':
2188 self.model_completion(text, ' '.join(args[2:]),
2189 line, categories = False, allowed_loop_mode=['virt'])},
2190 formatting)
2191 else:
2192 return self.list_completion(text,options)
2193
2194 if len(args) == 2:
2195 return model_comp_and_path
2196 elif len(args) == 3:
2197 try:
2198 int(args[2])
2199 except ValueError:
2200 return model_comp
2201 else:
2202 return model_comp_and_path
2203 elif len(args) > 3:
2204 return model_comp
2205
2206
2213
2215 """Complete particle information"""
2216 return self.model_completion(text, line[6:],line)
2217
2231
2233 "Complete the draw command"
2234
2235 args = self.split_arg(line[0:begidx])
2236
2237
2238 if args[-1].endswith(os.path.sep):
2239 return self.path_completion(text,
2240 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
2241 only_dirs = True)
2242
2243 if len(args) == 1:
2244 return self.path_completion(text, '.', only_dirs = True)
2245
2246
2247
2248 if len(args) >= 2:
2249 opt = ['horizontal', 'external=', 'max_size=', 'add_gap=',
2250 'non_propagating', '--']
2251 return self.list_completion(text, opt)
2252
2254 """ complete the launch command"""
2255 args = self.split_arg(line[0:begidx])
2256
2257
2258 if args[-1].endswith(os.path.sep):
2259 return self.path_completion(text,
2260 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
2261 only_dirs = True)
2262
2263 if len(args) == 1:
2264 out = {'Path from ./': self.path_completion(text, '.', only_dirs = True)}
2265 if MG5DIR != os.path.realpath('.'):
2266 out['Path from %s' % MG5DIR] = self.path_completion(text,
2267 MG5DIR, only_dirs = True, relative=False)
2268 if MG4DIR and MG4DIR != os.path.realpath('.') and MG4DIR != MG5DIR:
2269 out['Path from %s' % MG4DIR] = self.path_completion(text,
2270 MG4DIR, only_dirs = True, relative=False)
2271
2272
2273
2274 if len(args) >= 2:
2275 out={}
2276
2277 if line[0:begidx].endswith('--laststep='):
2278 opt = ['parton', 'pythia', 'pgs','delphes','auto']
2279 out['Options'] = self.list_completion(text, opt, line)
2280 else:
2281 opt = ['--cluster', '--multicore', '-i', '--name=', '-f','-m', '-n',
2282 '-p','--parton','--interactive', '--laststep=parton', '--laststep=pythia',
2283 '--laststep=pgs', '--laststep=delphes','--laststep=auto']
2284 out['Options'] = self.list_completion(text, opt, line)
2285
2286
2287 return self.deal_multiple_categories(out,formatting)
2288
2307
2326
2327 @cmd.debug()
2329 """ complete the open command """
2330
2331 args = self.split_arg(line[0:begidx])
2332
2333
2334 if os.path.sep in args[-1] + text:
2335 return self.path_completion(text,
2336 pjoin(*[a for a in args if \
2337 a.endswith(os.path.sep)]))
2338
2339 possibility = []
2340 if self._done_export:
2341 path = self._done_export[0]
2342 possibility = ['index.html']
2343 if os.path.isfile(pjoin(path,'README')):
2344 possibility.append('README')
2345 if os.path.isdir(pjoin(path,'Cards')):
2346 possibility += [f for f in os.listdir(pjoin(path,'Cards'))
2347 if f.endswith('.dat')]
2348 if os.path.isdir(pjoin(path,'HTML')):
2349 possibility += [f for f in os.listdir(pjoin(path,'HTML'))
2350 if f.endswith('.html') and 'default' not in f]
2351 else:
2352 possibility.extend(['./','../'])
2353 if os.path.exists('MG5_debug'):
2354 possibility.append('MG5_debug')
2355 if os.path.exists('ME5_debug'):
2356 possibility.append('ME5_debug')
2357
2358 return self.list_completion(text, possibility)
2359
2360 @cmd.debug()
2361 - def complete_output(self, text, line, begidx, endidx,
2362 possible_options = ['f', 'noclean', 'nojpeg'],
2363 possible_options_full = ['-f', '-noclean', '-nojpeg']):
2364 "Complete the output command"
2365
2366 possible_format = self._export_formats
2367
2368 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS',
2369 'Calculators', 'MadAnalysis', 'SimpleAnalysis',
2370 'mg5', 'DECAY', 'EventConverter', 'Models',
2371 'ExRootAnalysis', 'HELAS', 'Transfer_Fct', 'aloha',
2372 'matchbox', 'matchbox_cpp', 'tests']
2373
2374
2375 args = self.split_arg(line[0:begidx])
2376 if len(args) >= 1:
2377
2378 if len(args) > 1 and args[1] == 'pythia8':
2379 possible_options_full = list(possible_options_full) + ['--version=8.1','--version=8.2']
2380
2381 if len(args) > 1 and args[1] == 'aloha':
2382 try:
2383 return self.aloha_complete_output(text, line, begidx, endidx)
2384 except Exception, error:
2385 print error
2386
2387 if args[-1].endswith(os.path.sep):
2388 return [name for name in self.path_completion(text,
2389 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
2390 only_dirs = True) if name not in forbidden_names]
2391
2392 if args[-1][0] == '-' or len(args) > 1 and args[-2] == '-':
2393 return self.list_completion(text, possible_options)
2394
2395 if len(args) > 2:
2396 return self.list_completion(text, possible_options_full)
2397
2398 if len(args) == 1:
2399 format = possible_format + ['.' + os.path.sep, '..' + os.path.sep, 'auto']
2400 return self.list_completion(text, format)
2401
2402
2403 content = [name for name in self.path_completion(text, '.', only_dirs = True) \
2404 if name not in forbidden_names]
2405 content += ['auto']
2406 content += possible_options_full
2407 return self.list_completion(text, content)
2408
2410 "Complete the output aloha command"
2411 args = self.split_arg(line[0:begidx])
2412 completion_categories = {}
2413
2414 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS',
2415 'Calculators', 'MadAnalysis', 'SimpleAnalysis',
2416 'mg5', 'DECAY', 'EventConverter', 'Models',
2417 'ExRootAnalysis', 'Transfer_Fct', 'aloha',
2418 'apidoc','vendor']
2419
2420
2421
2422 options = ['--format=Fortran', '--format=Python','--format=gpu','--format=CPP','--output=']
2423 options = self.list_completion(text, options)
2424 if options:
2425 completion_categories['options'] = options
2426
2427 if args[-1] == '--output=' or args[-1].endswith(os.path.sep):
2428
2429 completion_categories['path'] = [name for name in self.path_completion(text,
2430 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
2431 only_dirs = True) if name not in forbidden_names]
2432
2433 else:
2434 ufomodel = ufomodels.load_model(self._curr_model.get('name'))
2435 wf_opt = []
2436 amp_opt = []
2437 opt_conjg = []
2438 for lor in ufomodel.all_lorentz:
2439 amp_opt.append('%s_0' % lor.name)
2440 for i in range(len(lor.spins)):
2441 wf_opt.append('%s_%i' % (lor.name,i+1))
2442 if i % 2 == 0 and lor.spins[i] == 2:
2443 opt_conjg.append('%sC%i_%i' % (lor.name,i //2 +1,i+1))
2444 completion_categories['amplitude routines'] = self.list_completion(text, amp_opt)
2445 completion_categories['Wavefunctions routines'] = self.list_completion(text, wf_opt)
2446 completion_categories['conjugate_routines'] = self.list_completion(text, opt_conjg)
2447
2448 return self.deal_multiple_categories(completion_categories,formatting)
2449
2451 "Complete the set command"
2452 args = self.split_arg(line[0:begidx])
2453
2454
2455 if len(args) == 1:
2456 opts = list(set(self.options.keys() + self._set_options))
2457 return self.list_completion(text, opts)
2458
2459 if len(args) == 2:
2460 if args[1] in ['group_subprocesses', 'complex_mass_scheme',\
2461 'loop_optimized_output', 'loop_color_flows',\
2462 'low_mem_multicore_nlo_generation']:
2463 return self.list_completion(text, ['False', 'True', 'default'])
2464 elif args[1] in ['ignore_six_quark_processes']:
2465 return self.list_completion(text, self._multiparticles.keys())
2466 elif args[1].lower() == 'ewscheme':
2467 return self.list_completion(text, ["external"])
2468 elif args[1] == 'gauge':
2469 return self.list_completion(text, ['unitary', 'Feynman','default'])
2470 elif args[1] == 'OLP':
2471 return self.list_completion(text, MadGraphCmd._OLP_supported)
2472 elif args[1] == 'output_dependencies':
2473 return self.list_completion(text,
2474 MadGraphCmd._output_dependencies_supported)
2475 elif args[1] == 'stdout_level':
2476 return self.list_completion(text, ['DEBUG','INFO','WARNING','ERROR',
2477 'CRITICAL','default'])
2478 elif args[1] == 'fortran_compiler':
2479 return self.list_completion(text, ['f77','g77','gfortran','default'])
2480 elif args[1] == 'cpp_compiler':
2481 return self.list_completion(text, ['g++', 'c++', 'clang', 'default'])
2482 elif args[1] == 'nb_core':
2483 return self.list_completion(text, [str(i) for i in range(100)] + ['default'] )
2484 elif args[1] == 'run_mode':
2485 return self.list_completion(text, [str(i) for i in range(3)] + ['default'])
2486 elif args[1] == 'cluster_type':
2487 return self.list_completion(text, cluster.from_name.keys() + ['default'])
2488 elif args[1] == 'cluster_queue':
2489 return []
2490 elif args[1] == 'automatic_html_opening':
2491 return self.list_completion(text, ['False', 'True', 'default'])
2492 else:
2493
2494 second_set = [name for name in self.path_completion(text, '.', only_dirs = True)]
2495 return self.list_completion(text, second_set + ['default'])
2496 elif len(args) >2 and args[-1].endswith(os.path.sep):
2497 return self.path_completion(text,
2498 pjoin(*[a for a in args if a.endswith(os.path.sep)]),
2499 only_dirs = True)
2500
2501 - def complete_import(self, text, line, begidx, endidx, allow_restrict=True,
2502 formatting=True):
2503 "Complete the import command"
2504
2505 args=self.split_arg(line[0:begidx])
2506
2507
2508 if len(args) == 1:
2509 opt = self.list_completion(text, self._import_formats)
2510 if opt:
2511 return opt
2512 mode = 'all'
2513 elif args[1] in self._import_formats:
2514 mode = args[1]
2515 else:
2516 args.insert(1, 'all')
2517 mode = 'all'
2518
2519
2520 completion_categories = {}
2521
2522 if mode in ['model', 'all'] and '-' in text:
2523
2524 path = '-'.join([part for part in text.split('-')[:-1]])
2525
2526
2527 all_name = self.find_restrict_card(path, no_restrict=False)
2528 all_name += self.find_restrict_card(path, no_restrict=False,
2529 base_dir=pjoin(MG5DIR,'models'))
2530 if os.environ['PYTHONPATH']:
2531 for modeldir in os.environ['PYTHONPATH'].split(':'):
2532 if not modeldir:
2533 continue
2534 all_name += self.find_restrict_card(path, no_restrict=False,
2535 base_dir=modeldir)
2536
2537 all_name = [name+' ' for name in all_name if name.startswith(text)
2538 and name.strip() != text]
2539
2540
2541 if all_name:
2542 completion_categories['Restricted model'] = all_name
2543
2544
2545 if os.path.sep in args[-1]:
2546 if mode.startswith('model') or mode == 'all':
2547
2548 try:
2549 cur_path = pjoin(*[a for a in args \
2550 if a.endswith(os.path.sep)])
2551 except Exception:
2552 pass
2553 else:
2554 all_dir = self.path_completion(text, cur_path, only_dirs = True)
2555 if mode in ['model_v4','all']:
2556 completion_categories['Path Completion'] = all_dir
2557
2558 new = []
2559 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path))
2560 for name in all_dir]
2561 if data:
2562 completion_categories['Path Completion'] = all_dir + new
2563 else:
2564 try:
2565 cur_path = pjoin(*[a for a in args \
2566 if a.endswith(os.path.sep)])
2567 except Exception:
2568 pass
2569 else:
2570 all_path = self.path_completion(text, cur_path)
2571 if mode == 'all':
2572 new = []
2573 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path))
2574 for name in all_path]
2575 if data:
2576 completion_categories['Path Completion'] = data[0]
2577 else:
2578 completion_categories['Path Completion'] = all_path
2579
2580
2581 if (len(args) == 2):
2582 is_model = True
2583 if mode == 'model':
2584 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py'))
2585 mod_name = lambda name: name
2586 elif mode == 'model_v4':
2587 file_cond = lambda p : (os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat'))
2588 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat')))
2589 mod_name = lambda name :(name[-3:] != '_v4' and name or name[:-3])
2590 elif mode == 'all':
2591 mod_name = lambda name: name
2592 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) \
2593 or os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) \
2594 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat'))
2595 else:
2596 cur_path = pjoin(*[a for a in args \
2597 if a.endswith(os.path.sep)])
2598 all_path = self.path_completion(text, cur_path)
2599 completion_categories['model name'] = all_path
2600 is_model = False
2601
2602 if is_model:
2603 model_list = [mod_name(name) for name in \
2604 self.path_completion(text,
2605 pjoin(MG5DIR,'models'),
2606 only_dirs = True) \
2607 if file_cond(name)]
2608 if mode == 'model' and 'PYTHONPATH' in os.environ:
2609 for modeldir in os.environ['PYTHONPATH'].split(':'):
2610 if not modeldir:
2611 continue
2612 model_list += [name for name in self.path_completion(text,
2613 modeldir, only_dirs=True)
2614 if os.path.exists(pjoin(modeldir,name, 'particles.py'))]
2615
2616
2617
2618 if mode == 'model_v4':
2619 completion_categories['model name'] = model_list
2620 elif allow_restrict:
2621
2622 all_name = []
2623 for model_name in model_list:
2624 all_name += self.find_restrict_card(model_name,
2625 base_dir=pjoin(MG5DIR,'models'))
2626 else:
2627 all_name = model_list
2628
2629 if mode == 'all':
2630 cur_path = pjoin(*[a for a in args \
2631 if a.endswith(os.path.sep)])
2632 all_path = self.path_completion(text, cur_path)
2633 completion_categories['model name'] = all_path + all_name
2634 elif mode == 'model':
2635 completion_categories['model name'] = all_name
2636
2637
2638 if mode == 'all' and len(args)>1:
2639 mode = self.find_import_type(args[2])
2640
2641 if len(args) >= 3 and mode.startswith('model') and not '-modelname' in line:
2642 if not text and not completion_categories:
2643 return ['--modelname']
2644 elif not (os.path.sep in args[-1] and line[-1] != ' '):
2645 completion_categories['options'] = self.list_completion(text, ['--modelname','-modelname','--noprefix'])
2646 if len(args) >= 3 and mode.startswith('banner') and not '--no_launch' in line:
2647 completion_categories['options'] = self.list_completion(text, ['--no_launch'])
2648
2649 return self.deal_multiple_categories(completion_categories,formatting)
2650
2652 """find the restriction file associate to a given model"""
2653
2654
2655 if no_restrict:
2656 output = [model_name]
2657 else:
2658 output = []
2659
2660
2661 if not os.path.exists(pjoin(base_dir, model_name, 'couplings.py')):
2662
2663 return output
2664
2665 if model_name.endswith(os.path.sep):
2666 model_name = model_name[:-1]
2667
2668
2669 if os.path.exists(pjoin(base_dir, model_name, 'restrict_default.dat')):
2670 output.append('%s-full' % model_name)
2671
2672
2673 for name in os.listdir(pjoin(base_dir, model_name)):
2674 if name.startswith('restrict_') and not name.endswith('default.dat') \
2675 and name.endswith('.dat'):
2676 tag = name[9:-4]
2677 while model_name.endswith(os.path.sep):
2678 model_name = model_name[:-1]
2679 output.append('%s-%s' % (model_name, tag))
2680
2681
2682 return output
2683
2685 "Complete the import command"
2686
2687 args = self.split_arg(line[0:begidx])
2688
2689 if len(args) == 1:
2690 return self.list_completion(text, self._install_opts)
2691 elif len(args) and args[0] == 'update':
2692 return self.list_completion(text, ['-f','--timeout='])
2693 elif len(args)>=2 and args[1] in self._advanced_install_opts:
2694 options = ['--keep_source','--logging=']
2695 if args[1]=='pythia8':
2696 options.append('--pythia8_tarball=')
2697 elif args[1]=='mg5amc_py8_interface':
2698 options.append('--mg5amc_py8_interface_tarball=')
2699 elif args[1] in ['MadAnalysis5','MadAnalysis']:
2700
2701 options.append('--no_root_in_MA5')
2702 options.append('--update')
2703 options.append('--madanalysis5_tarball=')
2704 for prefix in ['--with', '--veto']:
2705 for prog in ['fastjet', 'delphes', 'delphesMA5tune']:
2706 options.append('%s_%s' % (prefix, prog))
2707
2708 for opt in options[:]:
2709 if any(a.startswith(opt) for a in args):
2710 options.remove(opt)
2711 return self.list_completion(text, options)
2712 else:
2713 return self.list_completion(text, [])
2714
2715
2716
2717
2718 -class MadGraphCmd(HelpToCmd, CheckValidForCmd, CompleteForCmd, CmdExtended):
2719 """The command line processor of MadGraph"""
2720
2721 writing_dir = '.'
2722
2723
2724 _display_opts = ['particles', 'interactions', 'processes', 'diagrams',
2725 'diagrams_text', 'multiparticles', 'couplings', 'lorentz',
2726 'checks', 'parameters', 'options', 'coupling_order','variable']
2727 _add_opts = ['process', 'model']
2728 _save_opts = ['model', 'processes', 'options']
2729 _tutorial_opts = ['aMCatNLO', 'stop', 'MadLoop', 'MadGraph5']
2730 _switch_opts = ['mg5','aMC@NLO','ML5']
2731 _check_opts = ['full', 'timing', 'stability', 'profile', 'permutation',
2732 'gauge','lorentz', 'brs', 'cms']
2733 _import_formats = ['model_v4', 'model', 'proc_v4', 'command', 'banner']
2734 _install_opts = ['Delphes', 'MadAnalysis4', 'ExRootAnalysis',
2735 'update', 'SysCalc', 'Golem95', 'PJFry', 'QCDLoop', 'maddm']
2736
2737
2738 _advanced_install_opts = ['pythia8','zlib','boost','lhapdf6','lhapdf5','collier',
2739 'hepmc','mg5amc_py8_interface','ninja','oneloop','MadAnalysis5','MadAnalysis']
2740
2741 _install_opts.extend(_advanced_install_opts)
2742
2743 _v4_export_formats = ['madevent', 'standalone', 'standalone_msP','standalone_msF',
2744 'matrix', 'standalone_rw', 'madweight']
2745 _export_formats = _v4_export_formats + ['standalone_cpp', 'pythia8', 'aloha',
2746 'matchbox_cpp', 'matchbox']
2747 _set_options = ['group_subprocesses',
2748 'ignore_six_quark_processes',
2749 'stdout_level',
2750 'fortran_compiler',
2751 'cpp_compiler',
2752 'loop_optimized_output',
2753 'complex_mass_scheme',
2754 'gauge',
2755 'EWscheme',
2756 'max_npoint_for_channel']
2757 _valid_nlo_modes = ['all','real','virt','sqrvirt','tree','noborn','LOonly']
2758 _valid_sqso_types = ['==','<=','=','>']
2759 _valid_amp_so_types = ['=','<=', '==', '>']
2760 _OLP_supported = ['MadLoop', 'GoSam']
2761 _output_dependencies_supported = ['external', 'internal','environment_paths']
2762
2763
2764
2765 options_configuration = {'pythia8_path': './HEPTools/pythia8',
2766 'hwpp_path': './herwigPP',
2767 'thepeg_path': './thepeg',
2768 'hepmc_path': './hepmc',
2769 'madanalysis_path': './MadAnalysis',
2770 'madanalysis5_path':'./HEPTools/madanalysis5/madanalysis5',
2771 'pythia-pgs_path':'./pythia-pgs',
2772 'td_path':'./td',
2773 'delphes_path':'./Delphes',
2774 'exrootanalysis_path':'./ExRootAnalysis',
2775 'syscalc_path': './SysCalc',
2776 'timeout': 60,
2777 'web_browser':None,
2778 'eps_viewer':None,
2779 'text_editor':None,
2780 'fortran_compiler':None,
2781 'f2py_compiler':None,
2782 'cpp_compiler':None,
2783 'auto_update':7,
2784 'cluster_type': 'condor',
2785 'cluster_queue': None,
2786 'cluster_status_update': (600, 30),
2787 'fastjet':'fastjet-config',
2788 'pjfry':'auto',
2789 'golem':'auto',
2790 'samurai':None,
2791 'ninja':'./HEPTools/lib',
2792 'collier':'./HEPTools/lib',
2793 'lhapdf':'lhapdf-config',
2794 'applgrid':'applgrid-config',
2795 'amcfast':'amcfast-config',
2796 'cluster_temp_path':None,
2797 'mg5amc_py8_interface_path': './HEPTools/MG5aMC_PY8_interface',
2798 'cluster_local_path': None,
2799 'OLP': 'MadLoop',
2800 'cluster_nb_retry':1,
2801 'cluster_retry_wait':300,
2802 'cluster_size':100,
2803 'output_dependencies':'external'
2804 }
2805
2806 options_madgraph= {'group_subprocesses': 'Auto',
2807 'ignore_six_quark_processes': False,
2808 'low_mem_multicore_nlo_generation': False,
2809 'complex_mass_scheme': False,
2810 'gauge':'unitary',
2811 'stdout_level':None,
2812 'loop_optimized_output':True,
2813 'loop_color_flows':False,
2814 'max_npoint_for_channel': 0
2815 }
2816
2817 options_madevent = {'automatic_html_opening':True,
2818 'run_mode':2,
2819 'nb_core': None,
2820 'notification_center': True
2821 }
2822
2823
2824
2825 _curr_model = None
2826 _curr_amps = diagram_generation.AmplitudeList()
2827 _curr_proc_defs = base_objects.ProcessDefinitionList()
2828 _curr_matrix_elements = helas_objects.HelasMultiProcess()
2829 _curr_helas_model = None
2830 _curr_exporter = None
2831 _done_export = False
2832 _curr_decaymodel = None
2833
2834 helporder = ['Main commands', 'Documented commands']
2835
2836
2850
2851
2852 - def __init__(self, mgme_dir = '', *completekey, **stdin):
2853 """ add a tracker of the history """
2854
2855 CmdExtended.__init__(self, *completekey, **stdin)
2856
2857
2858 if mgme_dir:
2859 if os.path.isdir(pjoin(mgme_dir, 'Template')):
2860 self._mgme_dir = mgme_dir
2861 logger.info('Setting MG/ME directory to %s' % mgme_dir)
2862 else:
2863 logger.warning('Warning: Directory %s not valid MG/ME directory' % \
2864 mgme_dir)
2865 self._mgme_dir = MG4DIR
2866
2867
2868 self._multiparticles = {}
2869 self.options = {}
2870 self._generate_info = ""
2871 self._model_v4_path = None
2872 self._export_dir = None
2873 self._export_format = 'madevent'
2874 self._mgme_dir = MG4DIR
2875 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools'))
2876 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src'))
2877 self._comparisons = None
2878 self._cms_checks = []
2879 self._nlo_modes_for_completion = ['all','virt','real','LOonly']
2880
2881
2882 self.set_configuration()
2883
2903
2917
2918
2919
2921 """Generate an amplitude for a given process and add to
2922 existing amplitudes
2923 or merge two model
2924 """
2925
2926 args = self.split_arg(line)
2927
2928
2929 warning_duplicate = True
2930 if '--no_warning=duplicate' in args:
2931 warning_duplicate = False
2932 args.remove('--no_warning=duplicate')
2933
2934 diagram_filter = False
2935 if '--diagram_filter' in args:
2936 diagram_filter = True
2937 args.remove('--diagram_filter')
2938
2939
2940 self.check_add(args)
2941
2942 if args[0] == 'model':
2943 return self.add_model(args[1:])
2944
2945
2946
2947 if args[-1].startswith('--optimize'):
2948 optimize = True
2949 args.pop()
2950 else:
2951 optimize = False
2952
2953 if args[0] == 'process':
2954
2955 line = ' '.join(args[1:])
2956
2957
2958 if not self._generate_info:
2959 self._generate_info = line
2960
2961
2962 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
2963
2964
2965 if ',' in line:
2966 if ']' in line or '[' in line:
2967 error_msg=\
2968 """The '[' and ']' syntax cannot be used in cunjunction with decay chains.
2969 This implies that with decay chains:
2970 > Squared coupling order limitations are not available.
2971 > Loop corrections cannot be considered."""
2972 raise MadGraph5Error(error_msg)
2973 else:
2974 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))])
2975 myprocdef, line = self.extract_decay_chain_process(line, proc_number=nb_proc)
2976
2977
2978
2979 if myprocdef.are_decays_perturbed():
2980 raise MadGraph5Error("Decay processes cannot be perturbed.")
2981
2982
2983
2984 if myprocdef.decays_have_squared_orders() or \
2985 myprocdef['squared_orders']!={}:
2986 raise MadGraph5Error("Decay processes cannot specify "+\
2987 "squared orders constraints.")
2988 if myprocdef.are_negative_orders_present():
2989 raise MadGraph5Error("Decay processes cannot include negative"+\
2990 " coupling orders constraints.")
2991 else:
2992 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))])
2993 myprocdef = self.extract_process(line, proc_number=nb_proc)
2994
2995
2996
2997
2998 if not myprocdef:
2999 raise self.InvalidCmd("Empty or wrong format process, please try again.")
3000
3001
3002 if self._curr_amps and self._curr_amps[0].get_ninitial() != \
3003 myprocdef.get_ninitial():
3004 raise self.InvalidCmd("Can not mix processes with different number of initial states.")
3005
3006 self._curr_proc_defs.append(myprocdef)
3007
3008
3009
3010 if len([1 for val in myprocdef.get('orders').values()+\
3011 myprocdef.get('squared_orders').values() if val<0])>1:
3012 raise MadGraph5Error("Negative coupling order constraints"+\
3013 " can only be given on one type of coupling and either on"+\
3014 " squared orders or amplitude orders, not both.")
3015
3016 cpu_time1 = time.time()
3017
3018
3019 if self.options['group_subprocesses'] == 'Auto':
3020 collect_mirror_procs = True
3021 else:
3022 collect_mirror_procs = self.options['group_subprocesses']
3023 ignore_six_quark_processes = \
3024 self.options['ignore_six_quark_processes'] if \
3025 "ignore_six_quark_processes" in self.options \
3026 else []
3027
3028 myproc = diagram_generation.MultiProcess(myprocdef,
3029 collect_mirror_procs = collect_mirror_procs,
3030 ignore_six_quark_processes = ignore_six_quark_processes,
3031 optimize=optimize, diagram_filter=diagram_filter)
3032
3033
3034 for amp in myproc.get('amplitudes'):
3035 if amp not in self._curr_amps:
3036 self._curr_amps.append(amp)
3037 elif warning_duplicate:
3038 raise self.InvalidCmd, "Duplicate process %s found. Please check your processes." % \
3039 amp.nice_string_processes()
3040
3041
3042 self._done_export = False
3043
3044 cpu_time2 = time.time()
3045
3046 nprocs = len(myproc.get('amplitudes'))
3047 ndiags = sum([amp.get_number_of_diagrams() for \
3048 amp in myproc.get('amplitudes')])
3049
3050 logger.info("%i processes with %i diagrams generated in %0.3f s" % \
3051 (nprocs, ndiags, (cpu_time2 - cpu_time1)))
3052 ndiags = sum([amp.get_number_of_diagrams() for \
3053 amp in self._curr_amps])
3054 logger.info("Total: %i processes with %i diagrams" % \
3055 (len(self._curr_amps), ndiags))
3056
3058 """merge two model"""
3059
3060 model_path = args[0]
3061 recreate = ('--recreate' in args)
3062 keep_decay = ('--keep_decay' in args)
3063 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')]
3064 if output_dir:
3065 output_dir = output_dir[0]
3066 recreate = True
3067 restrict_name = ''
3068 else:
3069 name = os.path.basename(self._curr_model.get('modelpath'))
3070 restrict_name = self._curr_model.get('restrict_name')
3071 output_dir = pjoin(MG5DIR, 'models', '%s__%s' % (name,
3072 os.path.basename(model_path)))
3073
3074 if os.path.exists(output_dir):
3075 if recreate:
3076 shutil.rmtree(output_dir)
3077 else:
3078 logger.info('Model already created! Loading it from %s' % output_dir)
3079 oldmodel = self._curr_model.get('modelpath')
3080 new_model_name = output_dir
3081 if restrict_name:
3082 new_model_name = '%s-%s' % (output_dir, restrict_name)
3083 try:
3084 self.exec_cmd('import model %s' % new_model_name, errorhandling=False,
3085 printcmd=False, precmd=True, postcmd=True)
3086 except Exception, error:
3087 logger.debug('fail to load model %s with error:\n %s' % (output_dir, error))
3088 logger.warning('Fail to load the model. Restore previous model')
3089 self.exec_cmd('import model %s' % oldmodel, errorhandling=False,
3090 printcmd=False, precmd=True, postcmd=True)
3091 raise Exception('Invalid Model! Please retry with the option \'--recreate\'.')
3092 else:
3093 return
3094
3095
3096 import models.usermod as usermod
3097 base_model = usermod.UFOModel(self._curr_model.get('modelpath'))
3098
3099 identify = dict(tuple(a.split('=')) for a in args if '=' in a)
3100 base_model.add_model(path=model_path, identify_particles=identify)
3101 base_model.write(output_dir)
3102
3103 if keep_decay and os.path.exists(pjoin(self._curr_model.get('modelpath'), 'decays.py')):
3104 base_model.mod_file(pjoin(pjoin(self._curr_model.get('modelpath'), 'decays.py')),
3105 pjoin(pjoin(output_dir, 'decays.py')))
3106
3107 new_model_name = output_dir
3108 if restrict_name:
3109 new_model_name = '%s-%s' % (output_dir, restrict_name)
3110
3111 if 'modelname' in self.history.get('full_model_line'):
3112 opts = '--modelname'
3113 else:
3114 opts=''
3115 self.exec_cmd('import model %s %s' % (new_model_name, opts), errorhandling=False,
3116 printcmd=False, precmd=True, postcmd=True)
3117
3118
3119
3157
3158
3160 """Display current internal status"""
3161
3162 args = self.split_arg(line)
3163
3164 self.check_display(args)
3165
3166 if args[0] == 'diagrams':
3167 self.draw(' '.join(args[1:]))
3168
3169 if args[0] == 'particles' and len(args) == 1:
3170 propagating_particle = []
3171 nb_unpropagating = 0
3172 for particle in self._curr_model['particles']:
3173 if particle.get('propagating'):
3174 propagating_particle.append(particle)
3175 else:
3176 nb_unpropagating += 1
3177
3178 print "Current model contains %i particles:" % \
3179 len(propagating_particle)
3180 part_antipart = [part for part in propagating_particle \
3181 if not part['self_antipart']]
3182 part_self = [part for part in propagating_particle \
3183 if part['self_antipart']]
3184 for part in part_antipart:
3185 print part['name'] + '/' + part['antiname'],
3186 print ''
3187 for part in part_self:
3188 print part['name'],
3189 print ''
3190 if nb_unpropagating:
3191 print 'In addition of %s un-physical particle mediating new interactions.' \
3192 % nb_unpropagating
3193
3194 elif args[0] == 'particles':
3195 for arg in args[1:]:
3196 if arg.isdigit() or (arg[0] == '-' and arg[1:].isdigit()):
3197 particle = self._curr_model.get_particle(abs(int(arg)))
3198 else:
3199 particle = self._curr_model['particles'].find_name(arg)
3200 if not particle:
3201 raise self.InvalidCmd, 'no particle %s in current model' % arg
3202
3203 print "Particle %s has the following properties:" % particle.get_name()
3204 print str(particle)
3205
3206 elif args[0] == 'interactions' and len(args) == 1:
3207 text = "Current model contains %i interactions\n" % \
3208 len(self._curr_model['interactions'])
3209 for i, inter in enumerate(self._curr_model['interactions']):
3210 text += str(i+1) + ':'
3211 for part in inter['particles']:
3212 if part['is_part']:
3213 text += part['name']
3214 else:
3215 text += part['antiname']
3216 text += " "
3217 text += " ".join(order + '=' + str(inter['orders'][order]) \
3218 for order in inter['orders'])
3219 text += '\n'
3220 pydoc.pager(text)
3221
3222 elif args[0] == 'interactions' and len(args)==2 and args[1].isdigit():
3223 for arg in args[1:]:
3224 if int(arg) > len(self._curr_model['interactions']):
3225 raise self.InvalidCmd, 'no interaction %s in current model' % arg
3226 if int(arg) == 0:
3227 print 'Special interactions which identify two particles'
3228 else:
3229 print "Interactions %s has the following property:" % arg
3230 print self._curr_model['interactions'][int(arg)-1]
3231
3232 elif args[0] == 'interactions':
3233 request_part = args[1:]
3234 text = ''
3235 for i, inter in enumerate(self._curr_model['interactions']):
3236 present_part = [part['is_part'] and part['name'] or part['antiname']
3237 for part in inter['particles']
3238 if (part['is_part'] and part['name'] in request_part) or
3239 (not part['is_part'] and part['antiname'] in request_part)]
3240 if len(present_part) < len(request_part):
3241 continue
3242
3243 if set(present_part) != set(request_part):
3244 continue
3245
3246 if len(request_part) > len(set(request_part)):
3247 for p in request_part:
3248 if request_part.count(p) > present_part.count(p):
3249 continue
3250
3251 name = str(i+1) + ' : '
3252 for part in inter['particles']:
3253 if part['is_part']:
3254 name += part['name']
3255 else:
3256 name += part['antiname']
3257 name += " "
3258 text += "\nInteractions %s has the following property:\n" % name
3259 text += str(self._curr_model['interactions'][i])
3260
3261 text += '\n'
3262 print name
3263 if text =='':
3264 text += 'No matching for any interactions'
3265 pydoc.pager(text)
3266
3267
3268 elif args[0] == 'parameters' and len(args) == 1:
3269 text = "Current model contains %i parameters\n" % \
3270 sum([len(part) for part in
3271 self._curr_model['parameters'].values()])
3272 keys = self._curr_model['parameters'].keys()
3273 def key_sort(x, y):
3274 if ('external',) == x:
3275 return -1
3276 elif ('external',) == y:
3277 return +1
3278 elif len(x) < len(y):
3279 return -1
3280 else:
3281 return 1
3282 keys.sort(key_sort)
3283 for key in keys:
3284 item = self._curr_model['parameters'][key]
3285 text += '\nparameter type: %s\n' % str(key)
3286 for value in item:
3287 if hasattr(value, 'expr'):
3288 if value.value is not None:
3289 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value)
3290 else:
3291 text+= ' %s = %s\n' % (value.name, value.expr)
3292 else:
3293 if value.value is not None:
3294 text+= ' %s = %s\n' % (value.name, value.value)
3295 else:
3296 text+= ' %s \n' % (value.name)
3297 pydoc.pager(text)
3298
3299 elif args[0] == 'processes':
3300 for amp in self._curr_amps:
3301 print amp.nice_string_processes()
3302
3303 elif args[0] == 'diagrams_text':
3304 text = "\n".join([amp.nice_string() for amp in self._curr_amps])
3305 pydoc.pager(text)
3306
3307 elif args[0] == 'multiparticles':
3308 print 'Multiparticle labels:'
3309 for key in self._multiparticles:
3310 print self.multiparticle_string(key)
3311
3312 elif args[0] == 'coupling_order':
3313 hierarchy = self._curr_model['order_hierarchy'].items()
3314
3315 def order(first, second):
3316 if first[1] < second[1]:
3317 return -1
3318 else:
3319 return 1
3320 hierarchy.sort(order)
3321 for order in hierarchy:
3322 print ' %s : weight = %s' % order
3323
3324 elif args[0] == 'couplings' and len(args) == 1:
3325 if self._model_v4_path:
3326 print 'No couplings information available in V4 model'
3327 return
3328 text = ''
3329 text = "Current model contains %i couplings\n" % \
3330 sum([len(part) for part in
3331 self._curr_model['couplings'].values()])
3332 keys = self._curr_model['couplings'].keys()
3333 def key_sort(x, y):
3334 if ('external',) == x:
3335 return -1
3336 elif ('external',) == y:
3337 return +1
3338 elif len(x) < len(y):
3339 return -1
3340 else:
3341 return 1
3342 keys.sort(key_sort)
3343 for key in keys:
3344 item = self._curr_model['couplings'][key]
3345 text += '\ncouplings type: %s\n' % str(key)
3346 for value in item:
3347 if value.value is not None:
3348 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value)
3349 else:
3350 text+= ' %s = %s\n' % (value.name, value.expr)
3351
3352 pydoc.pager(text)
3353
3354 elif args[0] == 'couplings':
3355 if self._model_v4_path:
3356 print 'No couplings information available in V4 model'
3357 return
3358
3359 try:
3360 ufomodel = ufomodels.load_model(self._curr_model.get('name'))
3361 print 'Note that this is the UFO informations.'
3362 print ' "display couplings" present the actual definition'
3363 print 'prints the current states of mode'
3364 print eval('ufomodel.couplings.%s.nice_string()'%args[1])
3365 except Exception:
3366 raise self.InvalidCmd, 'no couplings %s in current model' % args[1]
3367
3368 elif args[0] == 'lorentz':
3369 if self._model_v4_path:
3370 print 'No lorentz information available in V4 model'
3371 return
3372 elif len(args) == 1:
3373 raise self.InvalidCmd,\
3374 'display lorentz require an argument: the name of the lorentz structure.'
3375 return
3376 try:
3377 ufomodel = ufomodels.load_model(self._curr_model.get('name'))
3378 print eval('ufomodel.lorentz.%s.nice_string()'%args[1])
3379 except Exception:
3380 raise self.InvalidCmd, 'no lorentz %s in current model' % args[1]
3381
3382 elif args[0] == 'checks':
3383 outstr = ''
3384 if self._comparisons:
3385 comparisons = self._comparisons[0]
3386 if len(args) > 1 and args[1] == 'failed':
3387 comparisons = [c for c in comparisons if not c['passed']]
3388 outstr += "Process check results:"
3389 for comp in comparisons:
3390 outstr += "\n%s:" % comp['process'].nice_string()
3391 outstr += "\n Phase space point: (px py pz E)"
3392 for i, p in enumerate(comp['momenta']):
3393 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p)
3394 outstr += "\n Permutation values:"
3395 outstr += "\n " + str(comp['values'])
3396 if comp['passed']:
3397 outstr += "\n Process passed (rel. difference %.9e)" % \
3398 comp['difference']
3399 else:
3400 outstr += "\n Process failed (rel. difference %.9e)" % \
3401 comp['difference']
3402
3403 used_aloha = sorted(self._comparisons[1])
3404 if used_aloha:
3405 outstr += "\nChecked ALOHA routines:"
3406 for aloha in used_aloha:
3407 aloha_str = aloha[0]
3408 if aloha[1]:
3409 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]])
3410 aloha_str += "_%d" % aloha[2]
3411 outstr += "\n" + aloha_str
3412
3413 outstr += '\n'
3414 for cms_check in self._cms_checks:
3415 outstr += '*'*102+'\n'
3416 outstr += 'Complex Mass Scheme check:\n'
3417 outstr += ' -> check %s\n'%cms_check['line']
3418 outstr += '*'*102+'\n'
3419 tmp_options = copy.copy(cms_check['options'])
3420 tmp_options['show_plot']=False
3421 outstr += process_checks.output_complex_mass_scheme(
3422 cms_check['cms_result'], cms_check['output_path'],
3423 tmp_options, self._curr_model) + '\n'
3424 outstr += '*'*102+'\n\n'
3425 pydoc.pager(outstr)
3426
3427 elif args[0] == 'options':
3428 if len(args) == 1:
3429 to_print = lambda name: True
3430 else:
3431 to_print = lambda name: any(poss in name for poss in args[1:])
3432
3433 outstr = " MadGraph5_aMC@NLO Options \n"
3434 outstr += " ---------------- \n"
3435 keys = self.options_madgraph.keys()
3436 keys.sort()
3437 for key in keys:
3438 if not to_print(key):
3439 continue
3440 default = self.options_madgraph[key]
3441 value = self.options[key]
3442 if value == default:
3443 outstr += " %25s \t:\t%s\n" % (key,value)
3444 else:
3445 outstr += " %25s \t:\t%s (user set)\n" % (key,value)
3446 outstr += "\n"
3447 outstr += " MadEvent Options \n"
3448 outstr += " ---------------- \n"
3449 keys = self.options_madevent.keys()
3450 keys.sort()
3451 for key in keys:
3452 if not to_print(key):
3453 continue
3454 default = self.options_madevent[key]
3455 value = self.options[key]
3456 if value == default:
3457 outstr += " %25s \t:\t%s\n" % (key,value)
3458 else:
3459 outstr += " %25s \t:\t%s (user set)\n" % (key,value)
3460 outstr += "\n"
3461 outstr += " Configuration Options \n"
3462 outstr += " --------------------- \n"
3463 keys = self.options_configuration.keys()
3464 keys.sort()
3465 for key in keys:
3466 if not to_print(key):
3467 continue
3468 default = self.options_configuration[key]
3469 value = self.options[key]
3470 if value == default:
3471 outstr += " %25s \t:\t%s\n" % (key,value)
3472 else:
3473 outstr += " %25s \t:\t%s (user set)\n" % (key,value)
3474
3475 output.write(outstr)
3476 elif args[0] in ["variable"]:
3477 super(MadGraphCmd, self).do_display(line, output)
3478
3479
3480 - def multiparticle_string(self, key):
3481 """Returns a nicely formatted string for the multiparticle"""
3482
3483 if self._multiparticles[key] and \
3484 isinstance(self._multiparticles[key][0], list):
3485 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\
3486 get('particle_dict')[part_id].get_name() \
3487 for part_id in id_list]) \
3488 for id_list in self._multiparticles[key]]))
3489 else:
3490 return "%s = %s" % (key, " ".join([self._curr_model.\
3491 get('particle_dict')[part_id].get_name() \
3492 for part_id in self._multiparticles[key]]))
3493
3519
3520
3521
3522 - def draw(self, line,selection='all',type=''):
3578
3579
3581 """Check a given process or set of processes"""
3582
3583 def create_lambda_values_list(lower_bound, N):
3584 """ Returns a list of values spanning the range [1.0, lower_bound] with
3585 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered
3586 by N values uniformly distributed. For example, lower_bound=1e-2
3587 and N=5 returns:
3588 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]"""
3589
3590 lCMS_values = [1]
3591 exp = 0
3592 n = 0
3593 while lCMS_values[-1]>=lower_bound:
3594 n = (n+1)
3595 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N)))
3596 if lCMS_values[-1]==lCMS_values[-2]:
3597 lCMS_values.pop()
3598 exp = (n+1)//N
3599
3600 lCMS_values = lCMS_values[:-1]
3601 if lCMS_values[-1]!=lower_bound:
3602 lCMS_values.append(lower_bound)
3603
3604 return lCMS_values
3605
3606
3607
3608 args = self.split_arg(line)
3609
3610 param_card = self.check_check(args)
3611
3612 options= {'events':None}
3613 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card):
3614 logger_check.info("Will use the param_card contained in the banner and the events associated")
3615 import madgraph.various.banner as banner
3616 options['events'] = param_card
3617 mybanner = banner.Banner(param_card)
3618 param_card = mybanner.charge_card('param_card')
3619
3620 aloha_lib.KERNEL.clean()
3621
3622 gauge = str(self.options['gauge'])
3623 options['reuse'] = args[1]=="-reuse"
3624 args = args[:1]+args[2:]
3625
3626
3627 if args[0] in ['stability', 'profile']:
3628 options['npoints'] = int(args[1])
3629 args = args[:1]+args[2:]
3630
3631 MLoptions={}
3632 i=-1
3633 CMS_options = {}
3634 while args[i].startswith('--'):
3635 option = args[i].split('=')
3636 if option[0] =='--energy':
3637 options['energy']=float(option[1])
3638 elif option[0]=='--split_orders':
3639 options['split_orders']=int(option[1])
3640 elif option[0]=='--helicity':
3641 try:
3642 options['helicity']=int(option[1])
3643 except ValueError:
3644 raise self.InvalidCmd("The value of the 'helicity' option"+\
3645 " must be an integer, not %s."%option[1])
3646 elif option[0]=='--reduction':
3647 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')]
3648 elif option[0]=='--collier_mode':
3649 MLoptions['COLLIERMode']=int(option[1])
3650 elif option[0]=='--collier_cache':
3651 MLoptions['COLLIERGlobalCache']=int(option[1])
3652 elif option[0]=='--collier_req_acc':
3653 if option[1]!='auto':
3654 MLoptions['COLLIERRequiredAccuracy']=float(option[1])
3655 elif option[0]=='--collier_internal_stability_test':
3656 MLoptions['COLLIERUseInternalStabilityTest']=eval(option[1])
3657 elif option[0]=='--CTModeRun':
3658 try:
3659 MLoptions['CTModeRun']=int(option[1])
3660 except ValueError:
3661 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\
3662 " must be an integer, not %s."%option[1])
3663 elif option[0]=='--offshellness':
3664 CMS_options['offshellness'] = float(option[1])
3665 if CMS_options['offshellness']<=-1.0:
3666 raise self.InvalidCmd('Offshellness must be number larger or'+
3667 ' equal to -1.0, not %f'%CMS_options['offshellness'])
3668 elif option[0]=='--analyze':
3669 options['analyze'] = option[1]
3670 elif option[0]=='--show_plot':
3671 options['show_plot'] = 'true' in option[1].lower()
3672 elif option[0]=='--report':
3673 options['report'] = option[1].lower()
3674 elif option[0]=='--seed':
3675 options['seed'] = int(option[1])
3676 elif option[0]=='--name':
3677 if '.' in option[1]:
3678 raise self.InvalidCmd("Do not specify the extension in the"+
3679 " name of the run")
3680 CMS_options['name'] = option[1]
3681 elif option[0]=='--resonances':
3682 if option[1]=='all':
3683 CMS_options['resonances'] = 'all'
3684 else:
3685 try:
3686 resonances=eval(option[1])
3687 except:
3688 raise self.InvalidCmd("Could not evaluate 'resonances'"+
3689 " option '%s'"%option[1])
3690 if isinstance(resonances,int) and resonances>0:
3691 CMS_options['resonances'] = resonances
3692 elif isinstance(resonances,list) and all(len(res)==2 and
3693 isinstance(res[0],int) and all(isinstance(i, int) for i in
3694 res[1]) for res in resonances):
3695 CMS_options['resonances'] = resonances
3696 else:
3697 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+
3698 " or and integer or a list of tuples of the form "+
3699 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1])
3700 elif option[0]=='--tweak':
3701
3702 value = option[1]
3703
3704 if value=='alltweaks':
3705 value=str(['default','seed667(seed667)','seed668(seed668)',
3706 'allwidths->0.9*allwidths(widths_x_0.9)',
3707 'allwidths->0.99*allwidths(widths_x_0.99)',
3708 'allwidths->1.01*allwidths(widths_x_1.01)',
3709 'allwidths->1.1*allwidths(widths_x_1.1)',
3710 'logp->logm(logp2logm)','logm->logp(logm2logp)'])
3711 try:
3712 tweaks = eval(value)
3713 if isinstance(tweaks, str):
3714 tweaks = [value]
3715 elif not isinstance(tweaks,list):
3716 tweaks = [value]
3717 except:
3718 tweaks = [value]
3719 if not all(isinstance(t,str) for t in tweaks):
3720 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value)
3721 CMS_options['tweak'] = []
3722 for tweakID, tweakset in enumerate(tweaks):
3723 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset)
3724 if specs:
3725 tweakset = specs.group('tweakset')
3726 name = specs.group('name')
3727 else:
3728 if tweakset!='default':
3729 name = 'tweak_%d'%(tweakID+1)
3730 else:
3731 name = ''
3732 new_tweak_set = {'custom':[],'params':{},'name':name}
3733 for tweak in tweakset.split('&'):
3734 if tweak=='default':
3735 continue
3736 if tweak.startswith('seed'):
3737 new_tweak_set['custom'].append(tweak)
3738 continue
3739 try:
3740 param, replacement = tweak.split('->')
3741 except ValueError:
3742 raise self.InvalidCmd("Tweak specification '%s'"%\
3743 tweak+" is incorrect. It should be of"+\
3744 " the form a->_any_function_of_(a,lambdaCMS).")
3745 if param in ['logp','logm','log'] and \
3746 replacement in ['logp','logm','log']:
3747 new_tweak_set['custom'].append(tweak)
3748 continue
3749 try:
3750
3751
3752 orig_param, orig_replacement = param, replacement
3753 replacement = replacement.replace(param,
3754 '__tmpprefix__%s'%param)
3755 param = '__tmpprefix__%s'%param
3756 res = float(eval(replacement.lower(),
3757 {'lambdacms':1.0,param.lower():98.85}))
3758 except:
3759 raise self.InvalidCmd("The substitution expression "+
3760 "'%s' for the tweaked parameter"%orig_replacement+
3761 " '%s' could not be evaluated. It must be an "%orig_param+
3762 "expression of the parameter and 'lambdaCMS'.")
3763 new_tweak_set['params'][param.lower()] = replacement.lower()
3764 CMS_options['tweak'].append(new_tweak_set)
3765
3766 elif option[0]=='--recompute_width':
3767 if option[1].lower() not in ['never','always','first_time','auto']:
3768 raise self.InvalidCmd("The option 'recompute_width' can "+\
3769 "only be 'never','always', 'first_time' or 'auto' (default).")
3770 CMS_options['recompute_width'] = option[1]
3771 elif option[0]=='--loop_filter':
3772
3773
3774
3775 CMS_options['loop_filter'] = '='.join(option[1:])
3776 elif option[0]=='--diff_lambda_power':
3777
3778
3779
3780
3781 try:
3782 CMS_options['diff_lambda_power']=float(option[1])
3783 except ValueError:
3784 raise self.InvalidCmd("the '--diff_lambda_power' option"+\
3785 " must be an integer or float, not '%s'."%option[1])
3786 elif option[0]=='--lambda_plot_range':
3787 try:
3788 plot_range=eval(option[1])
3789 except Exception as e:
3790 raise self.InvalidCmd("The plot range specified %s"%option[1]+\
3791 " is not a valid syntax. Error:\n%s"%str(e))
3792 if not isinstance(plot_range,(list,tuple)) or \
3793 len(plot_range)!=2 or any(not isinstance(p,(float,int))
3794 for p in plot_range):
3795 raise self.InvalidCmd("The plot range specified %s"\
3796 %option[1]+" is invalid")
3797 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range])
3798 elif option[0]=='--lambdaCMS':
3799 try:
3800 lambda_values = eval(option[1])
3801 except SyntaxError:
3802 raise self.InvalidCmd("'%s' is not a correct"%option[1]+
3803 " python expression for lambdaCMS values.")
3804 if isinstance(lambda_values,list):
3805 if lambda_values[0]!=1.0:
3806 raise self.InvalidCmd("The first value of the lambdaCMS values"+
3807 " specified must be 1.0, not %s"%str(lambda_values))
3808 for l in lambda_values:
3809 if not isinstance(l,float):
3810 raise self.InvalidCmd("All lambda CMS values must be"+
3811 " float, not '%s'"%str(l))
3812 elif isinstance(lambda_values,(tuple,float)):
3813
3814
3815
3816
3817 if isinstance(lambda_values, float):
3818
3819 lower_bound = lambda_values
3820 N = 10
3821 else:
3822 if isinstance(lambda_values[0],float) and \
3823 isinstance(lambda_values[1],int):
3824 lower_bound = lambda_values[0]
3825 N = lambda_values[1]
3826 else:
3827 raise self.InvalidCmd("'%s' must be a "%option[1]+
3828 "tuple with types (float, int).")
3829 lambda_values = create_lambda_values_list(lower_bound,N)
3830 else:
3831 raise self.InvalidCmd("'%s' must be an expression"%option[1]+
3832 " for either a float, tuple or list.")
3833 lower_bound = lambda_values[-1]
3834
3835
3836
3837
3838
3839
3840 CMS_options['lambdaCMS'] = lambda_values
3841 elif option[0]=='--cms':
3842 try:
3843 CMS_expansion_orders, CMS_expansion_parameters = \
3844 option[1].split(',')
3845 except ValueError:
3846 raise self.InvalidCmd("CMS expansion specification '%s'"%\
3847 args[i]+" is incorrect.")
3848 CMS_options['expansion_orders'] = [expansion_order for
3849 expansion_order in CMS_expansion_orders.split('&')]
3850 CMS_options['expansion_parameters'] = {}
3851 for expansion_parameter in CMS_expansion_parameters.split('&'):
3852 try:
3853 param, replacement = expansion_parameter.split('->')
3854 except ValueError:
3855 raise self.InvalidCmd("CMS expansion specification '%s'"%\
3856 expansion_parameter+" is incorrect. It should be of"+\
3857 " the form a->_any_function_of_(a,lambdaCMS).")
3858 try:
3859
3860
3861 orig_param, orig_replacement = param, replacement
3862 replacement = replacement.replace(param,
3863 '__tmpprefix__%s'%param)
3864 param = '__tmpprefix__%s'%param
3865 res = float(eval(replacement.lower(),
3866 {'lambdacms':1.0,param.lower():98.85}))
3867 except:
3868 raise self.InvalidCmd("The substitution expression "+
3869 "'%s' for CMS expansion parameter"%orig_replacement+
3870 " '%s' could not be evaluated. It must be an "%orig_param+
3871 "expression of the parameter and 'lambdaCMS'.")
3872
3873
3874 CMS_options['expansion_parameters'][param.lower()]=\
3875 replacement.lower()
3876 else:
3877 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0])
3878
3879 i=i-1
3880 args = args[:i+1]
3881
3882 if args[0]=='options':
3883
3884 logger_check.info("Options for the command 'check' are:")
3885 logger_check.info("{:<20} {}".format(' name','default value'))
3886 logger_check.info("-"*40)
3887 for key, value in options.items():
3888 logger_check.info("{:<20} = {}".format('--%s'%key,str(value)))
3889 return
3890
3891 if args[0].lower()=='cmsoptions':
3892
3893 logger_check.info("Special options for the command 'check cms' are:")
3894 logger_check.info("{:<20} {}".format(' name','default value'))
3895 logger_check.info("-"*40)
3896 for key, value in CMS_options.items():
3897 logger_check.info("{:<20} = {}".format('--%s'%key,str(value)))
3898 return
3899
3900
3901 if args[0]!='cms' and options['seed']!=-1:
3902
3903
3904
3905 logger_check.info('Setting random seed to %d.'%options['seed'])
3906 random.seed(options['seed'])
3907
3908 proc_line = " ".join(args[1:])
3909
3910 if not (args[0]=='cms' and options['analyze']!='None'):
3911 myprocdef = self.extract_process(proc_line)
3912
3913
3914 if not myprocdef:
3915 raise self.InvalidCmd("Empty or wrong format process, please try again.")
3916
3917 if myprocdef.get('NLO_mode')=='all':
3918 myprocdef.set('NLO_mode','virt')
3919 else:
3920 myprocdef = None
3921
3922
3923
3924 output_path = os.getcwd()
3925
3926 if args[0] in ['timing','stability', 'profile'] and not \
3927 myprocdef.get('perturbation_couplings'):
3928 raise self.InvalidCmd("Only loop processes can have their "+
3929 " timings or stability checked.")
3930
3931 if args[0]=='gauge' and \
3932 not myprocdef.get('perturbation_couplings') in [[],['QCD']]:
3933 raise self.InvalidCmd(
3934 """Feynman vs unitary gauge comparisons can only be done if there are no loop
3935 propagators affected by this gauge. Typically, either processes at tree level
3936 or including only QCD perturbations can be considered here.""")
3937
3938 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2:
3939 raise self.InvalidCmd("The current model does not allow for both "+\
3940 "Feynman and unitary gauge.")
3941
3942
3943 loggers = [logging.getLogger('madgraph.diagram_generation'),
3944 logging.getLogger('madgraph.loop_diagram_generation'),
3945 logging.getLogger('ALOHA'),
3946 logging.getLogger('madgraph.helas_objects'),
3947 logging.getLogger('madgraph.loop_exporter'),
3948 logging.getLogger('madgraph.export_v4'),
3949 logging.getLogger('cmdprint'),
3950 logging.getLogger('madgraph.model'),
3951 logging.getLogger('madgraph.base_objects')]
3952 old_levels = [log.level for log in loggers]
3953 for log in loggers:
3954 log.setLevel(logging.WARNING)
3955
3956
3957 cpu_time1 = time.time()
3958
3959
3960
3961
3962
3963
3964
3965 if myprocdef:
3966 if myprocdef.get('perturbation_couplings')==[]:
3967 aloha.loop_mode = False
3968
3969 comparisons = []
3970 gauge_result = []
3971 gauge_result_no_brs = []
3972 lorentz_result =[]
3973 nb_processes = 0
3974 timings = []
3975 stability = []
3976 profile_time = []
3977 profile_stab = []
3978 cms_results = []
3979
3980 if "_cuttools_dir" in dir(self):
3981 CT_dir = self._cuttools_dir
3982 else:
3983 CT_dir =""
3984 if "MLReductionLib" in MLoptions:
3985 if 1 in MLoptions["MLReductionLib"]:
3986 MLoptions["MLReductionLib"].remove(1)
3987
3988 TIR_dir={}
3989 if "_iregi_dir" in dir(self):
3990 TIR_dir['iregi_dir']=self._iregi_dir
3991 else:
3992 if "MLReductionLib" in MLoptions:
3993 if 3 in MLoptions["MLReductionLib"]:
3994 logger_check.warning('IREGI not available on your system; it will be skipped.')
3995 MLoptions["MLReductionLib"].remove(3)
3996
3997 if 'pjfry' in self.options and isinstance(self.options['pjfry'],str):
3998 TIR_dir['pjfry_dir']=self.options['pjfry']
3999 else:
4000 if "MLReductionLib" in MLoptions:
4001 if 2 in MLoptions["MLReductionLib"]:
4002 logger_check.warning('PJFRY not available on your system; it will be skipped.')
4003 MLoptions["MLReductionLib"].remove(2)
4004
4005 if 'golem' in self.options and isinstance(self.options['golem'],str):
4006 TIR_dir['golem_dir']=self.options['golem']
4007 else:
4008 if "MLReductionLib" in MLoptions:
4009 if 4 in MLoptions["MLReductionLib"]:
4010 logger_check.warning('GOLEM not available on your system; it will be skipped.')
4011 MLoptions["MLReductionLib"].remove(4)
4012
4013 if 'samurai' in self.options and isinstance(self.options['samurai'],str):
4014 TIR_dir['samurai_dir']=self.options['samurai']
4015 else:
4016 if "MLReductionLib" in MLoptions:
4017 if 5 in MLoptions["MLReductionLib"]:
4018 logger_check.warning('Samurai not available on your system; it will be skipped.')
4019 MLoptions["MLReductionLib"].remove(5)
4020
4021 if 'collier' in self.options and isinstance(self.options['collier'],str):
4022 TIR_dir['collier_dir']=self.options['collier']
4023 else:
4024 if "MLReductionLib" in MLoptions:
4025 if 7 in MLoptions["MLReductionLib"]:
4026 logger_check.warning('Collier not available on your system; it will be skipped.')
4027 MLoptions["MLReductionLib"].remove(7)
4028
4029 if 'ninja' in self.options and isinstance(self.options['ninja'],str):
4030 TIR_dir['ninja_dir']=self.options['ninja']
4031 else:
4032 if "MLReductionLib" in MLoptions:
4033 if 6 in MLoptions["MLReductionLib"]:
4034 logger_check.warning('Ninja not available on your system; it will be skipped.')
4035 MLoptions["MLReductionLib"].remove(6)
4036
4037 if args[0] in ['timing']:
4038 timings = process_checks.check_timing(myprocdef,
4039 param_card = param_card,
4040 cuttools=CT_dir,
4041 tir=TIR_dir,
4042 options = options,
4043 cmd = self,
4044 output_path = output_path,
4045 MLOptions = MLoptions
4046 )
4047
4048 if args[0] in ['stability']:
4049 stability=process_checks.check_stability(myprocdef,
4050 param_card = param_card,
4051 cuttools=CT_dir,
4052 tir=TIR_dir,
4053 options = options,
4054 output_path = output_path,
4055 cmd = self,
4056 MLOptions = MLoptions)
4057
4058 if args[0] in ['profile']:
4059
4060
4061 profile_time, profile_stab = process_checks.check_profile(myprocdef,
4062 param_card = param_card,
4063 cuttools=CT_dir,
4064 tir=TIR_dir,
4065 options = options,
4066 MLOptions = MLoptions,
4067 output_path = output_path,
4068 cmd = self)
4069
4070 if args[0] in ['gauge', 'full'] and \
4071 len(self._curr_model.get('gauge')) == 2 and\
4072 myprocdef.get('perturbation_couplings') in [[],['QCD']]:
4073
4074 line = " ".join(args[1:])
4075 myprocdef = self.extract_process(line)
4076 if gauge == 'unitary':
4077 myprocdef_unit = myprocdef
4078 self.do_set('gauge Feynman', log=False)
4079 myprocdef_feyn = self.extract_process(line)
4080 else:
4081 myprocdef_feyn = myprocdef
4082 self.do_set('gauge unitary', log=False)
4083 myprocdef_unit = self.extract_process(line)
4084
4085 nb_part_unit = len(myprocdef_unit.get('model').get('particles'))
4086 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles'))
4087 if nb_part_feyn == nb_part_unit:
4088 logger_check.error('No Goldstone present for this check!!')
4089 gauge_result_no_brs = process_checks.check_unitary_feynman(
4090 myprocdef_unit, myprocdef_feyn,
4091 param_card = param_card,
4092 options=options,
4093 cuttools=CT_dir,
4094 tir=TIR_dir,
4095 reuse = options['reuse'],
4096 output_path = output_path,
4097 cmd = self)
4098
4099
4100 self.do_set('gauge %s' % gauge, log=False)
4101 nb_processes += len(gauge_result_no_brs)
4102
4103 if args[0] in ['permutation', 'full']:
4104 comparisons = process_checks.check_processes(myprocdef,
4105 param_card = param_card,
4106 quick = True,
4107 cuttools=CT_dir,
4108 tir=TIR_dir,
4109 reuse = options['reuse'],
4110 cmd = self,
4111 output_path = output_path,
4112 options=options)
4113 nb_processes += len(comparisons[0])
4114
4115 if args[0] in ['lorentz', 'full']:
4116 myprocdeff = copy.copy(myprocdef)
4117 lorentz_result = process_checks.check_lorentz(myprocdeff,
4118 param_card = param_card,
4119 cuttools=CT_dir,
4120 tir=TIR_dir,
4121 reuse = options['reuse'],
4122 cmd = self,
4123 output_path = output_path,
4124 options=options)
4125 nb_processes += len(lorentz_result)
4126
4127 if args[0] in ['brs', 'full']:
4128 gauge_result = process_checks.check_gauge(myprocdef,
4129 param_card = param_card,
4130 cuttools=CT_dir,
4131 tir=TIR_dir,
4132 reuse = options['reuse'],
4133 cmd = self,
4134 output_path = output_path,
4135 options=options)
4136 nb_processes += len(gauge_result)
4137
4138
4139
4140 if args[0] in ['cms']:
4141
4142 cms_original_setup = self.options['complex_mass_scheme']
4143 process_line = " ".join(args[1:])
4144
4145 for key, value in CMS_options.items():
4146 if key=='tweak':
4147 continue
4148 if key not in options:
4149 options[key] = value
4150 else:
4151 raise MadGraph5Error,"Option '%s' is both in the option"%key+\
4152 " and CMS_option dictionary."
4153
4154 if options['analyze']=='None':
4155 cms_results = []
4156 for tweak in CMS_options['tweak']:
4157 options['tweak']=tweak
4158
4159 guessed_proc = myprocdef.get_process(
4160 [leg.get('ids')[0] for leg in myprocdef.get('legs')
4161 if not leg.get('state')],
4162 [leg.get('ids')[0] for leg in myprocdef.get('legs')
4163 if leg.get('state')])
4164 save_path = process_checks.CMS_save_path('pkl',
4165 {'ordered_processes':[guessed_proc.base_string()],
4166 'perturbation_orders':guessed_proc.get('perturbation_couplings')},
4167 self._curr_model, options, output_path=output_path)
4168 if os.path.isfile(save_path) and options['reuse']:
4169 cms_result = save_load_object.load_from_file(save_path)
4170 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"%
4171 (tweak['name'],save_path))
4172 if cms_result is None:
4173 raise self.InvalidCmd('The complex mass scheme check result'+
4174 " file below could not be read.\n %s"%save_path)
4175 else:
4176 cms_result = process_checks.check_complex_mass_scheme(
4177 process_line,
4178 param_card = param_card,
4179 cuttools=CT_dir,
4180 tir=TIR_dir,
4181 cmd = self,
4182 output_path = output_path,
4183 MLOptions = MLoptions,
4184 options=options)
4185
4186 save_path = process_checks.CMS_save_path('pkl', cms_result,
4187 self._curr_model, options, output_path=output_path)
4188 cms_results.append((cms_result,save_path,tweak['name']))
4189 else:
4190 cms_result = save_load_object.load_from_file(
4191 options['analyze'].split(',')[0])
4192 cms_results.append((cms_result,options['analyze'].split(',')[0],
4193 CMS_options['tweak'][0]['name']))
4194 if cms_result is None:
4195 raise self.InvalidCmd('The complex mass scheme check result'+
4196 " file below could not be read.\n %s"
4197 %options['analyze'].split(',')[0])
4198
4199
4200 self.do_set('complex_mass_scheme %s'%str(cms_original_setup),
4201 log=False)
4202
4203 nb_processes += len(cms_result['ordered_processes'])
4204
4205 cpu_time2 = time.time()
4206 logger_check.info("%i check performed in %s"% (nb_processes,
4207 misc.format_time(int(cpu_time2 - cpu_time1))))
4208
4209 if args[0] in ['cms']:
4210 text = "Note that the complex mass scheme test in principle only\n"
4211 text+= "works for stable particles in final states.\n\ns"
4212 if args[0] not in ['timing','stability', 'profile', 'cms']:
4213 if self.options['complex_mass_scheme']:
4214 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n"
4215 text+= "results only for stable particles in final states.\n\ns"
4216 elif not myprocdef.get('perturbation_couplings'):
4217 text = "Note That all width have been set to zero for those checks\n\n"
4218 else:
4219 text = "\n"
4220 else:
4221 text ="\n"
4222
4223 if timings:
4224 text += 'Timing result for the '+('optimized' if \
4225 self.options['loop_optimized_output'] else 'default')+' output:\n'
4226
4227 text += process_checks.output_timings(myprocdef, timings)
4228 if stability:
4229 text += 'Stability result for the '+('optimized' if \
4230 self.options['loop_optimized_output'] else 'default')+' output:\n'
4231 text += process_checks.output_stability(stability,output_path)
4232
4233 if profile_time and profile_stab:
4234 text += 'Timing result '+('optimized' if \
4235 self.options['loop_optimized_output'] else 'default')+':\n'
4236 text += process_checks.output_profile(myprocdef, profile_stab,
4237 profile_time, output_path, options['reuse']) + '\n'
4238 if lorentz_result:
4239 text += 'Lorentz invariance results:\n'
4240 text += process_checks.output_lorentz_inv(lorentz_result) + '\n'
4241 if gauge_result:
4242 text += 'Gauge results:\n'
4243 text += process_checks.output_gauge(gauge_result) + '\n'
4244 if gauge_result_no_brs:
4245 text += 'Gauge results (switching between Unitary/Feynman):\n'
4246 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n'
4247 if cms_results:
4248 text += 'Complex mass scheme results (varying width in the off-shell regions):\n'
4249 cms_result = cms_results[0][0]
4250 if len(cms_results)>1:
4251 analyze = []
4252 for i, (cms_res, save_path, tweakname) in enumerate(cms_results):
4253 save_load_object.save_to_file(save_path, cms_res)
4254 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"%
4255 (tweakname,save_path))
4256 if i==0:
4257 analyze.append(save_path)
4258 else:
4259 analyze.append('%s(%s)'%(save_path,tweakname))
4260 options['analyze']=','.join(analyze)
4261 options['tweak'] = CMS_options['tweak'][0]
4262
4263 self._cms_checks.append({'line':line, 'cms_result':cms_result,
4264 'options':options, 'output_path':output_path})
4265 text += process_checks.output_complex_mass_scheme(cms_result,
4266 output_path, options, self._curr_model,
4267 output='concise_text' if options['report']=='concise' else 'text')+'\n'
4268
4269 if comparisons and len(comparisons[0])>0:
4270 text += 'Process permutation results:\n'
4271 text += process_checks.output_comparisons(comparisons[0]) + '\n'
4272 self._comparisons = comparisons
4273
4274
4275 if len(text.split('\n'))>20 and not '-reuse' in line and text!='':
4276 if 'test_manager' not in sys.argv[0]:
4277 pydoc.pager(text)
4278
4279
4280 for i, log in enumerate(loggers):
4281 log.setLevel(old_levels[i])
4282
4283
4284
4285 if len(text.split('\n'))<=20 or options['reuse']:
4286
4287 logging.getLogger('madgraph.check_cmd').info(text)
4288 else:
4289 logging.getLogger('madgraph.check_cmd').debug(text)
4290
4291
4292 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL)
4293 if not options['reuse']:
4294 process_checks.clean_up(self._mgme_dir)
4295
4296
4318
4320 """Extract a process definition from a string. Returns
4321 a ProcessDefinition."""
4322
4323 orig_line = line
4324
4325 if not len(re.findall('>\D', line)) in [1,2]:
4326 self.do_help('generate')
4327 raise self.InvalidCmd('Wrong use of \">\" special character.')
4328
4329
4330
4331
4332 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)")
4333 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line)
4334
4335
4336
4337
4338
4339
4340 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$")
4341 proc_number_re = proc_number_pattern.match(line)
4342 if proc_number_re:
4343 proc_number = int(proc_number_re.group(2))
4344 line = proc_number_re.group(1)+ proc_number_re.group(3)
4345
4346
4347
4348 perturbation_couplings_pattern = \
4349 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\
4350 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
4351 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
4352 perturbation_couplings = ""
4353 LoopOption= 'tree'
4354 HasBorn= True
4355 if perturbation_couplings_re:
4356 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
4357 option=perturbation_couplings_re.group("option")
4358 if option:
4359 if option in self._valid_nlo_modes:
4360 LoopOption=option
4361 if option=='sqrvirt':
4362 LoopOption='virt'
4363 HasBorn=False
4364 elif option=='noborn':
4365 HasBorn=False
4366 else:
4367 raise self.InvalidCmd, "NLO mode %s is not valid. "%option+\
4368 "Valid modes are %s. "%str(self._valid_nlo_modes)
4369 else:
4370 LoopOption='all'
4371
4372 line = perturbation_couplings_re.group("proc")+\
4373 perturbation_couplings_re.group("rest")
4374
4375
4376 order_pattern = re.compile(\
4377 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\
4378 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*$")
4379 order_re = order_pattern.match(line)
4380 squared_orders = {}
4381 orders = {}
4382 constrained_orders = {}
4383
4384
4385
4386
4387 split_orders = []
4388 while order_re:
4389 type = order_re.group('type')
4390 if order_re.group('name').endswith('^2'):
4391 if type not in self._valid_sqso_types:
4392 raise self.InvalidCmd, "Type of squared order "+\
4393 "constraint '%s'"% type+" is not supported."
4394 if type == '=':
4395 name = order_re.group('name')
4396 value = order_re.group('value')
4397 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\
4398 {'n':name, 'v': value})
4399 type = "<="
4400 squared_orders[order_re.group('name')[:-2]] = \
4401 (int(order_re.group('value')),type)
4402 else:
4403 if type not in self._valid_amp_so_types:
4404 raise self.InvalidCmd, \
4405 "Amplitude order constraints can only be of type %s"%\
4406 (', '.join(self._valid_amp_so_types))+", not '%s'."%type
4407 name = order_re.group('name')
4408 value = int(order_re.group('value'))
4409 if type in ['=', '<=']:
4410 if type == '=' and value != 0:
4411 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\
4412 {'n':name, 'v': value})
4413 orders[name] = value
4414 elif type == "==":
4415 constrained_orders[name] = (value, type)
4416 if name not in squared_orders:
4417 squared_orders[name] = (2 * value,'==')
4418 if True:
4419 orders[name] = value
4420
4421 elif type == ">":
4422 constrained_orders[name] = (value, type)
4423 if name not in squared_orders:
4424 squared_orders[name] = (2 * value,'>')
4425
4426 line = order_re.group('before')
4427 order_re = order_pattern.match(line)
4428
4429
4430 if constrained_orders and LoopOption != 'tree':
4431 raise self.InvalidCmd, \
4432 "Amplitude order constraints (for not LO processes) can only be of type %s"%\
4433 (', '.join(['<=']))+", not '%s'."%type
4434
4435
4436
4437
4438
4439
4440 if orders=={} and squared_orders!={}:
4441 for order in squared_orders.keys():
4442 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>':
4443 orders[order]=squared_orders[order][0]
4444 else:
4445 orders[order]=99
4446
4447 if not self._curr_model['case_sensitive']:
4448
4449 line = line.lower()
4450
4451
4452 slash = line.find("/")
4453 dollar = line.find("$")
4454 forbidden_particles = ""
4455 if slash > 0:
4456 if dollar > slash:
4457 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line)
4458 else:
4459 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line)
4460 if forbidden_particles_re:
4461 forbidden_particles = forbidden_particles_re.group(2)
4462 line = forbidden_particles_re.group(1)
4463 if len(forbidden_particles_re.groups()) > 2:
4464 line = line + forbidden_particles_re.group(3)
4465
4466
4467 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line)
4468 forbidden_schannels = ""
4469 if forbidden_schannels_re:
4470 forbidden_schannels = forbidden_schannels_re.group(2)
4471 line = forbidden_schannels_re.group(1)
4472
4473
4474 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line)
4475 forbidden_onsh_schannels = ""
4476 if forbidden_onsh_schannels_re:
4477 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2)
4478 line = forbidden_onsh_schannels_re.group(1)
4479
4480
4481 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line)
4482 required_schannels = ""
4483 if required_schannels_re:
4484 required_schannels = required_schannels_re.group(2)
4485 line = required_schannels_re.group(1) + ">" + \
4486 required_schannels_re.group(3)
4487
4488 args = self.split_arg(line)
4489
4490 myleglist = base_objects.MultiLegList()
4491 state = False
4492
4493
4494 for part_name in args:
4495 if part_name == '>':
4496 if not myleglist:
4497 raise self.InvalidCmd, "No final state particles"
4498 state = True
4499 continue
4500
4501 mylegids = []
4502 if part_name in self._multiparticles:
4503 if isinstance(self._multiparticles[part_name][0], list):
4504 raise self.InvalidCmd,\
4505 "Multiparticle %s is or-multiparticle" % part_name + \
4506 " which can be used only for required s-channels"
4507 mylegids.extend(self._multiparticles[part_name])
4508 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit():
4509 if int(part_name) in self._curr_model.get('particle_dict'):
4510 mylegids.append(int(part_name))
4511 else:
4512 raise self.InvalidCmd, \
4513 "No pdg_code %s in model" % part_name
4514 else:
4515 mypart = self._curr_model['particles'].get_copy(part_name)
4516 if mypart:
4517 mylegids.append(mypart.get_pdg_code())
4518
4519 if mylegids:
4520 myleglist.append(base_objects.MultiLeg({'ids':mylegids,
4521 'state':state}))
4522 else:
4523 raise self.InvalidCmd, "No particle %s in model" % part_name
4524
4525
4526 if perturbation_couplings.lower()=='all':
4527 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings'])
4528
4529 if filter(lambda leg: leg.get('state') == True, myleglist):
4530
4531
4532 perturbation_couplings_list = perturbation_couplings.split()
4533 if perturbation_couplings_list==['']:
4534 perturbation_couplings_list=[]
4535
4536
4537 split_orders=list(set(perturbation_couplings_list+squared_orders.keys()))
4538 try:
4539 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else
4540 self._curr_model['order_hierarchy']
4541 [elem if not elem.endswith('.sqrt') else elem[:-5]])
4542 except KeyError:
4543 raise self.InvalidCmd, "The loaded model does not defined a "+\
4544 " coupling order hierarchy for these couplings: %s"%\
4545 str([so for so in split_orders if so!='WEIGHTED' and so not
4546 in self._curr_model['order_hierarchy'].keys()])
4547
4548
4549
4550
4551 if LoopOption=='tree':
4552 perturbation_couplings_list = []
4553 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']:
4554 if not isinstance(self._curr_model,loop_base_objects.LoopModel):
4555 raise self.InvalidCmd(\
4556 "The current model does not allow for loop computations.")
4557 else:
4558 for pert_order in perturbation_couplings_list:
4559 if pert_order not in self._curr_model['perturbation_couplings']:
4560 raise self.InvalidCmd(\
4561 "Perturbation order %s is not among" % pert_order + \
4562 " the perturbation orders allowed for by the loop model.")
4563 if not self.options['loop_optimized_output'] and \
4564 LoopOption not in ['tree','real'] and split_orders!=[]:
4565 logger.warning('The default output mode (loop_optimized_output'+\
4566 ' = False) does not support evaluations for given powers of'+\
4567 ' coupling orders. MadLoop output will therefore not be'+\
4568 ' able to provide such quantities.')
4569 split_orders = []
4570
4571
4572 forbidden_particle_ids = \
4573 self.extract_particle_ids(forbidden_particles)
4574 if forbidden_particle_ids and \
4575 isinstance(forbidden_particle_ids[0], list):
4576 raise self.InvalidCmd(\
4577 "Multiparticle %s is or-multiparticle" % part_name + \
4578 " which can be used only for required s-channels")
4579 forbidden_onsh_schannel_ids = \
4580 self.extract_particle_ids(forbidden_onsh_schannels)
4581 forbidden_schannel_ids = \
4582 self.extract_particle_ids(forbidden_schannels)
4583 if forbidden_onsh_schannel_ids and \
4584 isinstance(forbidden_onsh_schannel_ids[0], list):
4585 raise self.InvalidCmd,\
4586 "Multiparticle %s is or-multiparticle" % part_name + \
4587 " which can be used only for required s-channels"
4588 if forbidden_schannel_ids and \
4589 isinstance(forbidden_schannel_ids[0], list):
4590 raise self.InvalidCmd,\
4591 "Multiparticle %s is or-multiparticle" % part_name + \
4592 " which can be used only for required s-channels"
4593 required_schannel_ids = \
4594 self.extract_particle_ids(required_schannels)
4595 if required_schannel_ids and not \
4596 isinstance(required_schannel_ids[0], list):
4597 required_schannel_ids = [required_schannel_ids]
4598
4599 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()])
4600 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1:
4601 raise self.InvalidCmd(
4602 "At most one negative squared order constraint can be specified.")
4603
4604 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()])
4605
4606
4607 out = base_objects.ProcessDefinition({'legs': myleglist,
4608 'model': self._curr_model,
4609 'id': proc_number,
4610 'orders': orders,
4611 'squared_orders':sqorders_values,
4612 'sqorders_types':sqorders_types,
4613 'constrained_orders': constrained_orders,
4614 'forbidden_particles': forbidden_particle_ids,
4615 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids,
4616 'forbidden_s_channels': forbidden_schannel_ids,
4617 'required_s_channels': required_schannel_ids,
4618 'overall_orders': overall_orders,
4619 'perturbation_couplings': perturbation_couplings_list,
4620 'has_born':HasBorn,
4621 'NLO_mode':LoopOption,
4622 'split_orders':split_orders
4623 })
4624 return out
4625
4626
4627
4629 """ Routine to create the MultiProcess for the loop-induced case"""
4630
4631 args = self.split_arg(line)
4632
4633 warning_duplicate = True
4634 if '--no_warning=duplicate' in args:
4635 warning_duplicate = False
4636 args.remove('--no_warning=duplicate')
4637
4638
4639 self.check_add(args)
4640 if args[0] == 'process':
4641 args = args[1:]
4642
4643
4644
4645 if args[-1].startswith('--optimize'):
4646 optimize = True
4647 args.pop()
4648 else:
4649 optimize = False
4650
4651
4652 if not myprocdef:
4653 myprocdef = self.extract_process(' '.join(args))
4654
4655 myprocdef.set('NLO_mode', 'noborn')
4656
4657
4658 if not self._generate_info:
4659 self._generate_info = line
4660
4661
4662
4663
4664
4665
4666
4667 if self._curr_amps and self._curr_amps[0].get_ninitial() != \
4668 myprocdef.get_ninitial():
4669 raise self.InvalidCmd("Can not mix processes with different number of initial states.")
4670
4671 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \
4672 self._curr_amps[0]['has_born']):
4673 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process")
4674
4675
4676
4677 if len([1 for val in myprocdef.get('orders').values()+\
4678 myprocdef.get('squared_orders').values() if val<0])>1:
4679 raise MadGraph5Error("Negative coupling order constraints"+\
4680 " can only be given on one type of coupling and either on"+\
4681 " squared orders or amplitude orders, not both.")
4682
4683 cpu_time1 = time.time()
4684
4685
4686 if self.options['group_subprocesses'] == 'Auto':
4687 collect_mirror_procs = True
4688 else:
4689 collect_mirror_procs = self.options['group_subprocesses']
4690 ignore_six_quark_processes = \
4691 self.options['ignore_six_quark_processes'] if \
4692 "ignore_six_quark_processes" in self.options \
4693 else []
4694
4695
4696
4697 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef,
4698 collect_mirror_procs = collect_mirror_procs,
4699 ignore_six_quark_processes = ignore_six_quark_processes,
4700 optimize=optimize)
4701
4702 for amp in myproc.get('amplitudes'):
4703 if amp not in self._curr_amps:
4704 self._curr_amps.append(amp)
4705 if amp['has_born']:
4706 raise Exception
4707 elif warning_duplicate:
4708 raise self.InvalidCmd, "Duplicate process %s found. Please check your processes." % \
4709 amp.nice_string_processes()
4710
4711
4712 self._done_export = False
4713
4714 cpu_time2 = time.time()
4715
4716 nprocs = len(myproc.get('amplitudes'))
4717 ndiags = sum([amp.get_number_of_diagrams() for \
4718 amp in myproc.get('amplitudes')])
4719 logger.info("%i processes with %i diagrams generated in %0.3f s" % \
4720 (nprocs, ndiags, (cpu_time2 - cpu_time1)))
4721 ndiags = sum([amp.get_number_of_diagrams() for \
4722 amp in self._curr_amps])
4723 logger.info("Total: %i processes with %i diagrams" % \
4724 (len(self._curr_amps), ndiags))
4725
4726 @staticmethod
4728 """Takes a valid process and return
4729 a tuple (core_process, options). This removes
4730 - any NLO specifications.
4731 - any options
4732 [Used by MadSpin]
4733 """
4734
4735
4736
4737 line=procline
4738 pos1=line.find("[")
4739 if pos1>0:
4740 pos2=line.find("]")
4741 if pos2 >pos1:
4742 line=line[:pos1]+line[pos2+1:]
4743
4744
4745
4746
4747 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$")
4748 proc_number_re = proc_number_pattern.match(line)
4749 if proc_number_re:
4750 line = proc_number_re.group(1) + proc_number_re.group(3)
4751
4752
4753 pos=1000
4754
4755 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$")
4756 order_re = order_pattern.match(line)
4757 if (order_re):
4758 pos_order=line.find(order_re.group(2))
4759 if pos_order>0 and pos_order < pos : pos=pos_order
4760
4761
4762 slash = line.find("/")
4763 if slash > 0 and slash < pos: pos=slash
4764 dollar = line.find("$")
4765 if dollar > 0 and dollar < pos: pos=dollar
4766
4767 if pos<1000:
4768 proc_option=line[pos:]
4769 line=line[:pos]
4770 else:
4771 proc_option=""
4772
4773 return line, proc_option
4774
4776 """Takes a valid process and return
4777 a set of id of final states particles. [Used by MadSpin]
4778 """
4779
4780 if not self._curr_model['case_sensitive']:
4781 procline = procline.lower()
4782 pids = self._curr_model.get('name2pdg')
4783
4784
4785
4786
4787
4788
4789
4790 if ',' in procline:
4791 core, decay = procline.split(',', 1)
4792 core_final = self.get_final_part(core)
4793
4794
4795 all_decays = decay.split(',')
4796 nb_level, tmp_decay = 0, ''
4797 decays = []
4798
4799 for one_decay in all_decays:
4800 if '(' in one_decay:
4801 nb_level += 1
4802 if ')' in one_decay:
4803 nb_level -= 1
4804
4805 if nb_level:
4806 if tmp_decay:
4807 tmp_decay += ', %s' % one_decay
4808 else:
4809 tmp_decay = one_decay
4810 elif tmp_decay:
4811 final = '%s,%s' % (tmp_decay, one_decay)
4812 final = final.strip()
4813 assert final[0] == '(' and final[-1] == ')'
4814 final = final[1:-1]
4815 decays.append(final)
4816 tmp_decay = ''
4817 else:
4818 decays.append(one_decay)
4819
4820 for one_decay in decays:
4821 first = one_decay.split('>',1)[0].strip()
4822 if first in pids:
4823 pid = set([pids[first]])
4824 elif first in self._multiparticles:
4825 pid = set(self._multiparticles[first])
4826 else:
4827 raise Exception, 'invalid particle name: %s. ' % first
4828 core_final.difference_update(pid)
4829 core_final.update(self.get_final_part(one_decay))
4830
4831 return core_final
4832
4833
4834 final = set()
4835 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline)
4836 particles = final_states.groups()[0]
4837 for particle in particles.split():
4838 if particle in pids:
4839 final.add(pids[particle])
4840 elif particle in self._multiparticles:
4841 final.update(set(self._multiparticles[particle]))
4842 return final
4843
4844 - def extract_particle_ids(self, args):
4845 """Extract particle ids from a list of particle names. If
4846 there are | in the list, this corresponds to an or-list, which
4847 is represented as a list of id lists. An or-list is used to
4848 allow multiple required s-channel propagators to be specified
4849 (e.g. Z/gamma)."""
4850
4851 if isinstance(args, basestring):
4852 args.replace("|", " | ")
4853 args = self.split_arg(args)
4854 all_ids = []
4855 ids=[]
4856 for part_name in args:
4857 mypart = self._curr_model['particles'].get_copy(part_name)
4858 if mypart:
4859 ids.append([mypart.get_pdg_code()])
4860 elif part_name in self._multiparticles:
4861 ids.append(self._multiparticles[part_name])
4862 elif part_name == "|":
4863
4864 if ids:
4865 all_ids.append(ids)
4866 ids = []
4867 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()):
4868 ids.append([int(part_name)])
4869 else:
4870 raise self.InvalidCmd("No particle %s in model" % part_name)
4871 all_ids.append(ids)
4872
4873
4874 res_lists = []
4875 for i, id_list in enumerate(all_ids):
4876 res_lists.extend(diagram_generation.expand_list_list(id_list))
4877
4878 for ilist, idlist in enumerate(res_lists):
4879 set_dict = {}
4880 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \
4881 if i not in set_dict]
4882
4883 if len(res_lists) == 1:
4884 res_lists = res_lists[0]
4885
4886 return res_lists
4887
4889 """Optimize the order of particles in a pdg list, so that
4890 similar particles are next to each other. Sort according to:
4891 1. pdg > 0, 2. spin, 3. color, 4. mass > 0"""
4892
4893 if not pdg_list:
4894 return
4895 if not isinstance(pdg_list[0], int):
4896 return
4897
4898 model = self._curr_model
4899 pdg_list.sort(key = lambda i: i < 0)
4900 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion())
4901 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'),
4902 reverse = True)
4903 pdg_list.sort(key = lambda i: \
4904 model.get_particle(i).get('mass').lower() != 'zero')
4905
4907 """Recursively extract a decay chain process definition from a
4908 string. Returns a ProcessDefinition."""
4909
4910
4911 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*=\s*\d+\s*)*)$")
4912 proc_number_re = proc_number_pattern.match(line)
4913 overall_orders = {}
4914 if proc_number_re:
4915 proc_number = int(proc_number_re.group(2))
4916 line = proc_number_re.group(1)
4917 if proc_number_re.group(3):
4918 order_pattern = re.compile("^(.*?)\s*(\w+)\s*=\s*(\d+)\s*$")
4919 order_line = proc_number_re.group(3)
4920 order_re = order_pattern.match(order_line)
4921 while order_re:
4922 overall_orders[order_re.group(2)] = int(order_re.group(3))
4923 order_line = order_re.group(1)
4924 order_re = order_pattern.match(order_line)
4925 logger.info(line)
4926
4927
4928 index_comma = line.find(",")
4929 index_par = line.find(")")
4930 min_index = index_comma
4931 if index_par > -1 and (index_par < min_index or min_index == -1):
4932 min_index = index_par
4933
4934 if min_index > -1:
4935 core_process = self.extract_process(line[:min_index], proc_number,
4936 overall_orders)
4937 else:
4938 core_process = self.extract_process(line, proc_number,
4939 overall_orders)
4940
4941
4942
4943 while index_comma > -1:
4944 line = line[index_comma + 1:]
4945 if not line.strip():
4946 break
4947 index_par = line.find(')')
4948
4949 if line.lstrip()[0] == '(' and index_par !=-1 and \
4950 not ',' in line[:index_par]:
4951 par_start = line.find('(')
4952 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:])
4953 index_par = line.find(')')
4954 if line.lstrip()[0] == '(':
4955
4956
4957 line = line.lstrip()[1:]
4958
4959 decay_process, line = \
4960 self.extract_decay_chain_process(line,
4961 level_down=True)
4962 index_comma = line.find(",")
4963 index_par = line.find(')')
4964 else:
4965 index_comma = line.find(",")
4966 min_index = index_comma
4967 if index_par > -1 and \
4968 (index_par < min_index or min_index == -1):
4969 min_index = index_par
4970 if min_index > -1:
4971 decay_process = self.extract_process(line[:min_index])
4972 else:
4973 decay_process = self.extract_process(line)
4974
4975 core_process.get('decay_chains').append(decay_process)
4976
4977 if level_down:
4978 if index_par == -1:
4979 raise self.InvalidCmd, \
4980 "Missing ending parenthesis for decay process"
4981
4982 if index_par < index_comma:
4983 line = line[index_par + 1:]
4984 level_down = False
4985 break
4986
4987 if level_down:
4988 index_par = line.find(')')
4989 if index_par == -1:
4990 raise self.InvalidCmd, \
4991 "Missing ending parenthesis for decay process"
4992 line = line[index_par + 1:]
4993
4994
4995
4996 return core_process, line
4997
4998
4999
5001 """Main commands: Import files with external formats"""
5002
5003 args = self.split_arg(line)
5004
5005 self.check_import(args)
5006 if args[0].startswith('model'):
5007 self._model_v4_path = None
5008
5009 self._curr_amps = diagram_generation.AmplitudeList()
5010
5011 self._curr_proc_defs = base_objects.ProcessDefinitionList()
5012 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
5013
5014 if args[0].endswith('_v4'):
5015 self._curr_model, self._model_v4_path = \
5016 import_v4.import_model(args[1], self._mgme_dir)
5017 else:
5018
5019 if (args[1].startswith('loop_qcd_qed_sm') or\
5020 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\
5021 self.options['gauge']!='Feynman':
5022 logger.info('Switching to Feynman gauge because '+\
5023 'it is the only one supported by the model %s.'%args[1])
5024 self._curr_model = None
5025 self.do_set('gauge Feynman',log=False)
5026 prefix = not '--noprefix' in args
5027 if prefix:
5028 aloha.aloha_prefix='mdl_'
5029 else:
5030 aloha.aloha_prefix=''
5031
5032 try:
5033 self._curr_model = import_ufo.import_model(args[1], prefix=prefix,
5034 complex_mass_scheme=self.options['complex_mass_scheme'])
5035 except import_ufo.UFOImportError, error:
5036 if 'not a valid UFO model' in str(error):
5037 logger_stderr.warning('WARNING: %s' % error)
5038 logger_stderr.warning('Try to recover by running '+\
5039 'automatically `import model_v4 %s` instead.'% args[1])
5040 self.exec_cmd('import model_v4 %s ' % args[1], precmd=True)
5041 return
5042 if self.options['gauge']=='unitary':
5043 if not force and isinstance(self._curr_model,\
5044 loop_base_objects.LoopModel) and \
5045 self._curr_model.get('perturbation_couplings') not in \
5046 [[],['QCD']]:
5047 if 1 not in self._curr_model.get('gauge') :
5048 logger_stderr.warning('This model does not allow Feynman '+\
5049 'gauge. You will only be able to do tree level '+\
5050 'QCD loop cmputations with it.')
5051 else:
5052 logger.info('Change to the gauge to Feynman because '+\
5053 'this loop model allows for more than just tree level'+\
5054 ' and QCD perturbations.')
5055 self.do_set('gauge Feynman', log=False)
5056 return
5057 if 0 not in self._curr_model.get('gauge') :
5058 logger_stderr.warning('Change the gauge to Feynman since '+\
5059 'the model does not allow unitary gauge')
5060 self.do_set('gauge Feynman', log=False)
5061 return
5062 else:
5063 if 1 not in self._curr_model.get('gauge') :
5064 logger_stderr.warning('Change the gauge to unitary since the'+\
5065 ' model does not allow Feynman gauge.'+\
5066 ' Please re-import the model')
5067 self._curr_model = None
5068 self.do_set('gauge unitary', log= False)
5069 return
5070
5071 if '-modelname' not in args:
5072 self._curr_model.pass_particles_name_in_mg_default()
5073
5074
5075 self.process_model()
5076
5077 self._curr_amps = diagram_generation.AmplitudeList()
5078
5079 self._curr_proc_defs = base_objects.ProcessDefinitionList()
5080 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
5081 process_checks.store_aloha = []
5082
5083 elif args[0] == 'command':
5084
5085 if not os.path.isfile(args[1]):
5086 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1])
5087 else:
5088
5089
5090 self.check_for_export_dir(args[1])
5091
5092 self.import_command_file(args[1])
5093
5094 elif args[0] == 'banner':
5095 type = madevent_interface.MadEventCmd.detect_card_type(args[1])
5096 if type != 'banner':
5097 raise self.InvalidCmd, 'The File should be a valid banner'
5098 ban = banner_module.Banner(args[1])
5099
5100 if 'mg5proccard' in ban:
5101 for line in ban['mg5proccard'].split('\n'):
5102 if line.startswith('#') or line.startswith('<'):
5103 continue
5104 self.exec_cmd(line)
5105 else:
5106 raise self.InvalidCmd, 'Only MG5 banner are supported'
5107
5108 if not self._done_export:
5109 self.exec_cmd('output . -f')
5110
5111 ban.split(self._done_export[0])
5112 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards'))
5113 if '--no_launch' not in args:
5114 self.exec_cmd('launch')
5115
5116 elif args[0] == 'proc_v4':
5117
5118 if len(args) == 1 and self._export_dir:
5119 proc_card = pjoin(self._export_dir, 'Cards', \
5120 'proc_card.dat')
5121 elif len(args) == 2:
5122 proc_card = args[1]
5123
5124
5125 self.check_for_export_dir(os.path.realpath(proc_card))
5126 else:
5127 raise MadGraph5Error('No default directory in output')
5128
5129
5130
5131 self.import_mg4_proc_card(proc_card)
5132
5134 """ For simple decay chain: remove diagram that are not in the BR.
5135 param_card should be a ParamCard instance."""
5136
5137 assert isinstance(param_card, check_param_card.ParamCard)
5138
5139
5140 amplitudes = diagram_generation.AmplitudeList()
5141 for amp in self._curr_amps:
5142 amplitudes.extend(amp.get_amplitudes())
5143
5144 decay_tables = param_card['decay'].decay_table
5145 to_remove = []
5146 for amp in amplitudes:
5147 mother = [l.get('id') for l in amp['process'].get('legs') \
5148 if not l.get('state')]
5149 if 1 == len(mother):
5150 try:
5151 decay_table = decay_tables[abs(mother[0])]
5152 except KeyError:
5153 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0]))
5154 continue
5155
5156 child = [l.get('id') for l in amp['process'].get('legs') \
5157 if l.get('state')]
5158 if not mother[0] > 0:
5159 child = [x if self._curr_model.get_particle(x)['self_antipart']
5160 else -x for x in child]
5161 child.sort()
5162 child.insert(0, len(child))
5163
5164 if tuple(child) not in decay_table.keys():
5165 to_remove.append(amp)
5166
5167 def remove_amp(amps):
5168 for amp in amps[:]:
5169 if amp in to_remove:
5170 amps.remove(amp)
5171 if isinstance(amp, diagram_generation.DecayChainAmplitude):
5172 remove_amp(amp.get('decay_chains'))
5173 for decay in amp.get('decay_chains'):
5174 remove_amp(decay.get('amplitudes'))
5175 remove_amp(self._curr_amps)
5176
5177
5182
5184 """Set variables _particle_names and _couplings for tab
5185 completion, define multiparticles"""
5186
5187
5188 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\
5189 if p.get('propagating')] + \
5190 [p.get('antiname') for p in self._curr_model.get('particles') \
5191 if p.get('propagating')]
5192
5193 self._couplings = list(set(sum([i.get('orders').keys() for i in \
5194 self._curr_model.get('interactions')], [])))
5195
5196 self.add_default_multiparticles()
5197
5198
5227
5229 """ add default particle from file interface.multiparticles_default.txt
5230 """
5231
5232 defined_multiparticles = self._multiparticles.keys()
5233 removed_multiparticles = []
5234
5235
5236
5237 for key in self._multiparticles.keys():
5238 try:
5239 for part in self._multiparticles[key]:
5240 self._curr_model.get('particle_dict')[part]
5241 except Exception:
5242 del self._multiparticles[key]
5243 defined_multiparticles.remove(key)
5244 removed_multiparticles.append(key)
5245
5246
5247 for line in open(pjoin(MG5DIR, 'input', \
5248 'multiparticles_default.txt')):
5249 if line.startswith('#'):
5250 continue
5251 try:
5252 if not self._curr_model['case_sensitive']:
5253 multipart_name = line.lower().split()[0]
5254 else:
5255 multipart_name = line.split()[0]
5256 if multipart_name not in self._multiparticles:
5257
5258 self.exec_cmd('define %s' % line, printcmd=False, precmd=True)
5259 except self.InvalidCmd, why:
5260 logger_stderr.warning('impossible to set default multiparticles %s because %s' %
5261 (line.split()[0],why))
5262 if self.history[-1] == 'define %s' % line.strip():
5263 self.history.pop(-1)
5264 else:
5265 misc.sprint([self.history[-1], 'define %s' % line.strip()])
5266
5267 scheme = "old"
5268 for qcd_container in ['p', 'j']:
5269 if qcd_container not in self._multiparticles:
5270 continue
5271 multi = self._multiparticles[qcd_container]
5272 b = self._curr_model.get_particle(5)
5273 if not b:
5274 break
5275
5276 if 5 in multi:
5277 if b['mass'] != 'ZERO':
5278 multi.remove(5)
5279 multi.remove(-5)
5280 scheme = 4
5281 elif b['mass'] == 'ZERO':
5282 multi.append(5)
5283 multi.append(-5)
5284 scheme = 5
5285
5286 if scheme in [4,5]:
5287 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme)
5288 for container in ['p', 'j']:
5289 if container in defined_multiparticles:
5290 defined_multiparticles.remove(container)
5291 self.history.append("define p = %s # pass to %s flavors" % \
5292 (' ' .join([`i` for i in self._multiparticles['p']]),
5293 scheme)
5294 )
5295 self.history.append("define j = p")
5296
5297
5298 if defined_multiparticles:
5299 if 'all' in defined_multiparticles:
5300 defined_multiparticles.remove('all')
5301 logger.info("Kept definitions of multiparticles %s unchanged" % \
5302 " / ".join(defined_multiparticles))
5303
5304 for removed_part in removed_multiparticles:
5305 if removed_part in self._multiparticles:
5306 removed_multiparticles.remove(removed_part)
5307
5308 if removed_multiparticles:
5309 logger.info("Removed obsolete multiparticles %s" % \
5310 " / ".join(removed_multiparticles))
5311
5312
5313 line = []
5314 for part in self._curr_model.get('particles'):
5315 line.append('%s %s' % (part.get('name'), part.get('antiname')))
5316 line = 'all =' + ' '.join(line)
5317 self.do_define(line)
5318
5319 - def advanced_install(self, tool_to_install,
5320 HepToolsInstaller_web_address=None,
5321 additional_options=[]):
5322 """ Uses the HEPToolsInstaller.py script maintened online to install
5323 HEP tools with more complicated dependences.
5324 Additional options will be added to the list when calling HEPInstaller"""
5325
5326
5327 add_options = list(additional_options)
5328
5329
5330 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')):
5331 if HepToolsInstaller_web_address is None:
5332 raise MadGraph5Error, "The option 'HepToolsInstaller_web_address'"+\
5333 " must be specified in function advanced_install"+\
5334 " if the installers are not already downloaded."
5335 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')):
5336 os.mkdir(pjoin(MG5DIR,'HEPTools'))
5337 elif not HepToolsInstaller_web_address is None:
5338 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers'))
5339 if not HepToolsInstaller_web_address is None:
5340 logger.info('Downloading the HEPToolInstaller at:\n %s'%
5341 HepToolsInstaller_web_address)
5342
5343 if '//' in HepToolsInstaller_web_address:
5344 if sys.platform == "darwin":
5345 misc.call(['curl', HepToolsInstaller_web_address, '-o%s'
5346 %pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')],
5347 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'),
5348 cwd=MG5DIR)
5349 else:
5350 misc.call(['wget', HepToolsInstaller_web_address,
5351 '--output-document=%s'% pjoin(MG5DIR,'HEPTools',
5352 'HEPToolsInstallers.tar.gz')], stderr=open(os.devnull, 'w'),
5353 stdout=open(os.devnull, 'w'), cwd=MG5DIR)
5354 else:
5355
5356 shutil.copyfile(HepToolsInstaller_web_address,
5357 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'))
5358
5359
5360 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'],
5361 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w'))
5362
5363
5364 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'))
5365
5366
5367
5368 if '--local' in add_options:
5369 add_options.remove('--local')
5370 logger.warning('you are using a local installer. This is intended for debugging only!')
5371 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers'))
5372 shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir,
5373 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers'))
5374
5375
5376 name_map = {}
5377 try:
5378 tool = name_map[tool_to_install]
5379 except:
5380 tool = tool_to_install
5381
5382
5383 compiler_options = []
5384 if self.options['cpp_compiler'] is not None:
5385 compiler_options.append('--cpp_compiler=%s'%
5386 self.options['cpp_compiler'])
5387 compiler_options.append('--cpp_standard_lib=%s'%
5388 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler']))
5389 elif misc.which('g++'):
5390 compiler_options.append('--cpp_standard_lib=%s'%
5391 misc.detect_cpp_std_lib_dependence('g++'))
5392 else:
5393 compiler_options.append('--cpp_standard_lib=%s'%
5394 misc.detect_cpp_std_lib_dependence(None))
5395
5396 if not self.options['fortran_compiler'] is None:
5397 compiler_options.append('--fortran_compiler=%s'%
5398 self.options['fortran_compiler'])
5399
5400 if 'heptools_install_dir' in self.options:
5401 prefix = self.options['heptools_install_dir']
5402 config_file = '~/.mg5/mg5_configuration.txt'
5403 else:
5404 prefix = pjoin(MG5DIR, 'HEPTools')
5405 config_file = ''
5406
5407
5408 if tool=='mg5amc_py8_interface':
5409 add_options.append('--mg5_path=%s'%MG5DIR)
5410
5411 if misc.which('gnuplot') is None:
5412 logger.warning("==========")
5413 logger.warning("The optional dependency 'gnuplot' for the tool"+\
5414 " 'mg5amc_py8_interface' was not found. We recommend that you"+\
5415 " install it so as to be able to view the plots related to "+\
5416 " merging with Pythia 8.")
5417 logger.warning("==========")
5418 if self.options['pythia8_path']:
5419 add_options.append(
5420 '--with_pythia8=%s'%self.options['pythia8_path'])
5421
5422
5423 if tool=='madanalysis5':
5424 add_options.append('--mg5_path=%s'%MG5DIR)
5425 if not any(opt.startswith(('--with_fastjet', '--veto_fastjet')) for opt in add_options):
5426 fastjet_config = misc.which(self.options['fastjet'])
5427 if fastjet_config:
5428 add_options.append('--with_fastjet=%s'%fastjet_config)
5429
5430 if self.options['delphes_path'] and os.path.isdir(
5431 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))):
5432 add_options.append('--with_delphes3=%s'%\
5433 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path'])))
5434
5435 if tool=='pythia8':
5436
5437 lhapdf_config = misc.which(self.options['lhapdf'])
5438 lhapdf_version = None
5439 if lhapdf_config is None:
5440 lhapdf_version = None
5441 else:
5442 try:
5443 version = misc.Popen(
5444 [lhapdf_config,'--version'], stdout=subprocess.PIPE)
5445 lhapdf_version = int(version.stdout.read()[0])
5446 if lhapdf_version not in [5,6]:
5447 raise
5448 except:
5449 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+
5450 " sure '%s --version ' runs properly."%lhapdf_config)
5451
5452 if lhapdf_version is None:
5453 answer = self.ask(question=
5454 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+
5455 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >",
5456 default='y',text_format='33;32')
5457 if not answer.lower() in ['y','']:
5458 lhapdf_path = None
5459 else:
5460 self.advanced_install('lhapdf6',
5461 additional_options=add_options)
5462 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6')
5463 lhapdf_version = 6
5464 else:
5465 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\
5466 lhapdf_config),os.path.pardir))
5467 if lhapdf_version is None:
5468 logger.warning('You decided not to link the Pythia8 installation'+
5469 ' to LHAPDF. Beware that only built-in PDF sets can be used then.')
5470 else:
5471 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version)
5472 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN')
5473 lhapdf_option = []
5474 if lhapdf_version is None:
5475 lhapdf_option.append('--with_lhapdf6=OFF')
5476 lhapdf_option.append('--with_lhapdf5=OFF')
5477 elif lhapdf_version==5:
5478 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path)
5479 lhapdf_option.append('--with_lhapdf6=OFF')
5480 elif lhapdf_version==6:
5481 lhapdf_option.append('--with_lhapdf5=OFF')
5482 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path)
5483
5484 add_options = list(set(add_options))
5485
5486 add_options = [opt for opt in add_options if opt!='--force']+\
5487 (['--force'] if '--force' in add_options else [])
5488 return_code = misc.call([pjoin(MG5DIR,'HEPTools',
5489 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8',
5490 '--prefix=%s' % prefix]
5491 + lhapdf_option + compiler_options + add_options)
5492 else:
5493 logger.info('Now installing %s. Be patient...'%tool)
5494
5495 add_options = list(set(add_options))
5496
5497 add_options = [opt for opt in add_options if opt!='--force']+\
5498 (['--force'] if '--force' in add_options else [])
5499 return_code = misc.call([pjoin(MG5DIR,'HEPTools',
5500 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'%
5501 prefix] + compiler_options + add_options)
5502
5503 if return_code == 0:
5504 logger.info("%s successfully installed in %s."%(
5505 tool_to_install, prefix),'$MG:color:GREEN')
5506
5507 if tool=='madanalysis5':
5508 if not any(o.startswith(('--with_','--veto_','--update')) for o in add_options):
5509 logger.info(' To install recasting capabilities of madanalysis5 and/or', '$MG:color:BLACK')
5510 logger.info(' to allow delphes analysis at parton level.','$MG:color:BLACK')
5511 logger.info(' Please run \'install MadAnalysis5 --with_delphes --update\':', '$MG:color:BLACK')
5512
5513 elif return_code == 66:
5514 answer = self.ask(question=
5515 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, prefix)+
5516 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >"""
5517 ,default='y',text_format='33;32')
5518 if not answer.lower() in ['y','']:
5519 logger.info("Installation of %s aborted."%tool_to_install,
5520 '$MG:color:GREEN')
5521 return
5522 else:
5523 return self.advanced_install(tool_to_install,
5524 additional_options=add_options+['--force'])
5525 else:
5526 if tool=='madanalysis5' and '--update' not in add_options and \
5527 ('--no_MA5_further_install' not in add_options or
5528 '--no_root_in_MA5' in add_options):
5529 if not __debug__:
5530 logger.warning('Default installation of Madanalys5 failed.')
5531 logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.")
5532 logger.warning("This will however limit MA5 applicability for hadron-level analysis.")
5533 logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.")
5534 for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']:
5535 if option not in add_options:
5536 add_options.append(option)
5537 self.advanced_install('madanalysis5',
5538 HepToolsInstaller_web_address=HepToolsInstaller_web_address,
5539 additional_options=add_options)
5540 else:
5541 logger.critical("Default installation of Madanalys5 failed, we suggest you try again with the options '--no_MA5_further_install --no_root_in_MA5'.")
5542 raise self.InvalidCmd("Installation of %s failed."%tool_to_install)
5543
5544
5545 if tool == 'pythia8':
5546 self.options['pythia8_path'] = pjoin(prefix,'pythia8')
5547 self.exec_cmd('save options %s pythia8_path' % config_file, printcmd=False, log=False)
5548
5549
5550 self.advanced_install('mg5amc_py8_interface',
5551 additional_options=add_options+['--force'])
5552 elif tool == 'lhapdf6':
5553 self.options['lhapdf'] = pjoin(prefix,'lhapdf6','bin', 'lhapdf-config')
5554 self.exec_cmd('save options %s lhapdf' % config_file)
5555 elif tool == 'lhapdf5':
5556 self.options['lhapdf'] = pjoin(prefix,'lhapdf5','bin', 'lhapdf-config')
5557 self.exec_cmd('save options %s lhapdf' % config_file, printcmd=False, log=False)
5558 elif tool == 'madanalysis5':
5559 self.options['madanalysis5_path'] = pjoin(prefix, 'madanalysis5','madanalysis5')
5560 self.exec_cmd('save options madanalysis5_path', printcmd=False, log=False)
5561 elif tool == 'mg5amc_py8_interface':
5562
5563 if self.options['pythia8_path'] in ['',None,'None']:
5564 self.options['pythia8_path'] = pjoin(prefix,'pythia8')
5565 self.options['mg5amc_py8_interface_path'] = pjoin(prefix, 'MG5aMC_PY8_interface')
5566 self.exec_cmd('save options %s mg5amc_py8_interface_path' % config_file,
5567 printcmd=False, log=False)
5568 elif tool == 'collier':
5569 self.options['collier'] = pjoin(prefix,'lib')
5570 self.exec_cmd('save options %s collier' % config_file, printcmd=False, log=False)
5571 elif tool == 'ninja':
5572 if not misc.get_ninja_quad_prec_support(pjoin(
5573 prefix,'ninja','lib')):
5574 logger.warning(
5575 """Successful installation of Ninja, but without support for quadruple precision
5576 arithmetics. If you want to enable this (hence improving the treatment of numerically
5577 unstable points in the loop matrix elements) you can try to reinstall Ninja with:
5578 MG5aMC>install ninja
5579 After having made sure to have selected a C++ compiler in the 'cpp' option of
5580 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""")
5581 self.options['ninja'] = pjoin(prefix,'lib')
5582 self.exec_cmd('save options %s ninja' % config_file, printcmd=False, log=False)
5583
5584
5585
5586 path_to_be_set = []
5587 if sys.platform == "darwin":
5588 library_variables = ["DYLD_LIBRARY_PATH"]
5589 else:
5590 library_variables = ["LD_LIBRARY_PATH"]
5591 for variable in library_variables:
5592 if (variable not in os.environ) or \
5593 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\
5594 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)):
5595 path_to_be_set.append((variable,
5596 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))))
5597 for variable in ["PATH"]:
5598 if (variable not in os.environ) or \
5599 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\
5600 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)):
5601 path_to_be_set.append((variable,
5602 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))))
5603 if (variable not in os.environ) or \
5604 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\
5605 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)):
5606 path_to_be_set.append((variable,
5607 os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))))
5608
5609 if len(path_to_be_set)>0:
5610 shell_type = misc.get_shell_type()
5611 if shell_type in ['bash',None]:
5612 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.bashrc"%\
5613 (r'\n'.join('export %s=%s%s'%
5614 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set))
5615 elif shell_type=='tcsh':
5616 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.cshrc"%\
5617 (r'\n'.join('setenv %s %s%s'%
5618 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set))
5619
5620 logger.debug("==========")
5621 logger.debug("We recommend that you add to the following paths"+\
5622 " to your environment variables, so that you are guaranteed that"+\
5623 " at runtime, MG5_aMC will use the tools you have just installed"+\
5624 " and not some other versions installed elsewhere on your system.\n"+\
5625 "You can do so by running the following command in your terminal:"
5626 "\n %s"%modification_line)
5627 logger.debug("==========")
5628
5629
5630 return True
5631
5632 - def do_install(self, line, paths=None, additional_options=[]):
5633 """Install optional package from the MG suite.
5634 The argument 'additional_options' will be passed to the advanced_install
5635 functions. If it contains the option '--force', then the advanced_install
5636 function will overwrite any existing installation of the tool without
5637 warnings.
5638 """
5639
5640
5641 add_options = list(additional_options)
5642
5643 args = self.split_arg(line)
5644
5645 install_options = self.check_install(args)
5646
5647 if sys.platform == "darwin":
5648 program = "curl"
5649 else:
5650 program = "wget"
5651
5652
5653 if args[0] == 'update':
5654 self.install_update(['update']+install_options['update_options'],wget=program)
5655 return
5656
5657 plugin = ['maddm']
5658
5659 advertisements = {'pythia-pgs':['arXiv:0603175'],
5660 'Delphes':['arXiv:1307.6346'],
5661 'Delphes2':['arXiv:0903.2225'],
5662 'SysCalc':['arXiv:XXXX.YYYYY'],
5663 'Golem95':['arXiv:0807.0605'],
5664 'PJFry':['arXiv:1210.4095','arXiv:1112.0500'],
5665 'QCDLoop':['arXiv:0712.1851'],
5666 'pythia8':['arXiv:1410.3012'],
5667 'lhapdf6':['arXiv:1412.7420'],
5668 'lhapdf5':['arXiv:0605240'],
5669 'hepmc':['CPC 134 (2001) 41-46'],
5670 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'],
5671 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'],
5672 'MadAnalysis5':['arXiv:1206.1599'],
5673 'MadAnalysis':['arXiv:1206.1599'],
5674 'collier':['arXiv:1604.06792'],
5675 'oneloop':['arXiv:1007.4716'],
5676 'maddm':['arXiv:1505.04190']}
5677
5678
5679 if args[0] in advertisements:
5680
5681
5682
5683
5684
5685 logger.info(" You are installing '%s', please cite ref(s): \033[92m%s\033[0m. " % (args[0], ', '.join(advertisements[args[0]])), '$MG:color:BLACK')
5686
5687
5688 import urllib
5689 if paths:
5690 path = paths
5691 else:
5692 path = {}
5693
5694 data_path = ['http://madgraph.phys.ucl.ac.be/package_info.dat',
5695 'http://madgraph.physics.illinois.edu/package_info.dat']
5696
5697 r = random.randint(0,1)
5698 r = [r, (1-r)]
5699
5700 if any(a.startswith('--source=') for a in args):
5701 source = [a[9:] for a in args if a.startswith('--source=')][-1]
5702 if source == 'uiuc':
5703 r = [1]
5704 elif source == 'ucl':
5705 r = [0]
5706 else:
5707 data_path.append(source)
5708 r = [2]
5709 else:
5710 r = random.randint(0,1)
5711 r = [r, (1-r)]
5712
5713
5714
5715 for index in r:
5716 cluster_path = data_path[index]
5717 try:
5718 data = urllib.urlopen(cluster_path)
5719 except Exception:
5720 continue
5721 break
5722 else:
5723 raise MadGraph5Error, '''Impossible to connect any of us servers.
5724 Please check your internet connection or retry later'''
5725 for line in data:
5726 split = line.split()
5727 path[split[0]] = split[1]
5728
5729
5730
5731
5732
5733
5734
5735 if args[0] == 'Delphes':
5736 args[0] = 'Delphes3'
5737
5738 try:
5739 name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes',
5740 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs',
5741 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'madanalysis5',
5742 'MadAnalysis4':'MadAnalysis',
5743 'SysCalc':'SysCalc', 'Golem95': 'golem95',
5744 'PJFry':'PJFry','QCDLoop':'QCDLoop','MadAnalysis5':'madanalysis5'
5745 }
5746 name = name[args[0]]
5747 except KeyError:
5748 name = args[0]
5749
5750 if args[0] in self._advanced_install_opts:
5751
5752
5753
5754
5755 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \
5756 'MG5aMC_PY8_interface' in path else 'NA'
5757 add_options.append('--mg5amc_py8_interface_tarball=%s'%\
5758 MG5aMC_PY8_interface_path)
5759 add_options.extend(install_options['options_for_HEPToolsInstaller'])
5760 if not any(opt.startswith('--logging=') for opt in add_options):
5761 add_options.append('--logging=%d' % logger.level)
5762
5763 return self.advanced_install(name, path['HEPToolsInstaller'],
5764 additional_options = add_options)
5765
5766 if args[0] == 'PJFry' and not os.path.exists(
5767 pjoin(MG5DIR,'QCDLoop','lib','libqcdloop1.a')):
5768 logger.info("Installing PJFRY's dependence QCDLoop...")
5769 self.do_install('QCDLoop', paths=path)
5770
5771 if args[0] == 'Delphes':
5772 args[0] = 'Delphes3'
5773 if args[0] == 'MadAnalysis4':
5774 args[0] = 'MadAnalysis'
5775 try:
5776 name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes',
5777 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs',
5778 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'MadAnalysis',
5779 'SysCalc':'SysCalc', 'Golem95': 'golem95',
5780 'PJFry':'PJFry','QCDLoop':'QCDLoop',
5781 'maddm':'maddm'
5782 }
5783 name = name[args[0]]
5784 except:
5785 pass
5786
5787
5788 substitution={'Delphes2':'Delphes','pythia-pgs':'pythia8'}
5789 if args[0] in substitution:
5790 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\
5791 " You should consider installing and using %s, with:\n"%substitution[args[0]]+
5792 " > install %s"%substitution[args[0]])
5793
5794 try:
5795 os.system('rm -rf %s' % pjoin(MG5DIR, name))
5796 except Exception:
5797 pass
5798
5799
5800 logger.info('Downloading %s' % path[args[0]])
5801 if sys.platform == "darwin":
5802 misc.call(['curl', path[args[0]], '-o%s.tgz' % name], cwd=MG5DIR)
5803 else:
5804 misc.call(['wget', path[args[0]], '--output-document=%s.tgz'% name], cwd=MG5DIR)
5805
5806
5807 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR,
5808 stdout=open(os.devnull, 'w'))
5809
5810 if returncode:
5811 raise MadGraph5Error, 'Fail to download correctly the File. Stop'
5812
5813
5814
5815 if not os.path.exists(pjoin(MG5DIR, name)):
5816 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith(
5817 name.lower()) and not n.endswith('gz')]
5818 if not created_name:
5819 raise MadGraph5Error, 'The file was not loaded correctly. Stop'
5820 else:
5821 created_name = created_name[0]
5822 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name))
5823
5824
5825 logger.info('compile %s. This might take a while.' % name)
5826
5827
5828 if args[0] == "pythia-pgs" and sys.maxsize > 2**32:
5829 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts')
5830 text = open(path).read()
5831 text = text.replace('MBITS=32','MBITS=64')
5832 open(path, 'w').writelines(text)
5833 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')):
5834 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib'))
5835
5836 make_flags = []
5837
5838
5839 if 'FC' not in os.environ or not os.environ['FC']:
5840 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None':
5841 compiler = self.options['fortran_compiler']
5842 elif misc.which('gfortran'):
5843 compiler = 'gfortran'
5844 elif misc.which('g77'):
5845 compiler = 'g77'
5846 else:
5847 raise self.InvalidCmd('Require g77 or Gfortran compiler')
5848
5849 path = None
5850 base_compiler= ['FC=g77','FC=gfortran']
5851 if args[0] == "pythia-pgs":
5852 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts')
5853 elif args[0] == 'MadAnalysis':
5854 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile')
5855 if path:
5856 text = open(path).read()
5857 for base in base_compiler:
5858 text = text.replace(base,'FC=%s' % compiler)
5859 open(path, 'w').writelines(text)
5860 os.environ['FC'] = compiler
5861
5862
5863 if name == 'golem95':
5864
5865 ld_path = misc.Popen(['./configure',
5866 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']],
5867 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0]
5868
5869
5870 if name == 'PJFry':
5871
5872 ld_path = misc.Popen(['./configure',
5873 '--prefix=%s'%str(pjoin(MG5DIR, name)),
5874 '--enable-golem-mode', '--with-integrals=qcdloop1',
5875 'LDFLAGS=-L%s'%str(pjoin(MG5DIR,'QCDLoop','lib')),
5876 'FC=%s'%os.environ['FC'],
5877 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name),
5878 stdout=subprocess.PIPE).communicate()[0]
5879
5880
5881 if name == 'QCDLoop':
5882
5883 ld_path = misc.Popen(['./configure',
5884 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'],
5885 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name),
5886 stdout=subprocess.PIPE).communicate()[0]
5887
5888
5889 if args[0] == 'Delphes3':
5890
5891
5892
5893
5894 rootsys = os.environ['ROOTSYS']
5895 text = open(pjoin(MG5DIR, 'Delphes','Makefile')).read()
5896 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)',
5897 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys)
5898 open(pjoin(MG5DIR, 'Delphes','Makefile'),'w').write(text)
5899
5900
5901 if name == 'SysCalc':
5902 if self.options['lhapdf']:
5903 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'],
5904 stdout=subprocess.PIPE).communicate()[0]
5905 ld_path = ld_path.replace('\n','')
5906 if 'LD_LIBRARY_PATH' not in os.environ:
5907 os.environ['LD_LIBRARY_PATH'] = ld_path
5908 elif not os.environ['LD_LIBRARY_PATH']:
5909 os.environ['LD_LIBRARY_PATH'] = ld_path
5910 elif ld_path not in os.environ['LD_LIBRARY_PATH']:
5911 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path
5912 if self.options['lhapdf'] != 'lhapdf-config':
5913 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']):
5914 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH'])
5915 else:
5916 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6')
5917 if self.options['cpp_compiler']:
5918 make_flags.append('CXX=%s' % self.options['cpp_compiler'])
5919
5920
5921 if name in plugin:
5922 logger.info('no compilation needed for plugin. Loading plugin information')
5923 try:
5924 shutil.rmtree(pjoin(MG5DIR, 'PLUGIN', name))
5925 except Exception:
5926 pass
5927 shutil.move(pjoin(os.path.join(MG5DIR, name)), os.path.join(MG5DIR, 'PLUGIN', name))
5928
5929 try:
5930 __import__('PLUGIN.%s' % name, globals(), locals(), [], -1)
5931 plugin = sys.modules['PLUGIN.%s' % name]
5932 new_interface = plugin.new_interface
5933 new_output = plugin.new_output
5934 latest_validated_version = plugin.latest_validated_version
5935 minimal_mg5amcnlo_version = plugin.minimal_mg5amcnlo_version
5936 maximal_mg5amcnlo_version = plugin.maximal_mg5amcnlo_version
5937 except Exception, error:
5938 raise Exception, 'Plugin %s fail to be loaded. Please contact the author of the PLUGIN\n Error %s' % (name, error)
5939
5940 logger.info('Plugin %s correctly interfaced. Latest official validition for MG5aMC version %s.' % (name, '.'.join(`i` for i in latest_validated_version)))
5941 if new_interface:
5942 ff = open(pjoin(MG5DIR, 'bin', '%s.py' % name) , 'w')
5943 if __debug__:
5944 text = '''#! /usr/bin/env python
5945 import os
5946 import sys
5947 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
5948 exe_path = os.path.join(root_path,'bin','mg5_aMC')
5949 sys.argv.pop(0)
5950 os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) ))
5951 '''.format(name)
5952 else:
5953 text = '''#! /usr/bin/env python
5954 import os
5955 import sys
5956 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
5957 exe_path = os.path.join(root_path,'bin','mg5_aMC')
5958 sys.argv.pop(0)
5959 os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) ))
5960 '''.format(name)
5961 ff.write(text)
5962 ff.close()
5963 import stat
5964 os.chmod(pjoin(MG5DIR, 'bin', '%s.py' % name), stat.S_IRWXU)
5965 logger.info('To use this module, you need to quite MG5aMC and run the executable bin/%s.py' % name)
5966 status=0
5967
5968 elif logger.level <= logging.INFO:
5969 devnull = open(os.devnull,'w')
5970 try:
5971 misc.call(['make', 'clean'], stdout=devnull, stderr=-2)
5972 except Exception:
5973 pass
5974 if name == 'pythia-pgs':
5975
5976 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib'))
5977 if name in ['golem95','QCDLoop','PJFry']:
5978 status = misc.call(['make','install'],
5979 cwd = os.path.join(MG5DIR, name))
5980 else:
5981 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name))
5982 else:
5983 try:
5984 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name))
5985 except Exception:
5986 pass
5987 if name == 'pythia-pgs':
5988
5989 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib'))
5990 if name in ['golem95','QCDLoop','PJFry']:
5991 status = misc.compile(['install'], mode='',
5992 cwd = os.path.join(MG5DIR, name))
5993 else:
5994 status = self.compile(make_flags, mode='',
5995 cwd = os.path.join(MG5DIR, name))
5996
5997 if not status:
5998 logger.info('Installation succeeded')
5999 else:
6000
6001 if name == 'pythia-pgs':
6002 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio',
6003 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch']
6004 for f in to_comment:
6005 f = pjoin(MG5DIR, name, *f.split('/'))
6006 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l)
6007 fsock = open(f,'w').write(text)
6008 try:
6009 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name))
6010 except Exception:
6011 pass
6012 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name))
6013 if not status:
6014 logger.info('Compilation succeeded')
6015 else:
6016 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.')
6017
6018
6019
6020 if args[0] == 'MadAnalysis':
6021 try:
6022 os.system('rm -rf td')
6023 os.mkdir(pjoin(MG5DIR, 'td'))
6024 except Exception, error:
6025 print error
6026 pass
6027
6028 if sys.platform == "darwin":
6029 logger.info('Downloading TD for Mac')
6030 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td_mac_intel.tar.gz'
6031 misc.call(['curl', target, '-otd.tgz'],
6032 cwd=pjoin(MG5DIR,'td'))
6033 misc.call(['tar', '-xzpvf', 'td.tgz'],
6034 cwd=pjoin(MG5DIR,'td'))
6035 files.mv(MG5DIR + '/td/td_mac_intel',MG5DIR+'/td/td')
6036 else:
6037 if sys.maxsize > 2**32:
6038 logger.info('Downloading TD for Linux 64 bit')
6039 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td64/td'
6040 logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer.
6041 In 99% of the case, this is perfectly fine. If you do not have plot, please follow
6042 instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''')
6043 else:
6044 logger.info('Downloading TD for Linux 32 bit')
6045 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td'
6046 misc.call(['wget', target], cwd=pjoin(MG5DIR,'td'))
6047 os.chmod(pjoin(MG5DIR,'td','td'), 0775)
6048 self.options['td_path'] = pjoin(MG5DIR,'td')
6049
6050 if not misc.which('gs'):
6051 logger.warning('''gosthscript not install on your system. This is not required to run MA.
6052 but this prevent to create jpg files and therefore to have the plots in the html output.''')
6053 if sys.platform == "darwin":
6054 logger.warning('''You can download this program at the following link:
6055 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''')
6056
6057 if args[0] == 'Delphes2':
6058 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read()
6059 data = data.replace('data/', 'DELPHESDIR/data/')
6060 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w')
6061 out.write(data)
6062 if args[0] == 'Delphes3':
6063 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')):
6064 card_dir = pjoin(MG5DIR, 'Delphes','cards')
6065 else:
6066 card_dir = pjoin(MG5DIR, 'Delphes','examples')
6067 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'),
6068 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat'))
6069 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'),
6070 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat'))
6071 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'),
6072 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat'))
6073
6074
6075
6076 options_name = {'Delphes': 'delphes_path',
6077 'Delphes2': 'delphes_path',
6078 'Delphes3': 'delphes_path',
6079 'ExRootAnalysis': 'exrootanalysis_path',
6080 'MadAnalysis': 'madanalysis_path',
6081 'SysCalc': 'syscalc_path',
6082 'pythia-pgs':'pythia-pgs_path',
6083 'Golem95': 'golem',
6084 'PJFry': 'pjfry'}
6085
6086 if args[0] in options_name:
6087 opt = options_name[args[0]]
6088 if opt=='golem':
6089 self.options[opt] = pjoin(MG5DIR,name,'lib')
6090 self.exec_cmd('save options', printcmd=False)
6091 elif opt=='pjfry':
6092 self.options[opt] = pjoin(MG5DIR,'PJFry','lib')
6093 self.exec_cmd('save options', printcmd=False)
6094 elif self.options[opt] != self.options_configuration[opt]:
6095 self.options[opt] = self.options_configuration[opt]
6096 self.exec_cmd('save options',printcmd=False)
6097
6098
6099
6101 """ check if the current version of mg5 is up-to-date.
6102 and allow user to install the latest version of MG5 """
6103
6104 def apply_patch(filetext):
6105 """function to apply the patch"""
6106 text = filetext.read()
6107 pattern = re.compile(r'''=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''')
6108
6109 for orig, new in pattern.findall(text):
6110 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP'))
6111 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/')
6112 for i, name in enumerate(full_path):
6113 path = os.path.sep.join(full_path[:i+1])
6114 if path and not os.path.isdir(path):
6115 os.mkdir(path)
6116 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new))
6117 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP'))
6118
6119 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''')
6120
6121 for orig, new in pattern.findall(text):
6122 print 'move %s to %s' % (orig, new)
6123 try:
6124 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True)
6125 except IOError:
6126 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/')
6127 for i, name in enumerate(full_path):
6128 path = os.path.sep.join(full_path[:i+1])
6129 if path and not os.path.isdir(path):
6130 os.mkdir(path)
6131 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True)
6132
6133 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M)
6134 all_add = pattern.findall(text)
6135
6136
6137 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S)
6138 print 'this step can take a few minuts. please be patient'
6139 all_rm_add = pattern.findall(text)
6140
6141 for new in all_add:
6142 if new in all_rm_add:
6143 continue
6144 if os.path.isfile(pjoin(MG5DIR, new)):
6145 os.remove(pjoin(MG5DIR, new))
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE,
6158 cwd=MG5DIR)
6159 p.communicate(text)
6160
6161
6162
6163
6164
6165 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S)
6166 for match in pattern.findall(text):
6167 new = pjoin(MG5DIR, match[0])
6168 old = pjoin(MG5DIR, match[1])
6169 if new == old:
6170 continue
6171 elif os.path.exists(old):
6172 if not os.path.exists(os.path.dirname(new)):
6173 split = new.split('/')
6174 for i in range(1,len(split)):
6175 path = '/'.join(split[:i])
6176 if not os.path.exists(path):
6177 print 'mkdir', path
6178 os.mkdir(path)
6179 files.cp(old,new)
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200 for path in misc.glob('*', pjoin(MG5DIR, 'bin')):
6201 misc.call(['chmod', '+x', path])
6202 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')):
6203 misc.call(['chmod', '+x', path])
6204 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')):
6205 misc.call(['chmod', '+x', path])
6206 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')):
6207 misc.call(['chmod', '+x', path])
6208 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')):
6209 misc.call(['chmod', '+x', path])
6210
6211
6212 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M)
6213 for match in pattern.findall(text):
6214 if match[0] == 'file':
6215 new = os.path.dirname(pjoin(MG5DIR, match[1]))
6216 else:
6217 new = pjoin(MG5DIR, match[1])
6218 if not os.path.exists(new):
6219 split = new.split('/')
6220 for i in range(1,len(split)+1):
6221 path = '/'.join(split[:i])
6222 if path and not os.path.exists(path):
6223 print 'mkdir', path
6224 os.mkdir(path)
6225 if match[0] == 'file':
6226 print 'touch ', pjoin(MG5DIR, match[1])
6227 misc.call(['touch', pjoin(MG5DIR, match[1])])
6228
6229 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M)
6230 for new, old in pattern.findall(text):
6231 if not os.path.exists(pjoin(MG5DIR, new)):
6232 files.ln(old, os.path.dirname(new), os.path.basename(new))
6233
6234
6235 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')):
6236 misc.compile(cwd=pjoin(MG5DIR,'vendor','CutTools'))
6237 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')):
6238 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src'))
6239
6240
6241 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M)
6242 if pattern.search(text):
6243 return True
6244 else:
6245 return False
6246
6247 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')]
6248 if mode:
6249 mode = mode[-1]
6250 else:
6251 mode = "userrequest"
6252 force = any([arg=='-f' for arg in args])
6253 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')]
6254 if timeout:
6255 try:
6256 timeout = int(timeout[-1])
6257 except ValueError:
6258 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1])
6259 else:
6260 timeout = self.options['timeout']
6261 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')]
6262
6263 if input_path:
6264 fsock = open(input_path[0])
6265 need_binary = apply_patch(fsock)
6266 logger.info('manual patch apply. Please test your version.')
6267 if need_binary:
6268 logger.warning('Note that some files need to be loaded separately!')
6269 sys.exit(0)
6270
6271 options = ['y','n','on_exit']
6272 if mode == 'mg5_start':
6273 timeout = 2
6274 default = 'n'
6275 update_delay = self.options['auto_update'] * 24 * 3600
6276 if update_delay == 0:
6277 return
6278 elif mode == 'mg5_end':
6279 timeout = 5
6280 default = 'n'
6281 update_delay = self.options['auto_update'] * 24 * 3600
6282 if update_delay == 0:
6283 return
6284 options.remove('on_exit')
6285 elif mode == "userrequest":
6286 default = 'y'
6287 update_delay = 0
6288 else:
6289 raise self.InvalidCmd('Unknown mode for command install update')
6290
6291 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')) or \
6292 os.path.exists(os.path.join(MG5DIR,'.bzr')):
6293 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are:
6294 1) This version was loaded via bazaar (use bzr pull to update instead).
6295 2) This version is a beta release of MG5."""
6296 if mode == 'userrequest':
6297 raise self.ConfigurationError(error_text)
6298 return
6299
6300 if not misc.which('patch'):
6301 error_text = """Not able to find program \'patch\'. Please reload a clean version
6302 or install that program and retry."""
6303 if mode == 'userrequest':
6304 raise self.ConfigurationError(error_text)
6305 return
6306
6307
6308 data = {}
6309 for line in open(os.path.join(MG5DIR,'input','.autoupdate')):
6310 if not line.strip():
6311 continue
6312 sline = line.split()
6313 data[sline[0]] = int(sline[1])
6314
6315
6316 if 'version_nb' not in data:
6317 if mode == 'userrequest':
6318 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)'
6319 raise self.ConfigurationError(error_text)
6320 return
6321 elif 'last_check' not in data:
6322 data['last_check'] = time.time()
6323
6324
6325 if time.time() - data['last_check'] < update_delay:
6326 return
6327
6328 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout)
6329 class TimeOutError(Exception): pass
6330
6331 def handle_alarm(signum, frame):
6332 raise TimeOutError
6333
6334 signal.signal(signal.SIGALRM, handle_alarm)
6335 signal.alarm(timeout)
6336 to_update = 0
6337 try:
6338 filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/mg5amc_build_nb')
6339 signal.alarm(0)
6340 web_version = int(filetext.read().strip())
6341 except (TimeOutError, ValueError, IOError):
6342 signal.alarm(0)
6343 print 'failed to connect server'
6344 if mode == 'mg5_end':
6345
6346 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6347 fsock.write("version_nb %s\n" % data['version_nb'])
6348 fsock.write("last_check %s\n" % \
6349 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1))
6350 fsock.close()
6351 return
6352
6353 if web_version == data['version_nb']:
6354 logger.info('No new version of MG5 available')
6355
6356 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6357 fsock.write("version_nb %s\n" % data['version_nb'])
6358 fsock.write("last_check %s\n" % int(time.time()))
6359 fsock.close()
6360 return
6361 elif data['version_nb'] > web_version:
6362 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version))
6363 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6364 fsock.write("version_nb %s\n" % data['version_nb'])
6365 fsock.write("last_check %s\n" % int(time.time()))
6366 fsock.close()
6367 return
6368 else:
6369 if not force:
6370 answer = self.ask('New Version of MG5 available! Do you want to update your current version?',
6371 default, options)
6372 else:
6373 answer = default
6374
6375
6376 if answer == 'y':
6377 logger.info('start updating code')
6378 fail = 0
6379 for i in range(data['version_nb'], web_version):
6380 try:
6381 filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1))
6382
6383 except Exception:
6384 print 'fail to load patch to build #%s' % (i+1)
6385 fail = i
6386 break
6387 need_binary = apply_patch(filetext)
6388 if need_binary:
6389 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1)
6390 name = "extra_file%i" % (i+1)
6391 if sys.platform == "darwin":
6392 misc.call(['curl', path, '-o%s.tgz' % name], cwd=MG5DIR)
6393 else:
6394 misc.call(['wget', path, '--output-document=%s.tgz'% name], cwd=MG5DIR)
6395
6396 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR,
6397 stdout=open(os.devnull, 'w'))
6398
6399 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6400 if not fail:
6401 fsock.write("version_nb %s\n" % web_version)
6402 else:
6403 fsock.write("version_nb %s\n" % fail)
6404 fsock.write("last_check %s\n" % int(time.time()))
6405 fsock.close()
6406 logger.info('Refreshing installation of MG5aMC_PY8_interface.')
6407 self.do_install('mg5amc_py8_interface',additional_options=['--force'])
6408 logger.info('Checking current version. (type ctrl-c to bypass the check)')
6409 subprocess.call([os.path.join('tests','test_manager.py')],
6410 cwd=MG5DIR)
6411 print 'new version installed, please relaunch mg5'
6412 sys.exit(0)
6413 elif answer == 'n':
6414
6415 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6416 fsock.write("version_nb %s\n" % data['version_nb'])
6417 fsock.write("last_check %s\n" % int(time.time()))
6418 fsock.close()
6419 logger.info('Update bypassed.')
6420 logger.info('The next check for a new version will be performed in %s days' \
6421 % abs(self.options['auto_update']))
6422 logger.info('In order to change this delay. Enter the command:')
6423 logger.info('set auto_update X')
6424 logger.info('Putting X to zero will prevent this check at anytime.')
6425 logger.info('You can upgrade your version at any time by typing:')
6426 logger.info('install update')
6427 else:
6428
6429
6430 self.options['auto_update'] = -1 * self.options['auto_update']
6431
6432
6433
6435 """ assign all configuration variable from file
6436 ./input/mg5_configuration.txt. assign to default if not define """
6437
6438 if not self.options:
6439 self.options = dict(self.options_configuration)
6440 self.options.update(self.options_madgraph)
6441 self.options.update(self.options_madevent)
6442
6443 if not config_path:
6444 if os.environ.has_key('MADGRAPH_BASE'):
6445 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt')
6446 self.set_configuration(config_path, final=False)
6447 if 'HOME' in os.environ:
6448 config_path = pjoin(os.environ['HOME'],'.mg5',
6449 'mg5_configuration.txt')
6450 if os.path.exists(config_path):
6451 self.set_configuration(config_path, final=False)
6452 config_path = os.path.relpath(pjoin(MG5DIR,'input',
6453 'mg5_configuration.txt'))
6454 return self.set_configuration(config_path, final)
6455
6456 if not os.path.exists(config_path):
6457 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path)
6458 config_file = open(config_path)
6459
6460
6461 logger.info('load MG5 configuration from %s ' % config_file.name)
6462 for line in config_file:
6463 if '#' in line:
6464 line = line.split('#',1)[0]
6465 line = line.replace('\n','').replace('\r\n','')
6466 try:
6467 name, value = line.split('=')
6468 except ValueError:
6469 pass
6470 else:
6471 name = name.strip()
6472 value = value.strip()
6473 if name != 'mg5_path':
6474 self.options[name] = value
6475 if value.lower() == "none" or value=="":
6476 self.options[name] = None
6477
6478 self.options['stdout_level'] = logging.getLogger('madgraph').level
6479 if not final:
6480 return self.options
6481
6482
6483
6484
6485 for key in self.options:
6486 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path',
6487 'mg5amc_py8_interface_path','madanalysis5_path']:
6488 if self.options[key] in ['None', None]:
6489 self.options[key] = None
6490 continue
6491 path = self.options[key]
6492
6493 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')):
6494 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')):
6495 self.options['pythia8_path'] = None
6496 else:
6497 continue
6498
6499 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')):
6500 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')):
6501 self.options['mg5amc_py8_interface_path'] = None
6502 else:
6503 continue
6504
6505 if key == 'madanalysis5_path' and not os.path.isfile(pjoin(MG5DIR, path,'bin','ma5')):
6506 if not os.path.isfile(pjoin(path,'bin','ma5')):
6507 self.options['madanalysis5_path'] = None
6508 else:
6509 continue
6510
6511 if key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')):
6512 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')):
6513 self.options['hwpp_path'] = None
6514 else:
6515 continue
6516
6517 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')):
6518 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')):
6519 self.options['thepeg_path'] = None
6520 else:
6521 continue
6522
6523 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HEPEVT_Wrapper.h')):
6524 if not os.path.isfile(pjoin(path, 'include', 'HEPEVT_Wrapper.h')):
6525 self.options['hepmc_path'] = None
6526 else:
6527 continue
6528
6529 elif key in ['pjfry','golem','samurai']:
6530 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto':
6531
6532 program = misc.which_lib('lib%s.a'%key)
6533 if program != None:
6534 fpath, _ = os.path.split(program)
6535 logger.info('Using %s library in %s' % (key,fpath))
6536 self.options[key]=fpath
6537 else:
6538
6539 local_install = {'pjfry':'PJFRY', 'golem':'golem95',
6540 'samurai':'samurai'}
6541 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)):
6542 self.options[key]=pjoin(MG5DIR,local_install[key],'lib')
6543 else:
6544 self.options[key]=None
6545
6546 if key=='samurai' and \
6547 isinstance(self.options[key],str) and \
6548 self.options[key].lower() != 'auto':
6549 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')):
6550 try:
6551 version = open(pjoin(self.options[key],os.pardir,
6552 'VERSION'),'r').read()
6553 except IOError:
6554 version = None
6555 if version is None:
6556 self.options[key] = None
6557 logger.info('--------')
6558 logger.info(
6559 """The version of 'samurai' automatically detected seems too old to be compatible
6560 with MG5aMC and it will be turned off. Ask the authors for the latest version if
6561 you want to use samurai.
6562 If you want to enforce its use as-it-is, then specify directly its library folder
6563 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""")
6564 logger.info('--------')
6565
6566 elif key.endswith('path'):
6567 pass
6568 elif key in ['run_mode', 'auto_update']:
6569 self.options[key] = int(self.options[key])
6570 elif key in ['cluster_type','automatic_html_opening']:
6571 pass
6572 elif key in ['notification_center']:
6573 if self.options[key] in ['False', 'True']:
6574 self.allow_notification_center = eval(self.options[key])
6575 self.options[key] = self.allow_notification_center
6576 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']:
6577
6578 try:
6579 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False)
6580 except MadGraph5Error, error:
6581 print error
6582 logger.warning("Option %s from config file not understood" \
6583 % key)
6584 else:
6585 if key in self.options_madgraph:
6586 self.history.append('set %s %s' % (key, self.options[key]))
6587
6588 warnings = madevent_interface.MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options)
6589 if warnings:
6590 logger.warning(warnings)
6591
6592
6593 launch_ext.open_file.configure(self.options)
6594 return self.options
6595
6597 """Check if the files is in a valid export directory and assign it to
6598 export path if if is"""
6599
6600
6601 if self._export_dir:
6602 return
6603
6604 if os.path.exists(pjoin(os.getcwd(), 'Cards')):
6605 self._export_dir = os.getcwd()
6606 return
6607
6608 path_split = filepath.split(os.path.sep)
6609 if len(path_split) > 2 and path_split[-2] == 'Cards':
6610 self._export_dir = os.path.sep.join(path_split[:-2])
6611 return
6612
6614 """Main commands: Ask for editing the parameter and then
6615 Execute the code (madevent/standalone/...)
6616 """
6617
6618
6619 current_options = dict([(name, self.options[name]) for name in self.options_madgraph])
6620 start_cwd = os.getcwd()
6621
6622 args = self.split_arg(line)
6623
6624 (options, args) = _launch_parser.parse_args(args)
6625 self.check_launch(args, options)
6626 options = options.__dict__
6627
6628
6629 if args[0].startswith('standalone'):
6630 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\
6631 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\
6632 os.getcwd(),args[1],'SubProcesses','check_poles.f')):
6633 ext_program = launch_ext.MadLoopLauncher(self, args[1], \
6634 options=self.options, **options)
6635 else:
6636 ext_program = launch_ext.SALauncher(self, args[1], \
6637 options=self.options, **options)
6638 elif args[0] == 'madevent':
6639 if options['interactive']:
6640
6641 if isinstance(self, cmd.CmdShell):
6642 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options)
6643 else:
6644 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options)
6645 ME.pass_in_web_mode()
6646 stop = self.define_child_cmd_interface(ME)
6647 return stop
6648
6649
6650 if not self._generate_info:
6651
6652
6653 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read()
6654 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1]
6655 generate_info = generate_info.split('#')[0]
6656 else:
6657 generate_info = self._generate_info
6658
6659 if len(generate_info.split('>')[0].strip().split())>1:
6660 ext_program = launch_ext.MELauncher(args[1], self,
6661 shell = isinstance(self, cmd.CmdShell),
6662 options=self.options,**options)
6663 else:
6664
6665 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV',
6666 shell = isinstance(self, cmd.CmdShell),
6667 options=self.options,**options)
6668
6669 elif args[0] == 'pythia8':
6670 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options)
6671
6672 elif args[0] == 'aMC@NLO':
6673 if options['interactive']:
6674 if isinstance(self, cmd.CmdShell):
6675 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options)
6676 else:
6677 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options)
6678 ME.pass_in_web_mode()
6679
6680 config_line = [l for l in self.history if l.strip().startswith('set')]
6681 for line in config_line:
6682 ME.exec_cmd(line)
6683 stop = self.define_child_cmd_interface(ME)
6684 return stop
6685 ext_program = launch_ext.aMCatNLOLauncher( args[1], self,
6686 shell = isinstance(self, cmd.CmdShell),
6687 **options)
6688 elif args[0] == 'madweight':
6689 import madgraph.interface.madweight_interface as madweight_interface
6690 if options['interactive']:
6691 if isinstance(self, cmd.CmdShell):
6692 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options)
6693 else:
6694 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options)
6695
6696 config_line = [l for l in self.history if l.strip().startswith('set')]
6697 for line in config_line:
6698 MW.exec_cmd(line)
6699 stop = self.define_child_cmd_interface(MW)
6700 return stop
6701 ext_program = launch_ext.MWLauncher( self, args[1],
6702 shell = isinstance(self, cmd.CmdShell),
6703 options=self.options,**options)
6704 else:
6705 os.chdir(start_cwd)
6706 raise self.InvalidCmd , '%s cannot be run from MG5 interface' % args[0]
6707
6708
6709 ext_program.run()
6710 os.chdir(start_cwd)
6711
6712 for key, value in current_options.items():
6713 self.options[key] = value
6714
6771
6772
6774 """create a restriction card in a interactive way"""
6775
6776 args = self.split_arg(line)
6777 self.check_customize_model(args)
6778
6779 model_path = self._curr_model.get('modelpath')
6780 if not os.path.exists(pjoin(model_path,'build_restrict.py')):
6781 raise self.InvalidCmd('''Model not compatible with this option.''')
6782
6783
6784 self._curr_model = import_ufo.import_model(model_path, restrict=False)
6785
6786
6787 out_path = StringIO.StringIO()
6788 param_writer.ParamCardWriter(self._curr_model, out_path)
6789
6790 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n'))
6791
6792
6793 all_categories = self.ask('','0',[], ask_class=AskforCustomize)
6794 put_to_one = []
6795
6796 for block in param_card:
6797 value_dict = {}
6798 for param in param_card[block]:
6799 value = param.value
6800 if value == 0:
6801 param.value = 0.000001e-99
6802 elif value == 1:
6803 if block != 'qnumbers':
6804 put_to_one.append((block,param.lhacode))
6805 param.value = random.random()
6806 elif abs(value) in value_dict:
6807 param.value += value_dict[abs(value)] * 1e-4 * param.value
6808 value_dict[abs(value)] += 1
6809 else:
6810 value_dict[abs(value)] = 1
6811
6812 for category in all_categories:
6813 for options in category:
6814 if not options.status:
6815 continue
6816 param = param_card[options.lhablock].get(options.lhaid)
6817 param.value = options.value
6818
6819 logger.info('Loading the resulting model')
6820
6821 self._curr_model = import_ufo.RestrictModel(self._curr_model)
6822 model_name = self._curr_model.get('name')
6823 if model_name == 'mssm':
6824 keep_external=True
6825 else:
6826 keep_external=False
6827 self._curr_model.restrict_model(param_card,keep_external=keep_external)
6828
6829 if args:
6830 name = args[0].split('=',1)[1]
6831 path = pjoin(model_path,'restrict_%s.dat' % name)
6832 logger.info('Save restriction file as %s' % path)
6833 param_card.write(path)
6834 self._curr_model['name'] += '-%s' % name
6835
6836
6837 if put_to_one:
6838 out_path = StringIO.StringIO()
6839 param_writer.ParamCardWriter(self._curr_model, out_path)
6840
6841 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n'))
6842
6843 for (block, lhacode) in put_to_one:
6844 misc.sprint(block, lhacode)
6845 try:
6846 param_card[block].get(lhacode).value = 1
6847 except:
6848 pass
6849 self._curr_model.set_parameters_and_couplings(param_card)
6850
6851 if args:
6852 name = args[0].split('=',1)[1]
6853 path = pjoin(model_path,'paramcard_%s.dat' % name)
6854 logger.info('Save default card file as %s' % path)
6855 param_card.write(path)
6856
6857 - def do_save(self, line, check=True, to_keep={}, log=True):
6858 """Not in help: Save information to file"""
6859
6860 args = self.split_arg(line)
6861
6862 if check:
6863 self.check_save(args)
6864
6865 if args[0] == 'model':
6866 if self._curr_model:
6867
6868 if save_load_object.save_to_file(args[1], self._curr_model):
6869 logger.info('Saved model to file %s' % args[1])
6870 else:
6871 raise self.InvalidCmd('No model to save!')
6872 elif args[0] == 'processes':
6873 if self._curr_amps:
6874 if save_load_object.save_to_file(args[1], (self._curr_amps,self._curr_proc_defs) ):
6875 logger.info('Saved processes to file %s' % args[1])
6876 else:
6877 raise self.InvalidCmd('No processes to save!')
6878
6879 elif args[0] == 'options':
6880 partial_save = False
6881 to_define = {}
6882
6883 if any(not arg.startswith('--') and arg in self.options
6884 for arg in args):
6885
6886 partial_save = True
6887 all_arg = [arg for arg in args[1:] if not arg.startswith('--') and
6888 arg in self.options]
6889 for key in all_arg:
6890 to_define[key] = self.options[key]
6891 else:
6892
6893 for key, default in self.options_configuration.items():
6894 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None:
6895 to_define[key] = self.options[key]
6896
6897 if not '--auto' in args:
6898 for key, default in self.options_madevent.items():
6899 if self.options_madevent[key] != self.options[key] != None:
6900 if '_path' in key and os.path.basename(self.options[key]) == 'None':
6901 continue
6902 to_define[key] = self.options[key]
6903 elif key == 'cluster_queue' and self.options[key] is None:
6904 to_define[key] = self.options[key]
6905
6906 if '--all' in args:
6907 for key, default in self.options_madgraph.items():
6908 if self.options_madgraph[key] != self.options[key] != None and \
6909 key != 'stdout_level':
6910 to_define[key] = self.options[key]
6911 elif not '--auto' in args:
6912 for key, default in self.options_madgraph.items():
6913 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level':
6914 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \
6915 % (key,self.options_madgraph[key]) )
6916 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'')
6917
6918 if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options:
6919 filepath = args[1]
6920 else:
6921 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
6922
6923 basedir = MG5DIR
6924 if partial_save:
6925 basefile = filepath
6926 else:
6927 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt')
6928
6929
6930
6931 if to_keep:
6932 to_define = to_keep
6933 self.write_configuration(filepath, basefile, basedir, to_define)
6934
6935
6936 - def do_set(self, line, log=True, model_reload=True):
6937 """Set an option, which will be default for coming generations/outputs.
6938 """
6939
6940
6941
6942 args = self.split_arg(line)
6943
6944
6945 self.check_set(args)
6946
6947 if args[0] == 'ignore_six_quark_processes':
6948 if args[1] == 'False':
6949 self.options[args[0]] = False
6950 return
6951 self.options[args[0]] = list(set([abs(p) for p in \
6952 self._multiparticles[args[1]]\
6953 if self._curr_model.get_particle(p).\
6954 is_fermion() and \
6955 self._curr_model.get_particle(abs(p)).\
6956 get('color') == 3]))
6957 if log:
6958 logger.info('Ignore processes with >= 6 quarks (%s)' % \
6959 ",".join([\
6960 self._curr_model.get_particle(q).get('name') \
6961 for q in self.options[args[0]]]))
6962
6963 elif args[0] == 'group_subprocesses':
6964 if args[1] not in ['Auto', 'NLO']:
6965 self.options[args[0]] = eval(args[1])
6966 else:
6967 self.options[args[0]] = args[1]
6968 if log:
6969 logger.info('Set group_subprocesses to %s' % \
6970 str(self.options[args[0]]))
6971 logger.info('Note that you need to regenerate all processes')
6972 self._curr_amps = diagram_generation.AmplitudeList()
6973 self._curr_proc_defs = base_objects.ProcessDefinitionList()
6974 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
6975
6976 elif args[0] == "stdout_level":
6977 if args[1].isdigit():
6978 level = int(args[1])
6979 else:
6980 level = eval('logging.' + args[1])
6981 logging.root.setLevel(level)
6982 logging.getLogger('madgraph').setLevel(level)
6983 logging.getLogger('madevent').setLevel(level)
6984 self.options[args[0]] = level
6985 if log:
6986 logger.info('set output information to level: %s' % level)
6987 elif args[0].lower() == "ewscheme":
6988 logger.info("Change EW scheme to %s for the model %s. Note that YOU are responsible of the full validity of the input in that scheme." %\
6989 (self._curr_model.get('name'), args[1]))
6990 logger.info("Importing a model will restore the default scheme")
6991 self._curr_model.change_electroweak_mode(args[1])
6992 elif args[0] == "complex_mass_scheme":
6993 old = self.options[args[0]]
6994 self.options[args[0]] = eval(args[1])
6995 aloha.complex_mass = eval(args[1])
6996 aloha_lib.KERNEL.clean()
6997 if self.options[args[0]]:
6998 if old:
6999 if log:
7000 logger.info('Complex mass already activated.')
7001 return
7002 if log:
7003 logger.info('Activate complex mass scheme.')
7004 else:
7005 if not old:
7006 if log:
7007 logger.info('Complex mass already desactivated.')
7008 return
7009 if log:
7010 logger.info('Desactivate complex mass scheme.')
7011 if not self._curr_model:
7012 return
7013 self.exec_cmd('import model %s' % self._curr_model.get('name'))
7014
7015 elif args[0] == "gauge":
7016
7017 if not self._curr_model:
7018 if args[1] == 'unitary':
7019 aloha.unitary_gauge = True
7020 else:
7021 aloha.unitary_gauge = False
7022 aloha_lib.KERNEL.clean()
7023 self.options[args[0]] = args[1]
7024 if log: logger.info('Passing to gauge %s.' % args[1])
7025 return
7026
7027
7028 able_to_mod = True
7029 if args[1] == 'unitary':
7030 if 0 in self._curr_model.get('gauge'):
7031 aloha.unitary_gauge = True
7032 else:
7033 able_to_mod = False
7034 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \
7035 % self._curr_model.get('name'))
7036 else:
7037 if 1 in self._curr_model.get('gauge'):
7038 aloha.unitary_gauge = False
7039 else:
7040 able_to_mod = False
7041 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \
7042 % self._curr_model.get('name'))
7043
7044 if self.options['gauge'] == args[1]:
7045 return
7046
7047
7048 self.options[args[0]] = args[1]
7049
7050 if able_to_mod and log and args[0] == 'gauge' and \
7051 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \
7052 isinstance(self._curr_model,loop_base_objects.LoopModel) and \
7053 not self._curr_model['perturbation_couplings'] in [[],['QCD']]:
7054 logger.warning('You will only be able to do tree level'+\
7055 ' and QCD corrections in the unitary gauge.')
7056
7057
7058
7059
7060 model_name = self._curr_model.get('modelpath+restriction')
7061 self._curr_model = None
7062 self._curr_amps = diagram_generation.AmplitudeList()
7063 self._curr_proc_defs = base_objects.ProcessDefinitionList()
7064 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7065 self._curr_helas_model = None
7066 self._curr_exporter = None
7067 self._done_export = False
7068 import_ufo._import_once = []
7069 logger.info('Passing to gauge %s.' % args[1])
7070
7071 if able_to_mod:
7072
7073
7074
7075 MadGraphCmd.do_import(self,'model %s' %model_name, force=True)
7076 elif log:
7077 logger.info('Note that you have to reload the model')
7078
7079 elif args[0] == 'fortran_compiler':
7080 if args[1] != 'None':
7081 if log:
7082 logger.info('set fortran compiler to %s' % args[1])
7083 self.options['fortran_compiler'] = args[1]
7084 else:
7085 self.options['fortran_compiler'] = None
7086 elif args[0] == 'f2py_compiler':
7087 if args[1] != 'None':
7088 if log:
7089 logger.info('set f2py compiler to %s' % args[1])
7090 self.options['f2py_compiler'] = args[1]
7091 else:
7092 self.options['f2py_compiler'] = None
7093
7094 elif args[0] == 'loop_optimized_output':
7095 if log:
7096 logger.info('set loop optimized output to %s' % args[1])
7097 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7098 self.options[args[0]] = args[1]
7099 if not self.options['loop_optimized_output'] and \
7100 self.options['loop_color_flows']:
7101 logger.warning("Turning off option 'loop_color_flows'"+\
7102 " since it is not available for non-optimized loop output.")
7103 self.do_set('loop_color_flows False',log=False)
7104 elif args[0] == 'loop_color_flows':
7105 if log:
7106 logger.info('set loop color flows to %s' % args[1])
7107 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7108 self.options[args[0]] = args[1]
7109 if self.options['loop_color_flows'] and \
7110 not self.options['loop_optimized_output']:
7111 logger.warning("Turning on option 'loop_optimized'"+\
7112 " needed for loop color flow computation.")
7113 self.do_set('loop_optimized_output True',False)
7114
7115 elif args[0] == 'fastjet':
7116 try:
7117 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE,
7118 stderr=subprocess.PIPE)
7119 output, error = p.communicate()
7120 res = 0
7121 except Exception:
7122 res = 1
7123
7124 if res != 0 or error:
7125 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \
7126 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \
7127 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' +
7128 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n')
7129 self.options[args[0]] = None
7130 self.history.pop()
7131 elif int(output.split('.')[0]) < 3:
7132 logger.warning('%s is not ' % args[1] + \
7133 'v3 or greater. Please install FastJet v3+.')
7134 self.options[args[0]] = None
7135 self.history.pop()
7136 else:
7137 logger.info('set fastjet to %s' % args[1])
7138 self.options[args[0]] = args[1]
7139
7140 elif args[0] in ['pjfry','golem','samurai','ninja','collier'] and \
7141 not (args[0] in ['ninja','collier'] and args[1]=='./HEPTools/lib'):
7142 if args[1] in ['None',"''",'""']:
7143 self.options[args[0]] = None
7144 else:
7145 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0]))
7146 if program!=None:
7147 res = 0
7148 logger.info('set %s to %s' % (args[0],args[1]))
7149 self.options[args[0]] = args[1]
7150 else:
7151 res = 1
7152
7153 if res != 0 :
7154 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \
7155 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \
7156 'You will NOT be able to run %s otherwise.\n'%args[0])
7157
7158 elif args[0] == 'lhapdf':
7159 try:
7160 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE,
7161 stderr=subprocess.PIPE)
7162 logger.info('set lhapdf to %s' % args[1])
7163 self.options[args[0]] = args[1]
7164 except Exception:
7165 res = 1
7166 if res != 0:
7167 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \
7168 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \
7169 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \
7170 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \
7171 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n')
7172
7173 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry',
7174 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']:
7175 self.options[args[0]] = int(args[1])
7176
7177 elif args[0] in ['cluster_local_path']:
7178 self.options[args[0]] = args[1].strip()
7179
7180 elif args[0] == 'cluster_status_update':
7181 if '(' in args[1]:
7182 data = ' '.join([a for a in args[1:] if not a.startswith('-')])
7183 data = data.replace('(','').replace(')','').replace(',',' ').split()
7184 first, second = data[:2]
7185 else:
7186 first, second = args[1:3]
7187
7188 self.options[args[0]] = (int(first), int(second))
7189
7190 elif args[0] == 'OLP':
7191
7192
7193 self._curr_amps = diagram_generation.AmplitudeList()
7194 self._curr_proc_defs = base_objects.ProcessDefinitionList()
7195 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7196 self._curr_exporter = None
7197 self.options[args[0]] = args[1]
7198
7199 elif args[0] =='output_dependencies':
7200 self.options[args[0]] = args[1]
7201 elif args[0] =='notification_center':
7202 if args[1] in ['None','True','False']:
7203 self.options[args[0]] = eval(args[1])
7204 self.allow_notification_center = self.options[args[0]]
7205 else:
7206 raise self.InvalidCmd('expected bool for notification_center')
7207 elif args[0] in ['cluster_queue']:
7208 self.options[args[0]] = args[1].strip()
7209 elif args[0] in self.options:
7210 if args[1] in ['None','True','False']:
7211 self.options[args[0]] = eval(args[1])
7212 else:
7213 self.options[args[0]] = args[1]
7214
7215 - def post_set(self, stop, line):
7216 """Check if we need to save this in the option file"""
7217
7218 args = self.split_arg(line)
7219
7220 try:
7221 self.check_set(args, log=False)
7222 except Exception:
7223 return stop
7224
7225 if args[0] in self.options_configuration and '--no_save' not in args:
7226 self.exec_cmd('save options --auto', log=False)
7227 elif args[0] in self.options_madevent:
7228 if not '--no_save' in line:
7229 logger.info('This option will be the default in any output that you are going to create in this session.')
7230 logger.info('In order to keep this changes permanent please run \'save options\'')
7231 else:
7232
7233 if not self.history or self.history[-1].split() != line.split():
7234 self.history.append('set %s' % line)
7235 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set'])
7236 return stop
7237
7247
7249 """Main commands: Initialize a new Template or reinitialize one"""
7250
7251 args = self.split_arg(line)
7252
7253 self.check_output(args)
7254
7255
7256 noclean = '-noclean' in args
7257 force = '-f' in args
7258 nojpeg = '-nojpeg' in args
7259 flaglist = []
7260
7261 if '--postpone_model' in args:
7262 flaglist.append('store_model')
7263
7264 main_file_name = ""
7265 try:
7266 main_file_name = args[args.index('-name') + 1]
7267 except Exception:
7268 pass
7269
7270
7271
7272
7273
7274 if self._export_format == 'aloha':
7275
7276 format = [d[9:] for d in args if d.startswith('--format=')]
7277 if not format:
7278 format = 'Fortran'
7279 else:
7280 format = format[-1]
7281
7282 output = [d for d in args if d.startswith('--output=')]
7283 if not output:
7284 output = import_ufo.find_ufo_path(self._curr_model['name'])
7285 output = pjoin(output, format)
7286 if not os.path.isdir(output):
7287 os.mkdir(output)
7288 else:
7289 output = output[-1]
7290 if not os.path.isdir(output):
7291 raise self.InvalidCmd('%s is not a valid directory' % output)
7292 logger.info('creating routines in directory %s ' % output)
7293
7294 names = [d for d in args if not d.startswith('-')]
7295 wanted_lorentz = aloha_fct.guess_routine_from_name(names)
7296
7297 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name'))
7298 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz'))
7299 if wanted_lorentz:
7300 aloha_model.compute_subset(wanted_lorentz)
7301 else:
7302 aloha_model.compute_all(save=False)
7303 aloha_model.write(output, format)
7304 return
7305
7306
7307
7308
7309
7310
7311
7312
7313 config = {}
7314 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
7315 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'}
7316 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
7317 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'}
7318 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'}
7319 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'}
7320 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'}
7321 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'}
7322 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'}
7323 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'}
7324 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
7325
7326 if self._export_format == 'plugin':
7327 options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output}
7328 else:
7329 options = config[self._export_format]
7330
7331
7332 if os.path.realpath(self._export_dir) == os.getcwd():
7333 if len(args) == 0:
7334 i=0
7335 while 1:
7336 if os.path.exists('Pythia8_proc_%i' %i):
7337 i+=1
7338 else:
7339 break
7340 os.mkdir('Pythia8_proc_%i' %i)
7341 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i)
7342 logger.info('Create output in %s' % self._export_dir)
7343 elif not args[0] in ['.', '-f']:
7344 raise self.InvalidCmd, 'Wrong path directory to create in local directory use \'.\''
7345 elif not noclean and os.path.isdir(self._export_dir) and options['check']:
7346 if not force:
7347
7348 logger.info('INFO: directory %s already exists.' % self._export_dir)
7349 logger.info('If you continue this directory will be deleted and replaced.')
7350 answer = self.ask('Do you want to continue?', 'y', ['y','n'])
7351 else:
7352 answer = 'y'
7353 if answer != 'y':
7354 raise self.InvalidCmd('Stopped by user request')
7355 else:
7356 shutil.rmtree(self._export_dir)
7357
7358
7359
7360 if self.options['group_subprocesses'] in [True, False]:
7361 group_processes = self.options['group_subprocesses']
7362 elif self.options['group_subprocesses'] == 'Auto':
7363
7364 group_processes = True
7365
7366
7367
7368
7369 if self._curr_amps[0].get_ninitial() == 1 and \
7370 len(self._curr_amps)>1:
7371 processes = [amp.get('process') for amp in self._curr_amps]
7372 if len(set(proc.get('id') for proc in processes))!=len(processes):
7373
7374 if any(proc['perturbation_couplings'] != [] for proc in
7375 processes) and self._export_format == 'madevent':
7376 logger.warning("""
7377 || The loop-induced decay process you have specified contains several
7378 || subprocesses and, in order to be able to compute individual branching ratios,
7379 || MG5_aMC will *not* group them. Integration channels will also be considered
7380 || for each diagrams and as a result integration will be inefficient.
7381 || It is therefore recommended to perform this simulation by setting the MG5_aMC
7382 || option 'group_subprocesses' to 'True' (before the output of the process).
7383 || Notice that when doing so, processes for which one still wishes to compute
7384 || branching ratios independently can be specified using the syntax:
7385 || -> add process <proc_def>
7386 """)
7387 group_processes = False
7388
7389
7390 if options['exporter'] == 'v4':
7391 self._curr_exporter = export_v4.ExportV4Factory(self, noclean,
7392 group_subprocesses=group_processes)
7393 elif options['exporter'] == 'cpp':
7394 self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes)
7395
7396 self._curr_exporter.pass_information_from_cmd(self)
7397
7398 if options['output'] == 'Template':
7399 self._curr_exporter.copy_template(self._curr_model)
7400 elif options['output'] == 'dir' and not os.path.isdir(self._export_dir):
7401 os.makedirs(self._export_dir)
7402
7403
7404 self._done_export = False
7405
7406 if self._export_format == "madevent":
7407
7408
7409 if self.options['max_npoint_for_channel']:
7410 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel']
7411 else:
7412 base_objects.Vertex.max_n_loop_for_multichanneling = 3
7413
7414
7415 self.export(nojpeg, main_file_name, group_processes, args)
7416
7417
7418 self.finalize(nojpeg, flaglist=flaglist)
7419
7420
7421 self._done_export = (self._export_dir, self._export_format)
7422
7423
7424 self._export_dir = None
7425
7426
7427 - def export(self, nojpeg = False, main_file_name = "", group_processes=True,
7428 args=[]):
7429 """Export a generated amplitude to file."""
7430
7431
7432 if self._curr_exporter.exporter == 'cpp':
7433 self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model)
7434 elif self._model_v4_path:
7435 assert self._curr_exporter.exporter == 'v4'
7436 self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model)
7437 else:
7438 assert self._curr_exporter.exporter == 'v4'
7439 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
7440
7441 version = [arg[10:] for arg in args if arg.startswith('--version=')]
7442 if version:
7443 version = version[-1]
7444 else:
7445 version = '8.2'
7446
7447 def generate_matrix_elements(self, group_processes=True):
7448 """Helper function to generate the matrix elements before
7449 exporting. Uses the main function argument 'group_processes' to decide
7450 whether to use group_subprocess or not. (it has been set in do_output to
7451 the appropriate value if the MG5 option 'group_subprocesses' was set
7452 to 'Auto'."""
7453
7454 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']:
7455 to_distinguish = []
7456 for part in self._curr_model.get('particles'):
7457 if part.get('name') in args and part.get('antiname') in args and\
7458 part.get('name') != part.get('antiname'):
7459 to_distinguish.append(abs(part.get('pdg_code')))
7460
7461
7462 self._curr_amps.sort(lambda a1, a2: a2.get_number_of_diagrams() - \
7463 a1.get_number_of_diagrams())
7464
7465 cpu_time1 = time.time()
7466 ndiags = 0
7467 if not self._curr_matrix_elements.get_matrix_elements():
7468 if group_processes:
7469 cpu_time1 = time.time()
7470 dc_amps = diagram_generation.DecayChainAmplitudeList(\
7471 [amp for amp in self._curr_amps if isinstance(amp, \
7472 diagram_generation.DecayChainAmplitude)])
7473 non_dc_amps = diagram_generation.AmplitudeList(\
7474 [amp for amp in self._curr_amps if not \
7475 isinstance(amp, \
7476 diagram_generation.DecayChainAmplitude)])
7477 subproc_groups = group_subprocs.SubProcessGroupList()
7478 matrix_elements_opts = {'optimized_output':
7479 self.options['loop_optimized_output']}
7480
7481 grouping_criteria = self._curr_exporter.grouped_mode
7482 if non_dc_amps:
7483 subproc_groups.extend(\
7484 group_subprocs.SubProcessGroup.group_amplitudes(\
7485 non_dc_amps,grouping_criteria,
7486 matrix_elements_opts=matrix_elements_opts))
7487
7488 if dc_amps:
7489 dc_subproc_group = \
7490 group_subprocs.DecayChainSubProcessGroup.\
7491 group_amplitudes(dc_amps, grouping_criteria,
7492 matrix_elements_opts=matrix_elements_opts)
7493 subproc_groups.extend(dc_subproc_group.\
7494 generate_helas_decay_chain_subproc_groups())
7495
7496 ndiags = sum([len(m.get('diagrams')) for m in \
7497 subproc_groups.get_matrix_elements()])
7498 self._curr_matrix_elements = subproc_groups
7499
7500 uid = 0
7501 for group in subproc_groups:
7502 uid += 1
7503 for me in group.get('matrix_elements'):
7504 me.get('processes')[0].set('uid', uid)
7505 else:
7506 mode = {}
7507 if self._export_format in [ 'standalone_msP' ,
7508 'standalone_msF', 'standalone_rw']:
7509 mode['mode'] = 'MadSpin'
7510
7511
7512 if isinstance(self._curr_amps[0],
7513 loop_diagram_generation.LoopAmplitude):
7514 mode['optimized_output']=self.options['loop_optimized_output']
7515 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess
7516 compute_loop_nc = True
7517 else:
7518 HelasMultiProcessClass = helas_objects.HelasMultiProcess
7519 compute_loop_nc = False
7520
7521 self._curr_matrix_elements = HelasMultiProcessClass(
7522 self._curr_amps, compute_loop_nc=compute_loop_nc,
7523 matrix_element_opts=mode)
7524
7525 ndiags = sum([len(me.get('diagrams')) for \
7526 me in self._curr_matrix_elements.\
7527 get_matrix_elements()])
7528
7529 uid = 0
7530 for me in self._curr_matrix_elements.get_matrix_elements()[:]:
7531 uid += 1
7532 me.get('processes')[0].set('uid', uid)
7533
7534 cpu_time2 = time.time()
7535
7536
7537 return ndiags, cpu_time2 - cpu_time1
7538
7539
7540
7541 ndiags, cpu_time = generate_matrix_elements(self,group_processes)
7542
7543 calls = 0
7544
7545 path = self._export_dir
7546
7547 cpu_time1 = time.time()
7548
7549
7550
7551
7552
7553 if self._export_format == 'madevent':
7554 path = pjoin(path, 'SubProcesses')
7555 calls += self._curr_exporter.export_processes(self._curr_matrix_elements,
7556 self._curr_helas_model)
7557
7558
7559 card_path = pjoin(path, os.path.pardir, 'SubProcesses', \
7560 'procdef_mg5.dat')
7561 if self._generate_info:
7562 self._curr_exporter.write_procdef_mg5(card_path,
7563 self._curr_model['name'],
7564 self._generate_info)
7565 try:
7566 cmd.Cmd.onecmd(self, 'history .')
7567 except Exception:
7568 misc.sprint('command history fails.', 10)
7569 pass
7570
7571
7572 elif self._export_format == 'pythia8':
7573
7574 process_names = []
7575 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList):
7576 for (group_number, me_group) in enumerate(self._curr_matrix_elements):
7577 exporter = self._curr_exporter.generate_process_directory(\
7578 me_group.get('matrix_elements'), self._curr_helas_model,
7579 process_string = me_group.get('name'),
7580 process_number = group_number,
7581 version = version)
7582 process_names.append(exporter.process_name)
7583 else:
7584 exporter = self._curr_exporter.generate_process_directory(\
7585 self._curr_matrix_elements, self._curr_helas_model,
7586 process_string = self._generate_info, version = version)
7587 process_names.append(exporter.process_file_name)
7588
7589
7590 model_name, model_path = exporter.convert_model_to_pythia8(\
7591 self._curr_model, self._export_dir)
7592
7593
7594 filename, make_filename = \
7595 self._curr_exporter.generate_example_file_pythia8(path,
7596 model_path,
7597 process_names,
7598 exporter,
7599 main_file_name)
7600
7601
7602 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
7603
7604 if self._export_format == 'matrix':
7605 for me in matrix_elements:
7606 filename = pjoin(path, 'matrix_' + \
7607 me.get('processes')[0].shell_string() + ".f")
7608 if os.path.isfile(filename):
7609 logger.warning("Overwriting existing file %s" % filename)
7610 else:
7611 logger.info("Creating new file %s" % filename)
7612 calls = calls + self._curr_exporter.write_matrix_element_v4(\
7613 writers.FortranWriter(filename),\
7614 me, self._curr_helas_model)
7615 elif self._export_format in ['madevent', 'pythia8']:
7616 pass
7617
7618 elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\
7619 self._curr_exporter.grouped_mode:
7620 modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements)
7621 if modify:
7622 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
7623
7624 for me_number, me in enumerate(self._curr_matrix_elements):
7625 calls = calls + \
7626 self._curr_exporter.generate_subprocess_directory(\
7627 me, self._curr_helas_model, me_number)
7628
7629
7630 else:
7631 for nb,me in enumerate(matrix_elements[:]):
7632 new_calls = self._curr_exporter.generate_subprocess_directory(\
7633 me, self._curr_helas_model, nb)
7634 if isinstance(new_calls, int):
7635 if new_calls ==0:
7636 matrix_elements.remove(me)
7637 else:
7638 calls = calls + new_calls
7639
7640 cpu_time2 = time.time() - cpu_time1
7641
7642 logger.info(("Generated helas calls for %d subprocesses " + \
7643 "(%d diagrams) in %0.3f s") % \
7644 (len(matrix_elements),
7645 ndiags, cpu_time))
7646
7647 if calls:
7648 if "cpu_time2" in locals():
7649 logger.info("Wrote files for %d helas calls in %0.3f s" % \
7650 (calls, cpu_time2))
7651 else:
7652 logger.info("Wrote files for %d helas calls" % \
7653 (calls))
7654
7655 if self._export_format == 'pythia8':
7656 logger.info("- All necessary files for Pythia 8 generated.")
7657 logger.info("- Run \"launch\" and select %s.cc," % filename)
7658 logger.info(" or go to %s/examples and run" % path)
7659 logger.info(" make -f %s" % make_filename)
7660 logger.info(" (with process_name replaced by process name).")
7661 logger.info(" You can then run ./%s to produce events for the process" % \
7662 filename)
7663
7664
7665
7666
7667 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
7668 self._curr_amps = diagram_generation.AmplitudeList(\
7669 [me.get('base_amplitude') for me in \
7670 matrix_elements])
7671
7672 - def finalize(self, nojpeg, online = False, flaglist=[]):
7673 """Make the html output, write proc_card_mg5.dat and create
7674 madevent.tar.gz for a MadEvent directory"""
7675
7676 compiler_dict = {'fortran': self.options['fortran_compiler'],
7677 'cpp': self.options['cpp_compiler'],
7678 'f2py': self.options['f2py_compiler']}
7679
7680
7681 if self._model_v4_path:
7682 logger.info('Copy %s model files to directory %s' % \
7683 (os.path.basename(self._model_v4_path), self._export_dir))
7684 self._curr_exporter.export_model_files(self._model_v4_path)
7685 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS'))
7686 else:
7687
7688
7689
7690 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz()
7691 wanted_couplings = self._curr_matrix_elements.get_used_couplings()
7692
7693
7694 if hasattr(self, 'previous_lorentz'):
7695 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz))
7696 wanted_couplings = list(set(self.previous_couplings + wanted_couplings))
7697 del self.previous_lorentz
7698 del self.previous_couplings
7699 if 'store_model' in flaglist:
7700 self.previous_lorentz = wanted_lorentz
7701 self.previous_couplings = wanted_couplings
7702 else:
7703 self._curr_exporter.convert_model(self._curr_model,
7704 wanted_lorentz,
7705 wanted_couplings)
7706
7707
7708 if nojpeg:
7709 flaglist.append('nojpeg')
7710 if online:
7711 flaglist.append('online')
7712
7713
7714
7715 if self._export_format in ['NLO']:
7716
7717
7718 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt')
7719 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path',
7720 'hepmc_path']
7721 to_keep = {}
7722 for opt in opts_to_keep:
7723 if self.options[opt]:
7724 to_keep[opt] = self.options[opt]
7725 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \
7726 to_keep = to_keep)
7727
7728 elif self._export_format in ['madevent', 'madweight']:
7729
7730 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt')
7731 self.do_save('options %s' % filename.replace(' ', '\ '), check=False,
7732 to_keep={'mg5_path':MG5DIR})
7733
7734
7735 self._curr_exporter.finalize(self._curr_matrix_elements,
7736 self.history,
7737 self.options,
7738 flaglist)
7739
7740 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']:
7741 logger.info('Output to directory ' + self._export_dir + ' done.')
7742
7743 if self._export_format in ['madevent', 'NLO']:
7744 logger.info('Type \"launch\" to generate events from this process, or see')
7745 logger.info(self._export_dir + '/README')
7746 logger.info('Run \"open index.html\" to see more information about this process.')
7747
7749 """ propose some usefull possible action """
7750
7751 super(MadGraphCmd,self).do_help(line)
7752
7753 if line:
7754 return
7755
7756 if len(self.history) == 0:
7757 last_action_2 = 'mg5_start'
7758 last_action = 'mg5_start'
7759 else:
7760 args = self.history[-1].split()
7761 last_action = args[0]
7762 if len(args)>1:
7763 last_action_2 = '%s %s' % (last_action, args[1])
7764 else:
7765 last_action_2 = 'none'
7766
7767
7768
7769
7771 """Documented commands:Generate amplitudes for decay width calculation, with fixed
7772 number of final particles (called level)
7773 syntax; compute_widths particle [other particles] [--options=]
7774
7775 - particle/other particles can also be multiparticle name (can also be
7776 pid of the particle)
7777
7778 --body_decay=X [default=4.0025] allow to choose the precision.
7779 if X is an integer: compute all X body decay
7780 if X is a float <1: compute up to the time that total error < X
7781 if X is a float >1: stops at the first condition.
7782
7783 --path=X. Use a given file for the param_card. (default UFO built-in)
7784
7785 special argument:
7786 - skip_2body: allow to not consider those decay (use FR)
7787 - model: use the model pass in argument.
7788
7789 """
7790
7791
7792
7793 self.change_principal_cmd('MadGraph')
7794 if '--nlo' not in line:
7795 warning_text = """Please note that the automatic computation of the width is
7796 only valid in narrow-width approximation and at tree-level."""
7797 logger.warning(warning_text)
7798
7799 if not model:
7800 modelname = self._curr_model.get('modelpath+restriction')
7801 with misc.MuteLogger(['madgraph'], ['INFO']):
7802 model = import_ufo.import_model(modelname, decay=True)
7803 self._curr_model = model
7804
7805 if not isinstance(model, model_reader.ModelReader):
7806 model = model_reader.ModelReader(model)
7807
7808 if '--nlo' in line:
7809
7810 self.compute_widths_SMWidth(line, model=model)
7811 return
7812
7813
7814 particles, opts = self.check_compute_widths(self.split_arg(line))
7815
7816 if opts['path']:
7817 correct = True
7818 param_card = check_param_card.ParamCard(opts['path'])
7819 for param in param_card['decay']:
7820 if param.value == "auto":
7821 param.value = 1
7822 param.format = 'float'
7823 correct = False
7824 if not correct:
7825 if opts['output']:
7826 param_card.write(opts['output'])
7827 opts['path'] = opts['output']
7828 else:
7829 param_card.write(opts['path'])
7830
7831 data = model.set_parameters_and_couplings(opts['path'])
7832
7833
7834 if do2body:
7835 skip_2body = True
7836 decay_info = {}
7837 for pid in particles:
7838 particle = model.get_particle(pid)
7839 if not hasattr(particle, 'partial_widths'):
7840 skip_2body = False
7841 break
7842 elif not decay_info:
7843 logger_mg.info('Get two body decay from FeynRules formula')
7844 decay_info[pid] = []
7845 mass = abs(eval(str(particle.get('mass')), data).real)
7846 data = model.set_parameters_and_couplings(opts['path'], scale= mass)
7847 total = 0
7848
7849 for mode, expr in particle.partial_widths.items():
7850 tmp_mass = mass
7851 for p in mode:
7852 try:
7853 value_mass = eval(str(p.mass), data)
7854 except Exception:
7855
7856
7857 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data)
7858 tmp_mass -= abs(value_mass)
7859 if tmp_mass <=0:
7860 continue
7861
7862 decay_to = [p.get('pdg_code') for p in mode]
7863 value = eval(expr,{'cmath':cmath},data).real
7864 if -1e-10 < value < 0:
7865 value = 0
7866 if -1e-5 < value < 0:
7867 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' %
7868 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value))
7869 value = 0
7870 elif value < 0:
7871 raise Exception, 'Partial width for %s > %s negative: %s' % \
7872 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)
7873 elif 0 < value < 0.1 and particle['color'] !=1:
7874 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \
7875 % (particle.get('name'), value, decay_to))
7876 value = 0
7877
7878 decay_info[particle.get('pdg_code')].append([decay_to, value])
7879 total += value
7880 else:
7881 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info,
7882 opts['path'], opts['output'])
7883 if float(opts['body_decay']) == 2:
7884 return
7885 else:
7886 skip_2body = True
7887
7888
7889
7890
7891 self.do_decay_diagram('%s %s' % (' '.join([`id` for id in particles]),
7892 ' '.join('--%s=%s' % (key,value)
7893 for key,value in opts.items()
7894 if key not in ['precision_channel'])
7895 ), skip_2body=skip_2body, model=decaymodel)
7896
7897 if self._curr_amps:
7898 logger.info('Pass to numerical integration for computing the widths:')
7899 else:
7900 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output'])
7901
7902
7903
7904 return
7905
7906
7907 with misc.TMP_directory(dir=os.getcwd()) as path:
7908 decay_dir = pjoin(path,'temp_decay')
7909 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir))
7910 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]):
7911 self.exec_cmd('output %s -f' % decay_dir,child=False)
7912
7913 if os.path.exists(opts['output']):
7914 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat'))
7915 else:
7916 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat'))
7917 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'):
7918 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat'))
7919
7920 me_cmd = madevent_interface.MadEventCmd(decay_dir)
7921
7922 me_cmd.model_name = self._curr_model['name']
7923 me_cmd.options['automatic_html_opening'] = False
7924
7925 me_opts=[('accuracy', opts['precision_channel']),
7926 ('points', 1000),
7927 ('iterations',9)]
7928 me_cmd.exec_cmd('survey decay -f %s' % (
7929 " ".join(['--%s=%s' % val for val in me_opts])),
7930 postcmd=False)
7931 me_cmd.exec_cmd('combine_events', postcmd=False)
7932
7933 me_cmd.collect_decay_widths()
7934 me_cmd.do_quit('')
7935
7936 del me_cmd
7937
7938 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat'))
7939
7940 for pid in particles:
7941 width = param['decay'].get((pid,)).value
7942 particle = self._curr_model.get_particle(pid)
7943
7944
7945
7946
7947
7948
7949 if not pid in param['decay'].decay_table:
7950 continue
7951 if pid not in decay_info:
7952 decay_info[pid] = []
7953 for BR in param['decay'].decay_table[pid]:
7954 if len(BR.lhacode) == 3 and skip_2body:
7955 continue
7956 if 0 < BR.value * width <0.1 and particle['color'] !=1:
7957 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \
7958 % (particle.get('name'), BR.value * width, BR.lhacode[1:]))
7959
7960 continue
7961
7962 decay_info[pid].append([BR.lhacode[1:], BR.value * width])
7963
7964 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info,
7965 opts['path'], opts['output'])
7966
7967 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'):
7968 check_param_card.convert_to_slha1(opts['output'])
7969 return
7970
7971
7972
7973
7975 """Compute widths with SMWidth.
7976 """
7977
7978
7979 particles, opts = self.check_compute_widths(self.split_arg(line))
7980
7981 if opts['path']:
7982 correct = True
7983 param_card = check_param_card.ParamCard(opts['path'])
7984 for param in param_card['decay']:
7985 if param.value == "auto":
7986 param.value = 1
7987 param.format = 'float'
7988 correct = False
7989 if not correct:
7990 if opts['output']:
7991 param_card.write(opts['output'])
7992 opts['path'] = opts['output']
7993 else:
7994 param_card.write(opts['path'])
7995
7996 if not model:
7997 model_path = self._curr_model.get('modelpath')
7998 model_name = self._curr_model.get('name')
7999 currmodel = self._curr_model
8000 else:
8001 model_path = model.get('modelpath')
8002 model_name = model.get('name')
8003 currmodel = model
8004
8005 if not os.path.exists(pjoin(model_path, 'SMWidth')):
8006 raise self.InvalidCmd, "Model %s is not valid for computing NLO width with SMWidth"%model_name
8007
8008
8009 externparam = [(param.lhablock.lower(),param.name.lower()) for param \
8010 in currmodel.get('parameters')[('external',)]]
8011
8012 if ('sminputs','aewm1') in externparam:
8013
8014 arg2 = "1"
8015 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam:
8016
8017 arg2 = "2"
8018 else:
8019 raise Exception, "Do not know the EW scheme in the model %s"%model_name
8020
8021
8022 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')):
8023 logger.info('Compiling SMWidth. This has to be done only once and'+\
8024 ' can take a couple of minutes.','$MG:color:BLACK')
8025 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth',
8026 'makefile_MW5'))
8027 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \
8028 self.options_configuration['fortran_compiler']
8029 if current != new:
8030 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current)
8031 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current)
8032 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current)
8033 misc.compile(cwd=pjoin(model_path, 'SMWidth'))
8034
8035
8036 identpath=" "
8037 carddir=os.path.dirname(opts['path'])
8038 if 'ident_card.dat' in os.listdir(carddir):
8039 identpath=pjoin(carddir,'ident_card.dat')
8040
8041 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2],
8042 stdout=subprocess.PIPE,
8043 stdin=subprocess.PIPE,
8044 cwd=pjoin(model_path, 'SMWidth')).communicate()
8045 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I)
8046 width_list = pattern.findall(output)
8047 width_dict = {}
8048 for pid,width in width_list:
8049 width_dict[int(pid)] = float(width)
8050
8051 for pid in particles:
8052 if not pid in width_dict:
8053 width = 0
8054 else:
8055 width = width_dict[pid]
8056 param = param_card['decay'].get((pid,))
8057 param.value = width
8058 param.format = 'float'
8059 if pid not in param_card['decay'].decay_table:
8060 continue
8061 del param_card['decay'].decay_table[pid]
8062
8063 if opts['output']:
8064 param_card.write(opts['output'])
8065 logger.info('Results are written in %s' % opts['output'])
8066 else:
8067 param_card.write(opts['path'])
8068 logger.info('Results are written in %s' % opts['path'])
8069 return
8070
8071
8073 """Not in help: Generate amplitudes for decay width calculation, with fixed
8074 number of final particles (called level)
8075 syntax; decay_diagram part_name level param_path
8076 args; part_name level param_path
8077 part_name = name of the particle you want to calculate width
8078 level = a.) when level is int,
8079 it means the max number of decay products
8080 b.) when level is float,
8081 it means the required precision for width.
8082 param_path = path for param_card
8083 (this is necessary to determine whether a channel is onshell or not)
8084 e.g. calculate width for higgs up to 2-body decays.
8085 calculate_width h 2 [path]
8086 N.B. param_card must be given so that the program knows which channel
8087 is on shell and which is not.
8088
8089 special argument:
8090 - skip_2body: allow to not consider those decay (use FR)
8091 - model: use the model pass in argument.
8092 """
8093
8094 if model:
8095 self._curr_decaymodel = model
8096
8097
8098 args = self.split_arg(line)
8099
8100 particles, args = self.check_decay_diagram(args)
8101
8102 pids = particles
8103 level = float(args['body_decay'])
8104 param_card_path = args['path']
8105 min_br = float(args['min_br'])
8106
8107
8108 self._curr_amps = diagram_generation.AmplitudeList()
8109 self._curr_proc_defs = base_objects.ProcessDefinitionList()
8110
8111 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
8112
8113 self._done_export = False
8114
8115 self._export_format = None
8116
8117
8118
8119 if not model:
8120 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model,
8121 True)
8122 self._curr_decaymodel.read_param_card(param_card_path)
8123 else:
8124 self._curr_decaymodel = model
8125 model = self._curr_decaymodel
8126
8127 if isinstance(pids, int):
8128 pids = [pids]
8129
8130 first =True
8131 for part_nb,pid in enumerate(pids):
8132 part = self._curr_decaymodel.get_particle(pid)
8133 if part.get('width').lower() == 'zero':
8134 continue
8135 logger_mg.info('get decay diagram for %s' % part['name'])
8136
8137 if level // 1 == level and level >1:
8138 level = int(level)
8139 self._curr_decaymodel.find_channels(part, level, min_br)
8140 if not skip_2body:
8141 amp = part.get_amplitudes(2)
8142 if amp:
8143 self._curr_amps.extend(amp)
8144
8145 for l in range(3, level+1):
8146 amp = part.get_amplitudes(l)
8147 if amp:
8148 self._curr_amps.extend(amp)
8149 else:
8150 max_level = level // 1
8151 if max_level < 2:
8152 max_level = 999
8153 precision = level % 1
8154 if first:
8155 model.find_all_channels(2,generate_abstract=False)
8156 first = False
8157 if not skip_2body:
8158 amp = part.get_amplitudes(2)
8159 if amp:
8160 self._curr_amps.extend(amp)
8161 clevel = 2
8162 while part.get('apx_decaywidth_err').real > precision:
8163 clevel += 1
8164 if clevel > max_level:
8165 logger_mg.info(' stop to %s body-decay. approximate error: %s' %
8166 (max_level, part.get('apx_decaywidth_err')) )
8167 break
8168 if clevel > 3:
8169 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\
8170 (part.get('apx_decaywidth_err'), clevel))
8171 part.find_channels_nextlevel(model, min_br)
8172
8173 amp = part.get_amplitudes(clevel)
8174 if amp:
8175 self._curr_amps.extend(amp)
8176 part.update_decay_attributes(False, True, True, model)
8177
8178
8179
8180 if len(self._curr_amps) > 0:
8181 process = self._curr_amps[0]['process'].nice_string()
8182
8183 self._generate_info = process[9:]
8184
8185 else:
8186 logger.info("No decay is found")
8187
8189 """Temporary parser"""
8190
8191
8192
8193
8194
8195 _draw_usage = "draw FILEPATH [options]\n" + \
8196 "-- draw the diagrams in eps format\n" + \
8197 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \
8198 " Example: draw plot_dir . \n"
8199 _draw_parser = misc.OptionParser(usage=_draw_usage)
8200 _draw_parser.add_option("", "--horizontal", default=False,
8201 action='store_true', help="force S-channel to be horizontal")
8202 _draw_parser.add_option("", "--external", default=0, type='float',
8203 help="authorizes external particles to end at top or " + \
8204 "bottom of diagram. If bigger than zero this tune the " + \
8205 "length of those line.")
8206 _draw_parser.add_option("", "--max_size", default=1.5, type='float',
8207 help="this forbids external line bigger than max_size")
8208 _draw_parser.add_option("", "--non_propagating", default=True, \
8209 dest="contract_non_propagating", action='store_false',
8210 help="avoid contractions of non propagating lines")
8211 _draw_parser.add_option("", "--add_gap", default=0, type='float', \
8212 help="set the x-distance between external particles")
8213
8214
8215 _launch_usage = "launch [DIRPATH] [options]\n" + \
8216 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \
8217 " By default DIRPATH is the latest created directory \n" + \
8218 " (for pythia8, it should be the Pythia 8 main directory) \n" + \
8219 " Example: launch PROC_sm_1 --name=run2 \n" + \
8220 " Example: launch ../pythia8 \n"
8221 _launch_parser = misc.OptionParser(usage=_launch_usage)
8222 _launch_parser.add_option("-f", "--force", default=False, action='store_true',
8223 help="Use the card present in the directory in order to launch the different program")
8224 _launch_parser.add_option("-n", "--name", default='', type='str',
8225 help="Provide a name to the run (for madevent run)")
8226 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true',
8227 help="submit the job on the cluster")
8228 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true',
8229 help="submit the job on multicore core")
8230
8231 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true',
8232 help="Use Interactive Console [if available]")
8233 _launch_parser.add_option("-s", "--laststep", default='',
8234 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]")
8235 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true',
8236 help="Run the reweight module (reweighting by different model parameter")
8237 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true',
8238 help="Run the madspin package")
8244 """A class for asking a question where in addition you can have the
8245 set command define and modifying the param_card/run_card correctly"""
8246
8247 - def __init__(self, question, allow_arg=[], default=None,
8248 mother_interface=None, *arg, **opt):
8249
8250 model_path = mother_interface._curr_model.get('modelpath')
8251
8252 ufo_model = ufomodels.load_model(model_path)
8253 self.all_categories = ufo_model.build_restrict.all_categories
8254
8255 question = self.get_question()
8256
8257
8258 allow_arg = ['0']
8259 self.name2options = {}
8260 for category in self.all_categories:
8261 for options in category:
8262 if not options.first:
8263 continue
8264 self.name2options[str(len(allow_arg))] = options
8265 self.name2options[options.name.replace(' ','')] = options
8266 allow_arg.append(len(allow_arg))
8267 allow_arg.append('done')
8268
8269 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8270
8271
8272
8274 """Default action if line is not recognized"""
8275
8276 line = line.strip()
8277 args = line.split()
8278 if line == '' and self.default_value is not None:
8279 self.value = self.default_value
8280
8281 elif hasattr(self, 'do_%s' % args[0]):
8282 self.do_set(' '.join(args[1:]))
8283 elif line.strip() != '0' and line.strip() != 'done' and \
8284 str(line) != 'EOF' and line.strip() in self.allow_arg:
8285 option = self.name2options[line.strip()]
8286 option.status = not option.status
8287 self.value = 'repeat'
8288 else:
8289 self.value = line
8290
8291 return self.all_categories
8292
8293 - def reask(self, reprint_opt=True):
8298
8300 """ """
8301 self.value = 'repeat'
8302
8303 args = line.split()
8304 if args[0] not in self.name2options:
8305 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' %
8306 (args[0], ', '.join(self.name2options.keys()) ))
8307 return
8308 elif len(args) != 2:
8309 logger.warning('Invalid set command. Not correct number of argument')
8310 return
8311
8312
8313 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']:
8314 self.name2options[args[0]].status = True
8315 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']:
8316 self.name2options[args[0]].status = False
8317 else:
8318 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8319
8320
8321
8323 """define the current question."""
8324 question = ''
8325 i=0
8326 for category in self.all_categories:
8327 question += category.name + ':\n'
8328 for options in category:
8329 if not options.first:
8330 continue
8331 i+=1
8332 question += ' %s: %s [%s]\n' % (i, options.name,
8333 options.display(options.status))
8334 question += 'Enter a number to change it\'s status or press enter to validate.\n'
8335 question += 'For scripting this function, please type: \'help\''
8336 return question
8337
8338
8340 """ Complete the set command"""
8341 signal.alarm(0)
8342 args = self.split_arg(line[0:begidx])
8343
8344 if len(args) == 1:
8345 possibilities = [x for x in self.name2options if not x.isdigit()]
8346 return self.list_completion(text, possibilities, line)
8347 else:
8348 return self.list_completion(text,['True', 'False'], line)
8349
8350
8352 '''help message'''
8353
8354 print 'This allows you to optimize your model to your needs.'
8355 print 'Enter the number associate to the possible restriction/add-on'
8356 print ' to change the status of this restriction/add-on.'
8357 print ''
8358 print 'In order to allow scripting of this function you can use the '
8359 print 'function \'set\'. This function takes two argument:'
8360 print 'set NAME VALUE'
8361 print ' NAME is the description of the option where you remove all spaces'
8362 print ' VALUE is either True or False'
8363 print ' Example: For the question'
8364 print ''' sm customization:
8365 1: diagonal ckm [True]
8366 2: c mass = 0 [True]
8367 3: b mass = 0 [False]
8368 4: tau mass = 0 [False]
8369 5: muon mass = 0 [True]
8370 6: electron mass = 0 [True]
8371 Enter a number to change it's status or press enter to validate.'''
8372 print ''' you can answer by'''
8373 print ' set diagonalckm False'
8374 print ' set taumass=0 True'
8375
8379
8380
8381
8382
8383
8384
8385
8386 if __name__ == '__main__':
8387
8388 run_option = sys.argv
8389 if len(run_option) > 1:
8390
8391 input_file = open(run_option[1], 'rU')
8392 cmd_line = MadGraphCmd(stdin=input_file)
8393 cmd_line.use_rawinput = False
8394 cmd_line.cmdloop()
8395 else:
8396
8397 MadGraphCmd().cmdloop()
8398