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