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):
3520 if ('external',) == x:
3521 return -1
3522 else:
3523 return len(x)
3524 keys.sort(key=key_sort)
3525 for key in keys:
3526 item = self._curr_model['parameters'][key]
3527 text += '\nparameter type: %s\n' % str(key)
3528 for value in item:
3529 if hasattr(value, 'expr'):
3530 if value.value is not None:
3531 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value)
3532 else:
3533 text+= ' %s = %s\n' % (value.name, value.expr)
3534 else:
3535 if value.value is not None:
3536 text+= ' %s = %s\n' % (value.name, value.value)
3537 else:
3538 text+= ' %s \n' % (value.name)
3539 pydoc.pager(text)
3540
3541 elif args[0] == 'processes':
3542 for amp in self._curr_amps:
3543 print(amp.nice_string_processes())
3544
3545 elif args[0] == 'diagrams_text':
3546 text = "\n".join([amp.nice_string() for amp in self._curr_amps])
3547 pydoc.pager(text)
3548
3549 elif args[0] == 'multiparticles':
3550 print('Multiparticle labels:')
3551 for key in self._multiparticles:
3552 print(self.multiparticle_string(key))
3553
3554 elif args[0] == 'coupling_order':
3555 hierarchy = list(self._curr_model['order_hierarchy'].items())
3556
3557 def order(first, second):
3558 if first[1] < second[1]:
3559 return -1
3560 else:
3561 return 1
3562 hierarchy.sort(order)
3563 for order in hierarchy:
3564 print(' %s : weight = %s' % order)
3565
3566 elif args[0] == 'couplings' and len(args) == 1:
3567 if self._model_v4_path:
3568 print('No couplings information available in V4 model')
3569 return
3570 text = ''
3571 text = "Current model contains %i couplings\n" % \
3572 sum([len(part) for part in
3573 self._curr_model['couplings'].values()])
3574 keys = list(self._curr_model['couplings'].keys())
3575 def key_sort(x, y):
3576 if ('external',) == x:
3577 return -1
3578 elif ('external',) == y:
3579 return +1
3580 elif len(x) < len(y):
3581 return -1
3582 else:
3583 return 1
3584 keys.sort(key_sort)
3585 for key in keys:
3586 item = self._curr_model['couplings'][key]
3587 text += '\ncouplings type: %s\n' % str(key)
3588 for value in item:
3589 if value.value is not None:
3590 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value)
3591 else:
3592 text+= ' %s = %s\n' % (value.name, value.expr)
3593
3594 pydoc.pager(text)
3595
3596 elif args[0] == 'couplings':
3597 if self._model_v4_path:
3598 print('No couplings information available in V4 model')
3599 return
3600
3601 try:
3602 ufomodel = ufomodels.load_model(self._curr_model.get('name'))
3603 print('Note that this is the UFO informations.')
3604 print(' "display couplings" present the actual definition')
3605 print('prints the current states of mode')
3606 print(eval('ufomodel.couplings.%s.nice_string()'%args[1]))
3607 except Exception:
3608 raise self.InvalidCmd('no couplings %s in current model' % args[1])
3609
3610 elif args[0] == 'lorentz':
3611 print('in lorentz')
3612 if self._model_v4_path:
3613 print('No lorentz information available in V4 model')
3614 return
3615 elif len(args) == 1:
3616 ufomodel = ufomodels.load_model(self._curr_model.get('name'))
3617 print(dir(ufomodel.lorentz))
3618 return
3619 try:
3620 ufomodel = ufomodels.load_model(self._curr_model.get('name'))
3621 print(getattr(ufomodel.lorentz, args[1]).nice_string())
3622 except Exception as error:
3623 raise
3624 logger.info(str(error))
3625 raise self.InvalidCmd('no lorentz %s in current model' % args[1])
3626
3627 elif args[0] == 'checks':
3628 outstr = ''
3629 if self._comparisons:
3630 comparisons = self._comparisons[0]
3631 if len(args) > 1 and args[1] == 'failed':
3632 comparisons = [c for c in comparisons if not c['passed']]
3633 outstr += "Process check results:"
3634 for comp in comparisons:
3635 outstr += "\n%s:" % comp['process'].nice_string()
3636 outstr += "\n Phase space point: (px py pz E)"
3637 for i, p in enumerate(comp['momenta']):
3638 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p)
3639 outstr += "\n Permutation values:"
3640 outstr += "\n " + str(comp['values'])
3641 if comp['passed']:
3642 outstr += "\n Process passed (rel. difference %.9e)" % \
3643 comp['difference']
3644 else:
3645 outstr += "\n Process failed (rel. difference %.9e)" % \
3646 comp['difference']
3647
3648 used_aloha = sorted(self._comparisons[1])
3649 if used_aloha:
3650 outstr += "\nChecked ALOHA routines:"
3651 for aloha in used_aloha:
3652 aloha_str = aloha[0]
3653 if aloha[1]:
3654 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]])
3655 aloha_str += "_%d" % aloha[2]
3656 outstr += "\n" + aloha_str
3657
3658 outstr += '\n'
3659 for cms_check in self._cms_checks:
3660 outstr += '*'*102+'\n'
3661 outstr += 'Complex Mass Scheme check:\n'
3662 outstr += ' -> check %s\n'%cms_check['line']
3663 outstr += '*'*102+'\n'
3664 tmp_options = copy.copy(cms_check['options'])
3665 tmp_options['show_plot']=False
3666 outstr += process_checks.output_complex_mass_scheme(
3667 cms_check['cms_result'], cms_check['output_path'],
3668 tmp_options, self._curr_model) + '\n'
3669 outstr += '*'*102+'\n\n'
3670 pydoc.pager(outstr)
3671
3672 elif args[0] == 'options':
3673 if len(args) == 1:
3674 to_print = lambda name: True
3675 else:
3676 to_print = lambda name: any(poss in name for poss in args[1:])
3677
3678 outstr = " MadGraph5_aMC@NLO Options \n"
3679 outstr += " ---------------- \n"
3680 keys = list(self.options_madgraph.keys())
3681 keys.sort()
3682 for key in keys:
3683 if not to_print(key):
3684 continue
3685 default = self.options_madgraph[key]
3686 value = self.options[key]
3687 if value == default:
3688 outstr += " %25s \t:\t%s\n" % (key,value)
3689 else:
3690 outstr += " %25s \t:\t%s (user set)\n" % (key,value)
3691 outstr += "\n"
3692 outstr += " MadEvent Options \n"
3693 outstr += " ---------------- \n"
3694 keys = list(self.options_madevent.keys())
3695 keys.sort()
3696 for key in keys:
3697 if not to_print(key):
3698 continue
3699 default = self.options_madevent[key]
3700 value = self.options[key]
3701 if value == default:
3702 outstr += " %25s \t:\t%s\n" % (key,value)
3703 else:
3704 outstr += " %25s \t:\t%s (user set)\n" % (key,value)
3705 outstr += "\n"
3706 outstr += " Configuration Options \n"
3707 outstr += " --------------------- \n"
3708 keys = list(self.options_configuration.keys())
3709 keys.sort()
3710 for key in keys:
3711 if not to_print(key):
3712 continue
3713 default = self.options_configuration[key]
3714 value = self.options[key]
3715 if value == default:
3716 outstr += " %25s \t:\t%s\n" % (key,value)
3717 else:
3718 outstr += " %25s \t:\t%s (user set)\n" % (key,value)
3719
3720 output.write(outstr)
3721 elif args[0] in ["variable"]:
3722 super(MadGraphCmd, self).do_display(line, output)
3723
3724 elif args[0] in ["modellist", "model_list"]:
3725 outstr = []
3726 template = """%-30s | %-60s | %-25s """
3727 outstr.append(template % ('name', 'restriction', 'comment'))
3728 outstr.append('*'*150)
3729 already_done = []
3730
3731
3732 if 'PYTHONPATH' in os.environ:
3733 pythonpath = os.environ['PYTHONPATH'].split(':')
3734 else:
3735 pythonpath = []
3736
3737 for base in [pjoin(MG5DIR,'models')] + pythonpath:
3738 if not os.path.exists(base):
3739 continue
3740 file_cond = lambda p : os.path.exists(pjoin(base,p,'particles.py'))
3741 mod_name = lambda name: name
3742
3743 model_list = [mod_name(name) for name in \
3744 self.path_completion('',
3745 base,
3746 only_dirs = True) \
3747 if file_cond(name)]
3748
3749 for model_name in model_list:
3750 if model_name in already_done:
3751 continue
3752 all_name = self.find_restrict_card(model_name,
3753 base_dir=base,
3754 online=False)
3755 already_done.append(model_name)
3756 restrict = [name[len(model_name):] for name in all_name
3757 if len(name)>len(model_name)]
3758
3759 comment = 'from models directory'
3760 if base != pjoin(MG5DIR,'models'):
3761 comment = 'from PYTHONPATH: %s' % base
3762 lrestrict = ', '.join(restrict)
3763 if len(lrestrict) > 50:
3764 for i in range(-1,-len(restrict), -1):
3765 lrestrict = ', '.join(restrict[:i])
3766 if len(lrestrict)<50:
3767 break
3768 outstr.append(template % (model_name, lrestrict, comment))
3769 outstr.append(template % ('', ', '.join(restrict[i:]), ''))
3770 else:
3771 outstr.append(template % (model_name, ', '.join(restrict), comment))
3772 outstr.append('*'*150)
3773
3774
3775 for model_name in self._online_model:
3776 if model_name in already_done:
3777 continue
3778 restrict = [tag for tag in self._online_model[model_name]]
3779 comment = 'automatic download from MG5aMC server'
3780 outstr.append(template % (model_name, ','.join(restrict), comment))
3781 already_done.append(model_name)
3782
3783 outstr.append('*'*150)
3784
3785 data = import_ufo.get_model_db()
3786 self._online_model2 = []
3787 for line in data:
3788 model_name, path = line.decode().split()
3789 if model_name in already_done:
3790 continue
3791 if model_name.endswith('_v4'):
3792 continue
3793
3794 if 'feynrules' in path:
3795 comment = 'automatic download from FeynRules website'
3796 elif 'madgraph.phys' in path:
3797 comment = 'automatic download from MG5aMC server'
3798 else:
3799 comment = 'automatic download.'
3800 restrict = 'unknown'
3801 outstr.append(template % (model_name, restrict, comment))
3802 self._online_model2.append(model_name)
3803 pydoc.pager('\n'.join(outstr))
3804
3805
3806 - def multiparticle_string(self, key):
3807 """Returns a nicely formatted string for the multiparticle"""
3808
3809 if self._multiparticles[key] and \
3810 isinstance(self._multiparticles[key][0], list):
3811 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\
3812 get('particle_dict')[part_id].get_name() \
3813 for part_id in id_list]) \
3814 for id_list in self._multiparticles[key]]))
3815 else:
3816 return "%s = %s" % (key, " ".join([self._curr_model.\
3817 get('particle_dict')[part_id].get_name() \
3818 for part_id in self._multiparticles[key]]))
3819
3845
3846
3847
3848 - def draw(self, line,selection='all',Dtype=''):
3912
3913
3915 """Check a given process or set of processes"""
3916
3917 def create_lambda_values_list(lower_bound, N):
3918 """ Returns a list of values spanning the range [1.0, lower_bound] with
3919 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered
3920 by N values uniformly distributed. For example, lower_bound=1e-2
3921 and N=5 returns:
3922 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]"""
3923
3924 lCMS_values = [1]
3925 exp = 0
3926 n = 0
3927 while lCMS_values[-1]>=lower_bound:
3928 n = (n+1)
3929 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N)))
3930 if lCMS_values[-1]==lCMS_values[-2]:
3931 lCMS_values.pop()
3932 exp = (n+1)//N
3933
3934 lCMS_values = lCMS_values[:-1]
3935 if lCMS_values[-1]!=lower_bound:
3936 lCMS_values.append(lower_bound)
3937
3938 return lCMS_values
3939
3940
3941
3942 args = self.split_arg(line)
3943
3944 param_card = self.check_check(args)
3945
3946 options= {'events':None}
3947 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card):
3948 logger_check.info("Will use the param_card contained in the banner and the events associated")
3949 import madgraph.various.banner as banner
3950 options['events'] = param_card
3951 mybanner = banner.Banner(param_card)
3952 param_card = mybanner.charge_card('param_card')
3953
3954 aloha_lib.KERNEL.clean()
3955
3956 gauge = str(self.options['gauge'])
3957 options['reuse'] = args[1]=="-reuse"
3958 args = args[:1]+args[2:]
3959
3960
3961 if args[0] in ['stability', 'profile']:
3962 options['npoints'] = int(args[1])
3963 args = args[:1]+args[2:]
3964 MLoptions={}
3965 i=-1
3966 CMS_options = {}
3967 while args[i].startswith('--'):
3968 option = args[i].split('=')
3969 if option[0] =='--energy':
3970 options['energy']=float(option[1])
3971 elif option[0] == '--events' and option[1]:
3972 if option[1] == 'None':
3973 options['events'] = None
3974 elif not os.path.exists(option[1]):
3975 raise Exception('path %s does not exists' % option[1])
3976 else:
3977 options['events'] = option[1]
3978 elif option[0] == '--skip_evt':
3979 options['skip_evt']=int(option[1])
3980 elif option[0]=='--split_orders':
3981 options['split_orders']=int(option[1])
3982 elif option[0]=='--helicity':
3983 try:
3984 options['helicity']=int(option[1])
3985 except ValueError:
3986 raise self.InvalidCmd("The value of the 'helicity' option"+\
3987 " must be an integer, not %s."%option[1])
3988 elif option[0]=='--reduction':
3989 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')]
3990 elif option[0]=='--collier_mode':
3991 MLoptions['COLLIERMode']=int(option[1])
3992 elif option[0]=='--collier_cache':
3993 MLoptions['COLLIERGlobalCache']=int(option[1])
3994 elif option[0]=='--collier_req_acc':
3995 if option[1]!='auto':
3996 MLoptions['COLLIERRequiredAccuracy']=float(option[1])
3997 elif option[0]=='--collier_internal_stability_test':
3998 MLoptions['COLLIERUseInternalStabilityTest']=eval(option[1])
3999 elif option[0]=='--CTModeRun':
4000 try:
4001 MLoptions['CTModeRun']=int(option[1])
4002 except ValueError:
4003 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\
4004 " must be an integer, not %s."%option[1])
4005 elif option[0]=='--offshellness':
4006 CMS_options['offshellness'] = float(option[1])
4007 if CMS_options['offshellness']<=-1.0:
4008 raise self.InvalidCmd('Offshellness must be number larger or'+
4009 ' equal to -1.0, not %f'%CMS_options['offshellness'])
4010 elif option[0]=='--analyze':
4011 options['analyze'] = option[1]
4012 elif option[0]=='--show_plot':
4013 options['show_plot'] = 'true' in option[1].lower()
4014 elif option[0]=='--report':
4015 options['report'] = option[1].lower()
4016 elif option[0]=='--seed':
4017 options['seed'] = int(option[1])
4018 elif option[0]=='--name':
4019 if '.' in option[1]:
4020 raise self.InvalidCmd("Do not specify the extension in the"+
4021 " name of the run")
4022 CMS_options['name'] = option[1]
4023 elif option[0]=='--resonances':
4024 if option[1]=='all':
4025 CMS_options['resonances'] = 'all'
4026 else:
4027 try:
4028 resonances=eval(option[1])
4029 except:
4030 raise self.InvalidCmd("Could not evaluate 'resonances'"+
4031 " option '%s'"%option[1])
4032 if isinstance(resonances,int) and resonances>0:
4033 CMS_options['resonances'] = resonances
4034 elif isinstance(resonances,list) and all(len(res)==2 and
4035 isinstance(res[0],int) and all(isinstance(i, int) for i in
4036 res[1]) for res in resonances):
4037 CMS_options['resonances'] = resonances
4038 else:
4039 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+
4040 " or and integer or a list of tuples of the form "+
4041 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1])
4042 elif option[0]=='--tweak':
4043
4044 value = option[1]
4045
4046 if value=='alltweaks':
4047 value=str(['default','seed667(seed667)','seed668(seed668)',
4048 'allwidths->0.9*allwidths(widths_x_0.9)',
4049 'allwidths->0.99*allwidths(widths_x_0.99)',
4050 'allwidths->1.01*allwidths(widths_x_1.01)',
4051 'allwidths->1.1*allwidths(widths_x_1.1)',
4052 'logp->logm(logp2logm)','logm->logp(logm2logp)'])
4053 try:
4054 tweaks = eval(value)
4055 if isinstance(tweaks, str):
4056 tweaks = [value]
4057 elif not isinstance(tweaks,list):
4058 tweaks = [value]
4059 except:
4060 tweaks = [value]
4061 if not all(isinstance(t,str) for t in tweaks):
4062 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value)
4063 CMS_options['tweak'] = []
4064 for tweakID, tweakset in enumerate(tweaks):
4065 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset)
4066 if specs:
4067 tweakset = specs.group('tweakset')
4068 name = specs.group('name')
4069 else:
4070 if tweakset!='default':
4071 name = 'tweak_%d'%(tweakID+1)
4072 else:
4073 name = ''
4074 new_tweak_set = {'custom':[],'params':{},'name':name}
4075 for tweak in tweakset.split('&'):
4076 if tweak=='default':
4077 continue
4078 if tweak.startswith('seed'):
4079 new_tweak_set['custom'].append(tweak)
4080 continue
4081 try:
4082 param, replacement = tweak.split('->')
4083 except ValueError:
4084 raise self.InvalidCmd("Tweak specification '%s'"%\
4085 tweak+" is incorrect. It should be of"+\
4086 " the form a->_any_function_of_(a,lambdaCMS).")
4087 if param in ['logp','logm','log'] and \
4088 replacement in ['logp','logm','log']:
4089 new_tweak_set['custom'].append(tweak)
4090 continue
4091 try:
4092
4093
4094 orig_param, orig_replacement = param, replacement
4095 replacement = replacement.replace(param,
4096 '__tmpprefix__%s'%param)
4097 param = '__tmpprefix__%s'%param
4098 res = float(eval(replacement.lower(),
4099 {'lambdacms':1.0,param.lower():98.85}))
4100 except:
4101 raise self.InvalidCmd("The substitution expression "+
4102 "'%s' for the tweaked parameter"%orig_replacement+
4103 " '%s' could not be evaluated. It must be an "%orig_param+
4104 "expression of the parameter and 'lambdaCMS'.")
4105 new_tweak_set['params'][param.lower()] = replacement.lower()
4106 CMS_options['tweak'].append(new_tweak_set)
4107
4108 elif option[0]=='--recompute_width':
4109 if option[1].lower() not in ['never','always','first_time','auto']:
4110 raise self.InvalidCmd("The option 'recompute_width' can "+\
4111 "only be 'never','always', 'first_time' or 'auto' (default).")
4112 CMS_options['recompute_width'] = option[1]
4113 elif option[0]=='--loop_filter':
4114
4115
4116
4117 CMS_options['loop_filter'] = '='.join(option[1:])
4118 elif option[0]=='--diff_lambda_power':
4119
4120
4121
4122
4123 try:
4124 CMS_options['diff_lambda_power']=float(option[1])
4125 except ValueError:
4126 raise self.InvalidCmd("the '--diff_lambda_power' option"+\
4127 " must be an integer or float, not '%s'."%option[1])
4128 elif option[0]=='--lambda_plot_range':
4129 try:
4130 plot_range=eval(option[1])
4131 except Exception as e:
4132 raise self.InvalidCmd("The plot range specified %s"%option[1]+\
4133 " is not a valid syntax. Error:\n%s"%str(e))
4134 if not isinstance(plot_range,(list,tuple)) or \
4135 len(plot_range)!=2 or any(not isinstance(p,(float,int))
4136 for p in plot_range):
4137 raise self.InvalidCmd("The plot range specified %s"\
4138 %option[1]+" is invalid")
4139 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range])
4140 elif option[0]=='--lambdaCMS':
4141 try:
4142 lambda_values = eval(option[1])
4143 except SyntaxError:
4144 raise self.InvalidCmd("'%s' is not a correct"%option[1]+
4145 " python expression for lambdaCMS values.")
4146 if isinstance(lambda_values,list):
4147 if lambda_values[0]!=1.0:
4148 raise self.InvalidCmd("The first value of the lambdaCMS values"+
4149 " specified must be 1.0, not %s"%str(lambda_values))
4150 for l in lambda_values:
4151 if not isinstance(l,float):
4152 raise self.InvalidCmd("All lambda CMS values must be"+
4153 " float, not '%s'"%str(l))
4154 elif isinstance(lambda_values,(tuple,float)):
4155
4156
4157
4158
4159 if isinstance(lambda_values, float):
4160
4161 lower_bound = lambda_values
4162 N = 10
4163 else:
4164 if isinstance(lambda_values[0],float) and \
4165 isinstance(lambda_values[1],int):
4166 lower_bound = lambda_values[0]
4167 N = lambda_values[1]
4168 else:
4169 raise self.InvalidCmd("'%s' must be a "%option[1]+
4170 "tuple with types (float, int).")
4171 lambda_values = create_lambda_values_list(lower_bound,N)
4172 else:
4173 raise self.InvalidCmd("'%s' must be an expression"%option[1]+
4174 " for either a float, tuple or list.")
4175 lower_bound = lambda_values[-1]
4176
4177
4178
4179
4180
4181
4182 CMS_options['lambdaCMS'] = lambda_values
4183 elif option[0]=='--cms':
4184 try:
4185 CMS_expansion_orders, CMS_expansion_parameters = \
4186 option[1].split(',')
4187 except ValueError:
4188 raise self.InvalidCmd("CMS expansion specification '%s'"%\
4189 args[i]+" is incorrect.")
4190 CMS_options['expansion_orders'] = [expansion_order for
4191 expansion_order in CMS_expansion_orders.split('&')]
4192 CMS_options['expansion_parameters'] = {}
4193 for expansion_parameter in CMS_expansion_parameters.split('&'):
4194 try:
4195 param, replacement = expansion_parameter.split('->')
4196 except ValueError:
4197 raise self.InvalidCmd("CMS expansion specification '%s'"%\
4198 expansion_parameter+" is incorrect. It should be of"+\
4199 " the form a->_any_function_of_(a,lambdaCMS).")
4200 try:
4201
4202
4203 orig_param, orig_replacement = param, replacement
4204 replacement = replacement.replace(param,
4205 '__tmpprefix__%s'%param)
4206 param = '__tmpprefix__%s'%param
4207 res = float(eval(replacement.lower(),
4208 {'lambdacms':1.0,param.lower():98.85}))
4209 except:
4210 raise self.InvalidCmd("The substitution expression "+
4211 "'%s' for CMS expansion parameter"%orig_replacement+
4212 " '%s' could not be evaluated. It must be an "%orig_param+
4213 "expression of the parameter and 'lambdaCMS'.")
4214
4215
4216 CMS_options['expansion_parameters'][param.lower()]=\
4217 replacement.lower()
4218 else:
4219 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0])
4220
4221 i=i-1
4222 args = args[:i+1]
4223
4224 if args[0]=='options':
4225
4226 logger_check.info("Options for the command 'check' are:")
4227 logger_check.info("{:<20} {}".format(' name','default value'))
4228 logger_check.info("-"*40)
4229 for key, value in options.items():
4230 logger_check.info("{:<20} = {}".format('--%s'%key,str(value)))
4231 return
4232
4233 if args[0].lower()=='cmsoptions':
4234
4235 logger_check.info("Special options for the command 'check cms' are:")
4236 logger_check.info("{:<20} {}".format(' name','default value'))
4237 logger_check.info("-"*40)
4238 for key, value in CMS_options.items():
4239 logger_check.info("{:<20} = {}".format('--%s'%key,str(value)))
4240 return
4241
4242
4243 if args[0]!='cms' and options['seed']!=-1:
4244
4245
4246
4247 logger_check.info('Setting random seed to %d.'%options['seed'])
4248 random.seed(options['seed'])
4249
4250 proc_line = " ".join(args[1:])
4251
4252 if not (args[0]=='cms' and options['analyze']!='None'):
4253 myprocdef = self.extract_process(proc_line)
4254
4255
4256 if not myprocdef:
4257 raise self.InvalidCmd("Empty or wrong format process, please try again.")
4258
4259 if myprocdef.get('NLO_mode')=='all':
4260 myprocdef.set('NLO_mode','virt')
4261 else:
4262 myprocdef = None
4263
4264
4265
4266 output_path = os.getcwd()
4267
4268 if args[0] in ['timing','stability', 'profile'] and not \
4269 myprocdef.get('perturbation_couplings'):
4270 raise self.InvalidCmd("Only loop processes can have their "+
4271 " timings or stability checked.")
4272
4273 if args[0]=='gauge' and \
4274 not myprocdef.get('perturbation_couplings') in [[],['QCD']]:
4275 raise self.InvalidCmd(
4276 """Feynman vs unitary gauge comparisons can only be done if there are no loop
4277 propagators affected by this gauge. Typically, either processes at tree level
4278 or including only QCD perturbations can be considered here.""")
4279
4280 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2:
4281 raise self.InvalidCmd("The current model does not allow for both "+\
4282 "Feynman and unitary gauge.")
4283
4284
4285 loggers = [logging.getLogger('madgraph.diagram_generation'),
4286 logging.getLogger('madgraph.loop_diagram_generation'),
4287 logging.getLogger('ALOHA'),
4288 logging.getLogger('madgraph.helas_objects'),
4289 logging.getLogger('madgraph.loop_exporter'),
4290 logging.getLogger('madgraph.export_v4'),
4291 logging.getLogger('cmdprint'),
4292 logging.getLogger('madgraph.model'),
4293 logging.getLogger('madgraph.base_objects')]
4294 old_levels = [log.level for log in loggers]
4295 for log in loggers:
4296 log.setLevel(logging.WARNING)
4297
4298
4299 cpu_time1 = time.time()
4300
4301
4302
4303
4304
4305
4306
4307 if myprocdef:
4308 if myprocdef.get('perturbation_couplings')==[]:
4309 aloha.loop_mode = False
4310
4311 comparisons = []
4312 gauge_result = []
4313 gauge_result_no_brs = []
4314 lorentz_result =[]
4315 nb_processes = 0
4316 timings = []
4317 stability = []
4318 profile_time = []
4319 profile_stab = []
4320 cms_results = []
4321
4322 if "_cuttools_dir" in dir(self):
4323 CT_dir = self._cuttools_dir
4324 else:
4325 CT_dir =""
4326 if "MLReductionLib" in MLoptions:
4327 if 1 in MLoptions["MLReductionLib"]:
4328 MLoptions["MLReductionLib"].remove(1)
4329
4330 TIR_dir={}
4331 if "_iregi_dir" in dir(self):
4332 TIR_dir['iregi_dir']=self._iregi_dir
4333 else:
4334 if "MLReductionLib" in MLoptions:
4335 if 3 in MLoptions["MLReductionLib"]:
4336 logger_check.warning('IREGI not available on your system; it will be skipped.')
4337 MLoptions["MLReductionLib"].remove(3)
4338
4339
4340 if "MLReductionLib" in MLoptions:
4341 if 2 in MLoptions["MLReductionLib"]:
4342 logger_check.warning('PJFRY not supported anymore; it will be skipped.')
4343 MLoptions["MLReductionLib"].remove(2)
4344
4345 if 'golem' in self.options and isinstance(self.options['golem'],str):
4346 TIR_dir['golem_dir']=self.options['golem']
4347 else:
4348 if "MLReductionLib" in MLoptions:
4349 if 4 in MLoptions["MLReductionLib"]:
4350 logger_check.warning('GOLEM not available on your system; it will be skipped.')
4351 MLoptions["MLReductionLib"].remove(4)
4352
4353 if 'samurai' in self.options and isinstance(self.options['samurai'],str):
4354 TIR_dir['samurai_dir']=self.options['samurai']
4355 else:
4356 if "MLReductionLib" in MLoptions:
4357 if 5 in MLoptions["MLReductionLib"]:
4358 logger_check.warning('Samurai not available on your system; it will be skipped.')
4359 MLoptions["MLReductionLib"].remove(5)
4360
4361 if 'collier' in self.options and isinstance(self.options['collier'],str):
4362 TIR_dir['collier_dir']=self.options['collier']
4363 else:
4364 if "MLReductionLib" in MLoptions:
4365 if 7 in MLoptions["MLReductionLib"]:
4366 logger_check.warning('Collier not available on your system; it will be skipped.')
4367 MLoptions["MLReductionLib"].remove(7)
4368
4369 if 'ninja' in self.options and isinstance(self.options['ninja'],str):
4370 TIR_dir['ninja_dir']=self.options['ninja']
4371 else:
4372 if "MLReductionLib" in MLoptions:
4373 if 6 in MLoptions["MLReductionLib"]:
4374 logger_check.warning('Ninja not available on your system; it will be skipped.')
4375 MLoptions["MLReductionLib"].remove(6)
4376
4377 if args[0] in ['timing']:
4378 timings = process_checks.check_timing(myprocdef,
4379 param_card = param_card,
4380 cuttools=CT_dir,
4381 tir=TIR_dir,
4382 options = options,
4383 cmd = self,
4384 output_path = output_path,
4385 MLOptions = MLoptions
4386 )
4387
4388 if args[0] in ['stability']:
4389 stability=process_checks.check_stability(myprocdef,
4390 param_card = param_card,
4391 cuttools=CT_dir,
4392 tir=TIR_dir,
4393 options = options,
4394 output_path = output_path,
4395 cmd = self,
4396 MLOptions = MLoptions)
4397
4398 if args[0] in ['profile']:
4399
4400
4401 profile_time, profile_stab = process_checks.check_profile(myprocdef,
4402 param_card = param_card,
4403 cuttools=CT_dir,
4404 tir=TIR_dir,
4405 options = options,
4406 MLOptions = MLoptions,
4407 output_path = output_path,
4408 cmd = self)
4409
4410 if args[0] in ['gauge', 'full'] and \
4411 len(self._curr_model.get('gauge')) == 2 and\
4412 myprocdef.get('perturbation_couplings') in [[],['QCD']]:
4413
4414 line = " ".join(args[1:])
4415 myprocdef = self.extract_process(line)
4416 if gauge == 'unitary':
4417 myprocdef_unit = myprocdef
4418 self.do_set('gauge Feynman', log=False)
4419 myprocdef_feyn = self.extract_process(line)
4420 else:
4421 myprocdef_feyn = myprocdef
4422 self.do_set('gauge unitary', log=False)
4423 myprocdef_unit = self.extract_process(line)
4424
4425 nb_part_unit = len(myprocdef_unit.get('model').get('particles'))
4426 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles'))
4427 if nb_part_feyn == nb_part_unit:
4428 logger_check.error('No Goldstone present for this check!!')
4429 gauge_result_no_brs = process_checks.check_unitary_feynman(
4430 myprocdef_unit, myprocdef_feyn,
4431 param_card = param_card,
4432 options=options,
4433 cuttools=CT_dir,
4434 tir=TIR_dir,
4435 reuse = options['reuse'],
4436 output_path = output_path,
4437 cmd = self)
4438
4439
4440 self.do_set('gauge %s' % gauge, log=False)
4441 nb_processes += len(gauge_result_no_brs)
4442
4443 if args[0] in ['permutation', 'full']:
4444 comparisons = process_checks.check_processes(myprocdef,
4445 param_card = param_card,
4446 quick = True,
4447 cuttools=CT_dir,
4448 tir=TIR_dir,
4449 reuse = options['reuse'],
4450 cmd = self,
4451 output_path = output_path,
4452 options=options)
4453 nb_processes += len(comparisons[0])
4454
4455 if args[0] in ['lorentz', 'full']:
4456 myprocdeff = copy.copy(myprocdef)
4457 lorentz_result = process_checks.check_lorentz(myprocdeff,
4458 param_card = param_card,
4459 cuttools=CT_dir,
4460 tir=TIR_dir,
4461 reuse = options['reuse'],
4462 cmd = self,
4463 output_path = output_path,
4464 options=options)
4465 nb_processes += len(lorentz_result)
4466
4467 if args[0] in ['brs', 'full']:
4468 gauge_result = process_checks.check_gauge(myprocdef,
4469 param_card = param_card,
4470 cuttools=CT_dir,
4471 tir=TIR_dir,
4472 reuse = options['reuse'],
4473 cmd = self,
4474 output_path = output_path,
4475 options=options)
4476 nb_processes += len(gauge_result)
4477
4478
4479
4480 if args[0] in ['cms']:
4481
4482 cms_original_setup = self.options['complex_mass_scheme']
4483 process_line = " ".join(args[1:])
4484
4485 for key, value in CMS_options.items():
4486 if key=='tweak':
4487 continue
4488 if key not in options:
4489 options[key] = value
4490 else:
4491 raise MadGraph5Error("Option '%s' is both in the option"%key+\
4492 " and CMS_option dictionary.")
4493
4494 if options['analyze']=='None':
4495 cms_results = []
4496 for tweak in CMS_options['tweak']:
4497 options['tweak']=tweak
4498
4499 guessed_proc = myprocdef.get_process(
4500 [leg.get('ids')[0] for leg in myprocdef.get('legs')
4501 if not leg.get('state')],
4502 [leg.get('ids')[0] for leg in myprocdef.get('legs')
4503 if leg.get('state')])
4504 save_path = process_checks.CMS_save_path('pkl',
4505 {'ordered_processes':[guessed_proc.base_string()],
4506 'perturbation_orders':guessed_proc.get('perturbation_couplings')},
4507 self._curr_model, options, output_path=output_path)
4508 if os.path.isfile(save_path) and options['reuse']:
4509 cms_result = save_load_object.load_from_file(save_path)
4510 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"%
4511 (tweak['name'],save_path))
4512 if cms_result is None:
4513 raise self.InvalidCmd('The complex mass scheme check result'+
4514 " file below could not be read.\n %s"%save_path)
4515 else:
4516 cms_result = process_checks.check_complex_mass_scheme(
4517 process_line,
4518 param_card = param_card,
4519 cuttools=CT_dir,
4520 tir=TIR_dir,
4521 cmd = self,
4522 output_path = output_path,
4523 MLOptions = MLoptions,
4524 options=options)
4525
4526 save_path = process_checks.CMS_save_path('pkl', cms_result,
4527 self._curr_model, options, output_path=output_path)
4528 cms_results.append((cms_result,save_path,tweak['name']))
4529 else:
4530 cms_result = save_load_object.load_from_file(
4531 options['analyze'].split(',')[0])
4532 cms_results.append((cms_result,options['analyze'].split(',')[0],
4533 CMS_options['tweak'][0]['name']))
4534 if cms_result is None:
4535 raise self.InvalidCmd('The complex mass scheme check result'+
4536 " file below could not be read.\n %s"
4537 %options['analyze'].split(',')[0])
4538
4539
4540 self.do_set('complex_mass_scheme %s'%str(cms_original_setup),
4541 log=False)
4542
4543 nb_processes += len(cms_result['ordered_processes'])
4544
4545 cpu_time2 = time.time()
4546 logger_check.info("%i check performed in %s"% (nb_processes,
4547 misc.format_time(int(cpu_time2 - cpu_time1))))
4548
4549 if args[0] in ['cms']:
4550 text = "Note that the complex mass scheme test in principle only\n"
4551 text+= "works for stable particles in final states.\n\ns"
4552 if args[0] not in ['timing','stability', 'profile', 'cms']:
4553 if self.options['complex_mass_scheme']:
4554 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n"
4555 text+= "results only for stable particles in final states.\n\ns"
4556 elif not myprocdef.get('perturbation_couplings'):
4557 text = "Note That all width have been set to zero for those checks\n\n"
4558 else:
4559 text = "\n"
4560 else:
4561 text ="\n"
4562
4563 if timings:
4564 text += 'Timing result for the '+('optimized' if \
4565 self.options['loop_optimized_output'] else 'default')+' output:\n'
4566
4567 text += process_checks.output_timings(myprocdef, timings)
4568 if stability:
4569 text += 'Stability result for the '+('optimized' if \
4570 self.options['loop_optimized_output'] else 'default')+' output:\n'
4571 text += process_checks.output_stability(stability,output_path)
4572
4573 if profile_time and profile_stab:
4574 text += 'Timing result '+('optimized' if \
4575 self.options['loop_optimized_output'] else 'default')+':\n'
4576 text += process_checks.output_profile(myprocdef, profile_stab,
4577 profile_time, output_path, options['reuse']) + '\n'
4578 if lorentz_result:
4579 text += 'Lorentz invariance results:\n'
4580 text += process_checks.output_lorentz_inv(lorentz_result) + '\n'
4581 if gauge_result:
4582 text += 'Gauge results:\n'
4583 text += process_checks.output_gauge(gauge_result) + '\n'
4584 if gauge_result_no_brs:
4585 text += 'Gauge results (switching between Unitary/Feynman/axial gauge):\n'
4586 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n'
4587 if cms_results:
4588 text += 'Complex mass scheme results (varying width in the off-shell regions):\n'
4589 cms_result = cms_results[0][0]
4590 if len(cms_results)>1:
4591 analyze = []
4592 for i, (cms_res, save_path, tweakname) in enumerate(cms_results):
4593 save_load_object.save_to_file(save_path, cms_res)
4594 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"%
4595 (tweakname,save_path))
4596 if i==0:
4597 analyze.append(save_path)
4598 else:
4599 analyze.append('%s(%s)'%(save_path,tweakname))
4600 options['analyze']=','.join(analyze)
4601 options['tweak'] = CMS_options['tweak'][0]
4602
4603 self._cms_checks.append({'line':line, 'cms_result':cms_result,
4604 'options':options, 'output_path':output_path})
4605 text += process_checks.output_complex_mass_scheme(cms_result,
4606 output_path, options, self._curr_model,
4607 output='concise_text' if options['report']=='concise' else 'text')+'\n'
4608
4609 if comparisons and len(comparisons[0])>0:
4610 text += 'Process permutation results:\n'
4611 text += process_checks.output_comparisons(comparisons[0]) + '\n'
4612 self._comparisons = comparisons
4613
4614
4615 if len(text.split('\n'))>20 and not '-reuse' in line and text!='':
4616 if 'test_manager' not in sys.argv[0]:
4617 pydoc.pager(text)
4618
4619
4620 for i, log in enumerate(loggers):
4621 log.setLevel(old_levels[i])
4622
4623
4624
4625 if len(text.split('\n'))<=20 or options['reuse']:
4626
4627 logging.getLogger('madgraph.check_cmd').info(text)
4628 else:
4629 logging.getLogger('madgraph.check_cmd').debug(text)
4630
4631
4632 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL)
4633 if not options['reuse']:
4634 process_checks.clean_up(self._mgme_dir)
4635
4636
4654
4655
4656
4658 """Main commands: Generate an amplitude for a given process"""
4659
4660 self.clean_process()
4661 self._generate_info = line
4662
4663
4664 args = self.split_arg(line)
4665 args.insert(0, 'process')
4666 self.do_add(" ".join(args))
4667
4669 """Extract a process definition from a string. Returns
4670 a ProcessDefinition."""
4671
4672 orig_line = line
4673
4674 if not len(re.findall('>\D', line)) in [1,2]:
4675 self.do_help('generate')
4676 raise self.InvalidCmd('Wrong use of \">\" special character.')
4677
4678
4679
4680
4681 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)")
4682 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line)
4683
4684
4685
4686
4687
4688
4689 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$")
4690 proc_number_re = proc_number_pattern.match(line)
4691 if proc_number_re:
4692 proc_number = int(proc_number_re.group(2))
4693 line = proc_number_re.group(1)+ proc_number_re.group(3)
4694
4695
4696
4697 perturbation_couplings_pattern = \
4698 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\
4699 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$")
4700 perturbation_couplings_re = perturbation_couplings_pattern.match(line)
4701 perturbation_couplings = ""
4702 LoopOption= 'tree'
4703 HasBorn= True
4704 if perturbation_couplings_re:
4705 perturbation_couplings = perturbation_couplings_re.group("pertOrders")
4706 option=perturbation_couplings_re.group("option")
4707 if option:
4708 if option in self._valid_nlo_modes:
4709 LoopOption=option
4710 if option=='sqrvirt':
4711 LoopOption='virt'
4712 HasBorn=False
4713 elif option=='noborn':
4714 HasBorn=False
4715 else:
4716 raise self.InvalidCmd("NLO mode %s is not valid. "%option+\
4717 "Valid modes are %s. "%str(self._valid_nlo_modes))
4718 else:
4719 LoopOption='all'
4720
4721 line = perturbation_couplings_re.group("proc")+\
4722 perturbation_couplings_re.group("rest")
4723
4724
4725 order_pattern = re.compile(\
4726 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\
4727 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*?(?P<after>.*)")
4728 order_re = order_pattern.match(line)
4729 squared_orders = {}
4730 orders = {}
4731 constrained_orders = {}
4732
4733
4734
4735
4736 split_orders = []
4737 while order_re:
4738 type = order_re.group('type')
4739 if order_re.group('name').endswith('^2'):
4740 if type not in self._valid_sqso_types:
4741 raise self.InvalidCmd("Type of squared order "+\
4742 "constraint '%s'"% type+" is not supported.")
4743 if type == '=':
4744 name = order_re.group('name')
4745 value = order_re.group('value')
4746 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\
4747 {'n':name, 'v': value})
4748 type = "<="
4749 squared_orders[order_re.group('name')[:-2]] = \
4750 (int(order_re.group('value')),type)
4751 else:
4752 if type not in self._valid_amp_so_types:
4753 raise self.InvalidCmd("Amplitude order constraints can only be of type %s"%\
4754 (', '.join(self._valid_amp_so_types))+", not '%s'."%type)
4755 name = order_re.group('name')
4756 value = int(order_re.group('value'))
4757 if type in ['=', '<=']:
4758 if type == '=' and value != 0:
4759 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\
4760 {'n':name, 'v': value})
4761 orders[name] = value
4762 elif type == "==":
4763 constrained_orders[name] = (value, type)
4764 if name not in squared_orders:
4765 squared_orders[name] = (2 * value,'==')
4766 if True:
4767 orders[name] = value
4768
4769 elif type == ">":
4770 constrained_orders[name] = (value, type)
4771 if name not in squared_orders:
4772 squared_orders[name] = (2 * value,'>')
4773
4774 line = '%s %s' % (order_re.group('before'),order_re.group('after'))
4775 order_re = order_pattern.match(line)
4776
4777
4778 if self.options['default_unset_couplings'] != 99 and \
4779 (orders or squared_orders):
4780
4781 to_set = [name for name in self._curr_model.get('coupling_orders')
4782 if name not in orders and name not in squared_orders]
4783 if to_set:
4784 logger.info('the following coupling will be allowed up to the maximal value of %s: %s' %
4785 (self.options['default_unset_couplings'], ', '.join(to_set)), '$MG:BOLD')
4786 for name in to_set:
4787 orders[name] = int(self.options['default_unset_couplings'])
4788
4789
4790 if constrained_orders and LoopOption != 'tree':
4791 raise self.InvalidCmd("Amplitude order constraints (for not LO processes) can only be of type %s"%\
4792 (', '.join(['<=']))+", not '%s'."%type)
4793
4794
4795
4796
4797
4798
4799 if orders=={} and squared_orders!={}:
4800 for order in squared_orders.keys():
4801 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>':
4802 orders[order]=squared_orders[order][0]
4803 else:
4804 orders[order]=99
4805
4806
4807 if not self._curr_model['case_sensitive']:
4808
4809 line = line.lower()
4810
4811
4812 slash = line.find("/")
4813 dollar = line.find("$")
4814 forbidden_particles = ""
4815 if slash > 0:
4816 if dollar > slash:
4817 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line)
4818 else:
4819 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line)
4820 if forbidden_particles_re:
4821 forbidden_particles = forbidden_particles_re.group(2)
4822 line = forbidden_particles_re.group(1)
4823 if len(forbidden_particles_re.groups()) > 2:
4824 line = line + forbidden_particles_re.group(3)
4825
4826
4827 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line)
4828 forbidden_schannels = ""
4829 if forbidden_schannels_re:
4830 forbidden_schannels = forbidden_schannels_re.group(2)
4831 line = forbidden_schannels_re.group(1)
4832
4833
4834 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line)
4835 forbidden_onsh_schannels = ""
4836 if forbidden_onsh_schannels_re:
4837 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2)
4838 line = forbidden_onsh_schannels_re.group(1)
4839
4840
4841 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line)
4842 required_schannels = ""
4843 if required_schannels_re:
4844 required_schannels = required_schannels_re.group(2)
4845 line = required_schannels_re.group(1) + ">" + \
4846 required_schannels_re.group(3)
4847
4848 args = self.split_arg(line)
4849
4850 myleglist = base_objects.MultiLegList()
4851 state = False
4852
4853
4854 for part_name in args:
4855 if part_name == '>':
4856 if not myleglist:
4857 raise self.InvalidCmd("No final state particles")
4858 state = True
4859 continue
4860
4861 mylegids = []
4862 polarization = []
4863 if '{' in part_name:
4864 part_name, pol = part_name.split('{',1)
4865 pol, rest = pol.split('}',1)
4866
4867 no_dup_name = part_name
4868 while True:
4869 try:
4870 spin = self._curr_model.get_particle(no_dup_name).get('spin')
4871 break
4872 except AttributeError:
4873 if no_dup_name in self._multiparticles:
4874 spins = set([self._curr_model.get_particle(p).get('spin') for p in self._multiparticles[no_dup_name]])
4875 if len(spins) > 1:
4876 raise self.InvalidCmd('Can not use polarised on multi-particles for multi-particles with various spin')
4877 else:
4878 spin = spins.pop()
4879 break
4880 elif no_dup_name[0].isdigit():
4881 no_dup_name = no_dup_name[1:]
4882 else:
4883 raise
4884 if rest:
4885 raise self.InvalidCmd('A space is required after the "}" symbol to separate particles')
4886 ignore =False
4887 for i,p in enumerate(pol):
4888 if ignore or p==',':
4889 ignore= False
4890 continue
4891 if p in ['t','T']:
4892 if spin == 3:
4893 polarization += [1,-1]
4894 else:
4895 raise self.InvalidCmd('"T" (transverse) polarization are only supported for spin one particle.')
4896 elif p in ['l', 'L']:
4897 if spin == 3:
4898 logger.warning('"L" polarization is interpreted as Left for Longitudinal please use "0".')
4899 polarization += [-1]
4900 elif p in ['R','r']:
4901 polarization += [1]
4902 elif p in ["A",'a']:
4903 if spin == 3:
4904 polarization += [99]
4905 else:
4906 raise self.InvalidCmd('"A" (auxiliary) polarization are only supported for spin one particle.')
4907 elif p in ['+']:
4908 if i +1 < len(pol) and pol[i+1].isdigit():
4909 p = int(pol[i+1])
4910 if abs(p) > 3:
4911 raise self.InvalidCmd("polarization are between -3 and 3")
4912 polarization.append(p)
4913 ignore = True
4914 else:
4915 polarization += [1]
4916 elif p in ['-']:
4917 if i+1 < len(pol) and pol[i+1].isdigit():
4918 p = int(pol[i+1])
4919 if abs(p) > 3:
4920 raise self.InvalidCmd("polarization are between -3 and 3")
4921 polarization.append(-p)
4922 ignore = True
4923 else:
4924 polarization += [-1]
4925 elif p in [0,'0']:
4926 if spin in [1,2]:
4927 raise self.InvalidCmd('"0" (longitudinal) polarization are not supported for scalar/fermion.')
4928 else:
4929 polarization += [0]
4930 elif p.isdigit():
4931 p = int(p)
4932 if abs(p) > 3:
4933 raise self.InvalidCmd("polarization are between -3 and 3")
4934 polarization.append(p)
4935 else:
4936 raise self.InvalidCmd('Invalid Polarization')
4937
4938 duplicate =1
4939 if part_name in self._multiparticles:
4940 if isinstance(self._multiparticles[part_name][0], list):
4941 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \
4942 " which can be used only for required s-channels")
4943 mylegids.extend(self._multiparticles[part_name])
4944 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit():
4945 if int(part_name) in self._curr_model.get('particle_dict'):
4946 mylegids.append(int(part_name))
4947 else:
4948 raise self.InvalidCmd("No pdg_code %s in model" % part_name)
4949 else:
4950 mypart = self._curr_model['particles'].get_copy(part_name)
4951
4952 if mypart:
4953 mylegids.append(mypart.get_pdg_code())
4954 else:
4955
4956 if part_name[0].isdigit():
4957 duplicate, part_name = int(part_name[0]), part_name[1:]
4958 if part_name in self._multiparticles:
4959 if isinstance(self._multiparticles[part_name][0], list):
4960 raise self.InvalidCmd(\
4961 "Multiparticle %s is or-multiparticle" % part_name + \
4962 " which can be used only for required s-channels")
4963 mylegids.extend(self._multiparticles[part_name])
4964 else:
4965 mypart = self._curr_model['particles'].get_copy(part_name)
4966 mylegids.append(mypart.get_pdg_code())
4967
4968 if mylegids:
4969 for _ in range(duplicate):
4970 myleglist.append(base_objects.MultiLeg({'ids':mylegids,
4971 'state':state,
4972 'polarization': polarization}))
4973 else:
4974 raise self.InvalidCmd("No particle %s in model" % part_name)
4975
4976
4977 if perturbation_couplings.lower() in ['all', 'loonly']:
4978 if perturbation_couplings.lower() in ['loonly']:
4979 LoopOption = 'LOonly'
4980 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings'])
4981
4982
4983 if [leg for leg in myleglist if leg.get('state') == True]:
4984
4985
4986 perturbation_couplings_list = perturbation_couplings.split()
4987 if perturbation_couplings_list==['']:
4988 perturbation_couplings_list=[]
4989
4990
4991 split_orders=list(set(perturbation_couplings_list+list(squared_orders.keys())))
4992 try:
4993 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else
4994 self._curr_model.get('order_hierarchy')
4995 [elem if not elem.endswith('.sqrt') else elem[:-5]])
4996 except KeyError:
4997 raise self.InvalidCmd("The loaded model does not defined a "+\
4998 " coupling order hierarchy for these couplings: %s"%\
4999 str([so for so in split_orders if so!='WEIGHTED' and so not
5000 in list(self._curr_model['order_hierarchy'].keys())]))
5001
5002
5003
5004
5005 if LoopOption=='tree':
5006 perturbation_couplings_list = []
5007 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']:
5008 if not isinstance(self._curr_model,loop_base_objects.LoopModel):
5009 raise self.InvalidCmd(\
5010 "The current model does not allow for loop computations.")
5011 else:
5012 for pert_order in perturbation_couplings_list:
5013 if pert_order not in self._curr_model['perturbation_couplings']:
5014 raise self.InvalidCmd(\
5015 "Perturbation order %s is not among" % pert_order + \
5016 " the perturbation orders allowed for by the loop model.")
5017 if not self.options['loop_optimized_output'] and \
5018 LoopOption not in ['tree','real'] and split_orders!=[]:
5019 logger.warning('The default output mode (loop_optimized_output'+\
5020 ' = False) does not support evaluations for given powers of'+\
5021 ' coupling orders. MadLoop output will therefore not be'+\
5022 ' able to provide such quantities.')
5023 split_orders = []
5024
5025
5026 forbidden_particle_ids = \
5027 self.extract_particle_ids(forbidden_particles)
5028 if forbidden_particle_ids and \
5029 isinstance(forbidden_particle_ids[0], list):
5030 raise self.InvalidCmd(\
5031 "Multiparticle %s is or-multiparticle" % part_name + \
5032 " which can be used only for required s-channels")
5033 forbidden_onsh_schannel_ids = \
5034 self.extract_particle_ids(forbidden_onsh_schannels)
5035 forbidden_schannel_ids = \
5036 self.extract_particle_ids(forbidden_schannels)
5037 if forbidden_onsh_schannel_ids and \
5038 isinstance(forbidden_onsh_schannel_ids[0], list):
5039 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \
5040 " which can be used only for required s-channels")
5041 if forbidden_schannel_ids and \
5042 isinstance(forbidden_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 required_schannel_ids = \
5046 self.extract_particle_ids(required_schannels)
5047 if required_schannel_ids and not \
5048 isinstance(required_schannel_ids[0], list):
5049 required_schannel_ids = [required_schannel_ids]
5050
5051 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()])
5052 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1:
5053 raise self.InvalidCmd(
5054 "At most one negative squared order constraint can be specified.")
5055
5056 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()])
5057
5058 out = base_objects.ProcessDefinition({'legs': myleglist,
5059 'model': self._curr_model,
5060 'id': proc_number,
5061 'orders': orders,
5062 'squared_orders':sqorders_values,
5063 'sqorders_types':sqorders_types,
5064 'constrained_orders': constrained_orders,
5065 'forbidden_particles': forbidden_particle_ids,
5066 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids,
5067 'forbidden_s_channels': forbidden_schannel_ids,
5068 'required_s_channels': required_schannel_ids,
5069 'overall_orders': overall_orders,
5070 'perturbation_couplings': perturbation_couplings_list,
5071 'has_born':HasBorn,
5072 'NLO_mode':LoopOption,
5073 'split_orders':split_orders
5074 })
5075 return out
5076
5077
5078
5080 """ Routine to create the MultiProcess for the loop-induced case"""
5081
5082 args = self.split_arg(line)
5083
5084 warning_duplicate = True
5085 if '--no_warning=duplicate' in args:
5086 warning_duplicate = False
5087 args.remove('--no_warning=duplicate')
5088
5089
5090 self.check_add(args)
5091 if args[0] == 'process':
5092 args = args[1:]
5093
5094
5095
5096 if args[-1].startswith('--optimize'):
5097 optimize = True
5098 args.pop()
5099 else:
5100 optimize = False
5101
5102
5103 loop_filter=None
5104 for arg in args:
5105 if arg.startswith('--loop_filter='):
5106 loop_filter = arg[14:]
5107
5108
5109 args = [a for a in args if not a.startswith('--loop_filter=')]
5110
5111 if not myprocdef:
5112 myprocdef = self.extract_process(' '.join(args))
5113
5114 myprocdef.set('NLO_mode', 'noborn')
5115
5116
5117 if not self._generate_info:
5118 self._generate_info = line
5119
5120
5121
5122
5123
5124
5125
5126 if self._curr_amps and self._curr_amps[0].get_ninitial() != \
5127 myprocdef.get_ninitial():
5128 raise self.InvalidCmd("Can not mix processes with different number of initial states.")
5129
5130 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \
5131 self._curr_amps[0]['has_born']):
5132 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process")
5133
5134
5135
5136 if len([1 for val in list(myprocdef.get('orders').values())+\
5137 list(myprocdef.get('squared_orders').values()) if val<0])>1:
5138 raise MadGraph5Error("Negative coupling order constraints"+\
5139 " can only be given on one type of coupling and either on"+\
5140 " squared orders or amplitude orders, not both.")
5141
5142 cpu_time1 = time.time()
5143
5144
5145 if self.options['group_subprocesses'] == 'Auto':
5146 collect_mirror_procs = True
5147 else:
5148 collect_mirror_procs = self.options['group_subprocesses']
5149 ignore_six_quark_processes = \
5150 self.options['ignore_six_quark_processes'] if \
5151 "ignore_six_quark_processes" in self.options \
5152 else []
5153
5154
5155
5156 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef,
5157 collect_mirror_procs = collect_mirror_procs,
5158 ignore_six_quark_processes = ignore_six_quark_processes,
5159 optimize=optimize,
5160 loop_filter=loop_filter)
5161
5162 for amp in myproc.get('amplitudes'):
5163 if amp not in self._curr_amps:
5164 self._curr_amps.append(amp)
5165 if amp['has_born']:
5166 raise Exception
5167 elif warning_duplicate:
5168 raise self.InvalidCmd("Duplicate process %s found. Please check your processes." % \
5169 amp.nice_string_processes())
5170
5171
5172 self._done_export = False
5173 self._curr_proc_defs.append(myprocdef)
5174
5175 cpu_time2 = time.time()
5176
5177 nprocs = len(myproc.get('amplitudes'))
5178 ndiags = sum([amp.get_number_of_diagrams() for \
5179 amp in myproc.get('amplitudes')])
5180 logger.info("%i processes with %i diagrams generated in %0.3f s" % \
5181 (nprocs, ndiags, (cpu_time2 - cpu_time1)))
5182 ndiags = sum([amp.get_number_of_diagrams() for \
5183 amp in self._curr_amps])
5184 logger.info("Total: %i processes with %i diagrams" % \
5185 (len(self._curr_amps), ndiags))
5186
5187 @staticmethod
5189 """Takes a valid process and return
5190 a tuple (core_process, options). This removes
5191 - any NLO specifications.
5192 - any options
5193 [Used by MadSpin]
5194 """
5195
5196
5197
5198 line=procline
5199 pos1=line.find("[")
5200 if pos1>0:
5201 pos2=line.find("]")
5202 if pos2 >pos1:
5203 line=line[:pos1]+line[pos2+1:]
5204
5205
5206
5207
5208 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$")
5209 proc_number_re = proc_number_pattern.match(line)
5210 if proc_number_re:
5211 line = proc_number_re.group(1) + proc_number_re.group(3)
5212
5213
5214 pos=1000
5215
5216 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$")
5217 order_re = order_pattern.match(line)
5218 if (order_re):
5219 pos_order=line.find(order_re.group(2))
5220 if pos_order>0 and pos_order < pos : pos=pos_order
5221
5222
5223 slash = line.find("/")
5224 if slash > 0 and slash < pos: pos=slash
5225 dollar = line.find("$")
5226 if dollar > 0 and dollar < pos: pos=dollar
5227
5228 if pos<1000:
5229 proc_option=line[pos:]
5230 line=line[:pos]
5231 else:
5232 proc_option=""
5233
5234 return line, proc_option
5235
5237 """Takes a valid process and return
5238 a set of id of final states particles. [Used by MadSpin]
5239 """
5240
5241 if not self._curr_model['case_sensitive']:
5242 procline = procline.lower()
5243 pids = self._curr_model.get('name2pdg')
5244
5245
5246
5247
5248
5249
5250
5251 if ',' in procline:
5252 core, decay = procline.split(',', 1)
5253 core_final = self.get_final_part(core)
5254
5255
5256 all_decays = decay.split(',')
5257 nb_level, tmp_decay = 0, ''
5258 decays = []
5259
5260 for one_decay in all_decays:
5261 if '(' in one_decay:
5262 nb_level += 1
5263 if ')' in one_decay:
5264 nb_level -= 1
5265
5266 if nb_level:
5267 if tmp_decay:
5268 tmp_decay += ', %s' % one_decay
5269 else:
5270 tmp_decay = one_decay
5271 elif tmp_decay:
5272 final = '%s,%s' % (tmp_decay, one_decay)
5273 final = final.strip()
5274 assert final[0] == '(' and final[-1] == ')'
5275 final = final[1:-1]
5276 decays.append(final)
5277 tmp_decay = ''
5278 else:
5279 decays.append(one_decay)
5280
5281 for one_decay in decays:
5282 first = one_decay.split('>',1)[0].strip()
5283 if first in pids:
5284 pid = set([pids[first]])
5285 elif first in self._multiparticles:
5286 pid = set(self._multiparticles[first])
5287 else:
5288 raise Exception('invalid particle name: %s. ' % first)
5289 core_final.difference_update(pid)
5290 core_final.update(self.get_final_part(one_decay))
5291
5292 return core_final
5293
5294
5295 final = set()
5296 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline)
5297 particles = final_states.groups()[0]
5298 for particle in particles.split():
5299 if '{' in particle:
5300 particle = particle.split('{')[0]
5301 if particle in pids:
5302 final.add(pids[particle])
5303 elif particle in self._multiparticles:
5304 final.update(set(self._multiparticles[particle]))
5305 elif particle[0].isdigit():
5306 if particle[1:] in pids:
5307 final.add(pids[particle[1:]])
5308 elif particle in self._multiparticles:
5309 final.update(set(self._multiparticles[particle[1:]]))
5310
5311 return final
5312
5313 - def extract_particle_ids(self, args):
5314 """Extract particle ids from a list of particle names. If
5315 there are | in the list, this corresponds to an or-list, which
5316 is represented as a list of id lists. An or-list is used to
5317 allow multiple required s-channel propagators to be specified
5318 (e.g. Z/gamma)."""
5319
5320 if isinstance(args, six.string_types):
5321 args.replace("|", " | ")
5322 args = self.split_arg(args)
5323 all_ids = []
5324 ids=[]
5325 for part_name in args:
5326 mypart = self._curr_model['particles'].get_copy(part_name)
5327 if mypart:
5328 ids.append([mypart.get_pdg_code()])
5329 elif part_name in self._multiparticles:
5330 ids.append(self._multiparticles[part_name])
5331 elif part_name == "|":
5332
5333 if ids:
5334 all_ids.append(ids)
5335 ids = []
5336 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()):
5337 ids.append([int(part_name)])
5338 else:
5339 raise self.InvalidCmd("No particle %s in model" % part_name)
5340 all_ids.append(ids)
5341
5342
5343 res_lists = []
5344 for i, id_list in enumerate(all_ids):
5345 res_lists.extend(diagram_generation.expand_list_list(id_list))
5346
5347 for ilist, idlist in enumerate(res_lists):
5348 set_dict = {}
5349 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \
5350 if i not in set_dict]
5351
5352 if len(res_lists) == 1:
5353 res_lists = res_lists[0]
5354
5355 return res_lists
5356
5358 """Optimize the order of particles in a pdg list, so that
5359 similar particles are next to each other. Sort according to:
5360 1. pdg > 0, 2. spin, 3. color, 4. mass > 0"""
5361
5362 if not pdg_list:
5363 return
5364 if not isinstance(pdg_list[0], int):
5365 return
5366
5367 model = self._curr_model
5368 pdg_list.sort(key = lambda i: i < 0)
5369 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion())
5370 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'),
5371 reverse = True)
5372 pdg_list.sort(key = lambda i: \
5373 model.get_particle(i).get('mass').lower() != 'zero')
5374
5376 """Recursively extract a decay chain process definition from a
5377 string. Returns a ProcessDefinition."""
5378
5379
5380 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*\<?=\s*\d+\s*)*)$")
5381 proc_number_re = proc_number_pattern.match(line)
5382 overall_orders = {}
5383 if proc_number_re:
5384 proc_number = int(proc_number_re.group(2))
5385 line = proc_number_re.group(1)
5386 if proc_number_re.group(3):
5387 order_pattern = re.compile("^(.*?)\s*(\w+)\s*\<?=\s*(\d+)\s*$")
5388 order_line = proc_number_re.group(3)
5389 order_re = order_pattern.match(order_line)
5390 while order_re:
5391 overall_orders[order_re.group(2)] = int(order_re.group(3))
5392 order_line = order_re.group(1)
5393 order_re = order_pattern.match(order_line)
5394 logger.info(line)
5395
5396
5397 index_comma = line.find(",")
5398 index_par = line.find(")")
5399 min_index = index_comma
5400 if index_par > -1 and (index_par < min_index or min_index == -1):
5401 min_index = index_par
5402
5403 if min_index > -1:
5404 core_process = self.extract_process(line[:min_index], proc_number,
5405 overall_orders)
5406 else:
5407 core_process = self.extract_process(line, proc_number,
5408 overall_orders)
5409
5410
5411
5412 while index_comma > -1:
5413 line = line[index_comma + 1:]
5414 if not line.strip():
5415 break
5416 index_par = line.find(')')
5417
5418 if line.lstrip()[0] == '(' and index_par !=-1 and \
5419 not ',' in line[:index_par]:
5420 par_start = line.find('(')
5421 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:])
5422 index_par = line.find(')')
5423 if line.lstrip()[0] == '(':
5424
5425
5426 line = line.lstrip()[1:]
5427
5428 decay_process, line = \
5429 self.extract_decay_chain_process(line,
5430 level_down=True)
5431 index_comma = line.find(",")
5432 index_par = line.find(')')
5433 else:
5434 index_comma = line.find(",")
5435 min_index = index_comma
5436 if index_par > -1 and \
5437 (index_par < min_index or min_index == -1):
5438 min_index = index_par
5439 if min_index > -1:
5440 decay_process = self.extract_process(line[:min_index])
5441 else:
5442 decay_process = self.extract_process(line)
5443
5444 core_process.get('decay_chains').append(decay_process)
5445
5446 if level_down:
5447 if index_par == -1:
5448 raise self.InvalidCmd("Missing ending parenthesis for decay process")
5449
5450 if index_par < index_comma:
5451 line = line[index_par + 1:]
5452 level_down = False
5453 break
5454
5455 if level_down:
5456 index_par = line.find(')')
5457 if index_par == -1:
5458 raise self.InvalidCmd("Missing ending parenthesis for decay process")
5459 line = line[index_par + 1:]
5460
5461
5462
5463 return core_process, line
5464
5465
5466
5468 """Main commands: Import files with external formats"""
5469
5470 args = self.split_arg(line)
5471
5472 self.check_import(args)
5473 if args[0].startswith('model'):
5474 self._model_v4_path = None
5475
5476 self.clean_process()
5477
5478 if args[0].endswith('_v4'):
5479 self._curr_model, self._model_v4_path = \
5480 import_v4.import_model(args[1], self._mgme_dir)
5481 else:
5482
5483 if (args[1].startswith('loop_qcd_qed_sm') or\
5484 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\
5485 self.options['gauge']!='Feynman':
5486 logger.info('Switching to Feynman gauge because '+\
5487 'it is the only one supported by the model %s.'%args[1])
5488 self._curr_model = None
5489 self.do_set('gauge Feynman',log=False)
5490 prefix = not '--noprefix' in args
5491 if prefix:
5492 aloha.aloha_prefix='mdl_'
5493 else:
5494 aloha.aloha_prefix=''
5495
5496 self._curr_model = import_ufo.import_model(args[1], prefix=prefix,
5497 complex_mass_scheme=self.options['complex_mass_scheme'])
5498 if os.path.sep in args[1] and "import" in self.history[-1]:
5499 self.history[-1] = 'import model %s' % self._curr_model.get('modelpath+restriction')
5500
5501 if self.options['gauge'] in ['unitary', 'axial']:
5502 if not force and isinstance(self._curr_model,\
5503 loop_base_objects.LoopModel) and \
5504 self._curr_model.get('perturbation_couplings') not in \
5505 [[],['QCD']]:
5506 if 1 not in self._curr_model.get('gauge') :
5507 logger_stderr.warning('This model does not allow Feynman '+\
5508 'gauge. You will only be able to do tree level '+\
5509 'QCD loop cmputations with it.')
5510 else:
5511 logger.info('Change to the gauge to Feynman because '+\
5512 'this loop model allows for more than just tree level'+\
5513 ' and QCD perturbations.')
5514 self.do_set('gauge Feynman', log=False)
5515 return
5516 if 0 not in self._curr_model.get('gauge') :
5517 logger_stderr.warning('Change the gauge to Feynman since '+\
5518 'the model does not allow unitary gauge')
5519 self.do_set('gauge Feynman', log=False)
5520 return
5521 else:
5522 if 1 not in self._curr_model.get('gauge') :
5523 logger_stderr.warning('Change the gauge to unitary since the'+\
5524 ' model does not allow Feynman gauge.'+\
5525 ' Please re-import the model')
5526 self._curr_model = None
5527 self.do_set('gauge unitary', log= False)
5528 return
5529
5530 if '-modelname' not in args:
5531 self._curr_model.pass_particles_name_in_mg_default()
5532
5533
5534 self.process_model()
5535
5536 self._curr_amps = diagram_generation.AmplitudeList()
5537
5538 self._curr_proc_defs = base_objects.ProcessDefinitionList()
5539 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
5540 process_checks.store_aloha = []
5541
5542 elif args[0] == 'command':
5543
5544 if not os.path.isfile(args[1]):
5545 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1])
5546 else:
5547
5548
5549 self.check_for_export_dir(args[1])
5550
5551 self.import_command_file(args[1])
5552
5553 elif args[0] == 'banner':
5554 type = madevent_interface.MadEventCmd.detect_card_type(args[1])
5555 if type != 'banner':
5556 raise self.InvalidCmd('The File should be a valid banner')
5557 ban = banner_module.Banner(args[1])
5558
5559 if 'mg5proccard' in ban:
5560 for line in ban['mg5proccard'].split('\n'):
5561 if line.startswith('#') or line.startswith('<'):
5562 continue
5563 self.exec_cmd(line)
5564 else:
5565 raise self.InvalidCmd('Only MG5 banner are supported')
5566
5567 if not self._done_export:
5568 self.exec_cmd('output . -f')
5569
5570 ban.split(self._done_export[0])
5571 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards'))
5572 if '--no_launch' not in args:
5573 self.exec_cmd('launch')
5574
5575 elif args[0] == 'proc_v4':
5576
5577 if len(args) == 1 and self._export_dir:
5578 proc_card = pjoin(self._export_dir, 'Cards', \
5579 'proc_card.dat')
5580 elif len(args) == 2:
5581 proc_card = args[1]
5582
5583
5584 self.check_for_export_dir(os.path.realpath(proc_card))
5585 else:
5586 raise MadGraph5Error('No default directory in output')
5587
5588
5589
5590 self.import_mg4_proc_card(proc_card)
5591
5593 """ For simple decay chain: remove diagram that are not in the BR.
5594 param_card should be a ParamCard instance."""
5595
5596 assert isinstance(param_card, check_param_card.ParamCard)
5597
5598
5599 amplitudes = diagram_generation.AmplitudeList()
5600 for amp in self._curr_amps:
5601 amplitudes.extend(amp.get_amplitudes())
5602
5603 decay_tables = param_card['decay'].decay_table
5604 to_remove = []
5605 for amp in amplitudes:
5606 mother = [l.get('id') for l in amp['process'].get('legs') \
5607 if not l.get('state')]
5608 if 1 == len(mother):
5609 try:
5610 decay_table = decay_tables[abs(mother[0])]
5611 except KeyError:
5612 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0]))
5613 continue
5614
5615 child = [l.get('id') for l in amp['process'].get('legs') \
5616 if l.get('state')]
5617 if not mother[0] > 0:
5618 child = [x if self._curr_model.get_particle(x)['self_antipart']
5619 else -x for x in child]
5620 child.sort()
5621 child.insert(0, len(child))
5622
5623 if tuple(child) not in list(decay_table.keys()):
5624 to_remove.append(amp)
5625
5626 def remove_amp(amps):
5627 for amp in amps[:]:
5628 if amp in to_remove:
5629 amps.remove(amp)
5630 if isinstance(amp, diagram_generation.DecayChainAmplitude):
5631 remove_amp(amp.get('decay_chains'))
5632 for decay in amp.get('decay_chains'):
5633 remove_amp(decay.get('amplitudes'))
5634 remove_amp(self._curr_amps)
5635
5636
5641
5643 """Set variables _particle_names and _couplings for tab
5644 completion, define multiparticles"""
5645
5646
5647 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\
5648 if p.get('propagating')] + \
5649 [p.get('antiname') for p in self._curr_model.get('particles') \
5650 if p.get('propagating')]
5651
5652 self._couplings = list(set(sum([list(i.get('orders').keys()) for i in \
5653 self._curr_model.get('interactions')], [])))
5654
5655 self.add_default_multiparticles()
5656
5657
5686
5688 """ add default particle from file interface.multiparticles_default.txt
5689 """
5690
5691 defined_multiparticles = list(self._multiparticles.keys())
5692 removed_multiparticles = []
5693
5694
5695
5696 for key in list(self._multiparticles.keys()):
5697 try:
5698 for part in self._multiparticles[key]:
5699 self._curr_model.get('particle_dict')[part]
5700 except Exception:
5701 del self._multiparticles[key]
5702 defined_multiparticles.remove(key)
5703 removed_multiparticles.append(key)
5704
5705
5706 for line in open(pjoin(MG5DIR, 'input', \
5707 'multiparticles_default.txt')):
5708 if line.startswith('#'):
5709 continue
5710 try:
5711 if not self._curr_model['case_sensitive']:
5712 multipart_name = line.lower().split()[0]
5713 else:
5714 multipart_name = line.split()[0]
5715 if multipart_name not in self._multiparticles:
5716
5717 self.exec_cmd('define %s' % line, printcmd=False, precmd=True)
5718 except self.InvalidCmd as why:
5719 logger.warning('impossible to set default multiparticles %s because %s' %
5720 (line.split()[0],why))
5721 if self.history[-1] == 'define %s' % line.strip():
5722 self.history.pop(-1)
5723 else:
5724 misc.sprint([self.history[-1], 'define %s' % line.strip()])
5725
5726 scheme = "old"
5727 for qcd_container in ['p', 'j']:
5728 if qcd_container not in self._multiparticles:
5729 continue
5730 multi = self._multiparticles[qcd_container]
5731 b = self._curr_model.get_particle(5)
5732 if not b:
5733 break
5734
5735 if 5 in multi:
5736 if b['mass'] != 'ZERO':
5737 multi.remove(5)
5738 multi.remove(-5)
5739 scheme = 4
5740 elif b['mass'] == 'ZERO':
5741 multi.append(5)
5742 multi.append(-5)
5743 scheme = 5
5744
5745 if scheme in [4,5]:
5746 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme)
5747 for container in ['p', 'j']:
5748 if container in defined_multiparticles:
5749 defined_multiparticles.remove(container)
5750 self.history.append("define p = %s # pass to %s flavors" % \
5751 (' ' .join([repr(i) for i in self._multiparticles['p']]),
5752 scheme)
5753 )
5754 self.history.append("define j = p")
5755
5756
5757 if defined_multiparticles:
5758 if 'all' in defined_multiparticles:
5759 defined_multiparticles.remove('all')
5760 logger.info("Kept definitions of multiparticles %s unchanged" % \
5761 " / ".join(defined_multiparticles))
5762
5763 for removed_part in removed_multiparticles:
5764 if removed_part in self._multiparticles:
5765 removed_multiparticles.remove(removed_part)
5766
5767 if removed_multiparticles:
5768 logger.info("Removed obsolete multiparticles %s" % \
5769 " / ".join(removed_multiparticles))
5770
5771
5772 line = []
5773 for part in self._curr_model.get('particles'):
5774 line.append('%s %s' % (part.get('name'), part.get('antiname')))
5775 line = 'all =' + ' '.join(line)
5776 self.do_define(line)
5777
5778 - def advanced_install(self, tool_to_install,
5779 HepToolsInstaller_web_address=None,
5780 additional_options=[]):
5781 """ Uses the HEPToolsInstaller.py script maintened online to install
5782 HEP tools with more complicated dependences.
5783 Additional options will be added to the list when calling HEPInstaller"""
5784
5785
5786 add_options = list(additional_options)
5787
5788
5789 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')):
5790 if HepToolsInstaller_web_address is None:
5791 raise MadGraph5Error("The option 'HepToolsInstaller_web_address'"+\
5792 " must be specified in function advanced_install"+\
5793 " if the installers are not already downloaded.")
5794 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')):
5795 os.mkdir(pjoin(MG5DIR,'HEPTools'))
5796 elif not HepToolsInstaller_web_address is None:
5797 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers'))
5798 if not HepToolsInstaller_web_address is None:
5799 logger.info('Downloading the HEPToolInstaller at:\n %s'%
5800 HepToolsInstaller_web_address)
5801
5802 if '//' in HepToolsInstaller_web_address:
5803 misc.wget(HepToolsInstaller_web_address,
5804 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'),
5805 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'),
5806 cwd=MG5DIR)
5807 else:
5808
5809 shutil.copyfile(HepToolsInstaller_web_address,
5810 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'))
5811
5812
5813 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'],
5814 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w'))
5815
5816
5817 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'))
5818
5819
5820
5821 if '--local' in add_options:
5822 add_options.remove('--local')
5823 logger.warning('you are using a local installer. This is intended for debugging only!')
5824 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers'))
5825 shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir,
5826 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers'))
5827
5828
5829 name_map = {'lhapdf6_py3': 'lhapdf6'}
5830 try:
5831 tool = name_map[tool_to_install]
5832 except:
5833 tool = tool_to_install
5834
5835
5836 compiler_options = []
5837 if self.options['cpp_compiler'] is not None:
5838 compiler_options.append('--cpp_compiler=%s'%
5839 self.options['cpp_compiler'])
5840 compiler_options.append('--cpp_standard_lib=%s'%
5841 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler']))
5842 elif misc.which('g++'):
5843 compiler_options.append('--cpp_standard_lib=%s'%
5844 misc.detect_cpp_std_lib_dependence('g++'))
5845 else:
5846 compiler_options.append('--cpp_standard_lib=%s'%
5847 misc.detect_cpp_std_lib_dependence(None))
5848
5849 if not self.options['fortran_compiler'] is None:
5850 compiler_options.append('--fortran_compiler=%s'%
5851 self.options['fortran_compiler'])
5852
5853 if 'heptools_install_dir' in self.options:
5854 prefix = self.options['heptools_install_dir']
5855 config_file = '~/.mg5/mg5_configuration.txt'
5856 else:
5857 prefix = pjoin(MG5DIR, 'HEPTools')
5858 config_file = ''
5859
5860
5861 if tool=='mg5amc_py8_interface':
5862
5863
5864 if misc.which('gnuplot') is None:
5865 logger.warning("==========")
5866 logger.warning("The optional dependency 'gnuplot' for the tool"+\
5867 " 'mg5amc_py8_interface' was not found. We recommend that you"+\
5868 " install it so as to be able to view the plots related to "+\
5869 " merging with Pythia 8.")
5870 logger.warning("==========")
5871 if self.options['pythia8_path']:
5872 add_options.append(
5873 '--with_pythia8=%s'%self.options['pythia8_path'])
5874
5875
5876 if tool=='madanalysis5':
5877 add_options.append('--mg5_path=%s'%MG5DIR)
5878 if not any(opt.startswith(('--with_fastjet', '--veto_fastjet')) for opt in add_options):
5879 fastjet_config = misc.which(self.options['fastjet'])
5880 if fastjet_config:
5881 add_options.append('--with_fastjet=%s'%fastjet_config)
5882
5883 if self.options['delphes_path'] and os.path.isdir(
5884 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))):
5885 add_options.append('--with_delphes3=%s'%\
5886 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path'])))
5887
5888 if tool=='pythia8':
5889
5890 lhapdf_config = misc.which(self.options['lhapdf'])
5891 lhapdf_version = None
5892 if lhapdf_config is None:
5893 lhapdf_version = None
5894 else:
5895 try:
5896 version = misc.Popen(
5897 [lhapdf_config,'--version'], stdout=subprocess.PIPE)
5898 lhapdf_version = int(version.stdout.read().decode()[0])
5899 if lhapdf_version not in [5,6]:
5900 raise
5901 except:
5902 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+
5903 " sure '%s --version ' runs properly."%lhapdf_config)
5904
5905 if lhapdf_version is None:
5906 answer = self.ask(question=
5907 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+
5908 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >",
5909 default='y',text_format='33;32')
5910 if not answer.lower() in ['y','']:
5911 lhapdf_path = None
5912 else:
5913 self.advanced_install('lhapdf6',
5914 additional_options=add_options)
5915 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6')
5916 lhapdf_version = 6
5917 else:
5918 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\
5919 lhapdf_config),os.path.pardir))
5920 if lhapdf_version is None:
5921 logger.warning('You decided not to link the Pythia8 installation'+
5922 ' to LHAPDF. Beware that only built-in PDF sets can be used then.')
5923 else:
5924 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version)
5925 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN')
5926 lhapdf_option = []
5927 if lhapdf_version is None:
5928 lhapdf_option.append('--with_lhapdf6=OFF')
5929 lhapdf_option.append('--with_lhapdf5=OFF')
5930 elif lhapdf_version==5:
5931 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path)
5932 lhapdf_option.append('--with_lhapdf6=OFF')
5933 elif lhapdf_version==6:
5934 lhapdf_option.append('--with_lhapdf5=OFF')
5935 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path)
5936
5937 add_options = list(set(add_options))
5938
5939 add_options = [opt for opt in add_options if opt!='--force']+\
5940 (['--force'] if '--force' in add_options else [])
5941 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools',
5942 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8',
5943 '--prefix=%s' % prefix]
5944 + lhapdf_option + compiler_options + add_options)
5945 else:
5946 logger.info('Now installing %s. Be patient...'%tool)
5947
5948 add_options.append('--mg5_path=%s'%MG5DIR)
5949 add_options = list(set(add_options))
5950 add_options.append('--mg5_path=%s'%MG5DIR)
5951
5952 add_options = [opt for opt in add_options if opt!='--force']+\
5953 (['--force'] if '--force' in add_options else [])
5954 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools',
5955 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'%
5956 prefix] + compiler_options + add_options)
5957
5958 if return_code == 0:
5959 logger.info("%s successfully installed in %s."%(
5960 tool_to_install, prefix),'$MG:color:GREEN')
5961
5962 if tool=='madanalysis5':
5963 if not any(o.startswith(('--with_','--veto_','--update')) for o in add_options):
5964 logger.info(' To install recasting capabilities of madanalysis5 and/or', '$MG:BOLD')
5965 logger.info(' to allow delphes analysis at parton level.','$MG:BOLD')
5966 logger.info(' Please run \'install MadAnalysis5 --with_delphes --update\':', '$MG:BOLD')
5967
5968 elif return_code == 66:
5969 answer = self.ask(question=
5970 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, prefix)+
5971 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >"""
5972 ,default='y',text_format='33;32')
5973 if not answer.lower() in ['y','']:
5974 logger.info("Installation of %s aborted."%tool_to_install,
5975 '$MG:color:GREEN')
5976 return
5977 else:
5978 return self.advanced_install(tool_to_install,
5979 additional_options=add_options+['--force'])
5980 else:
5981 if tool=='madanalysis5' and '--update' not in add_options and \
5982 ('--no_MA5_further_install' not in add_options or
5983 '--no_root_in_MA5' in add_options):
5984 if not __debug__:
5985 logger.warning('Default installation of Madanalys5 failed.')
5986 logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.")
5987 logger.warning("This will however limit MA5 applicability for hadron-level analysis.")
5988 logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.")
5989 for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']:
5990 if option not in add_options:
5991 add_options.append(option)
5992 self.advanced_install('madanalysis5',
5993 HepToolsInstaller_web_address=HepToolsInstaller_web_address,
5994 additional_options=add_options)
5995 else:
5996 logger.critical("Default installation of Madanalys5 failed, we suggest you try again with the options '--no_MA5_further_install --no_root_in_MA5'.")
5997 raise self.InvalidCmd("Installation of %s failed."%tool_to_install)
5998
5999
6000 if tool == 'pythia8':
6001 self.options['pythia8_path'] = pjoin(prefix,'pythia8')
6002 self.exec_cmd('save options %s pythia8_path' % config_file, printcmd=False, log=False)
6003
6004
6005 self.advanced_install('mg5amc_py8_interface',
6006 additional_options=add_options+['--force'])
6007 elif tool == 'lhapdf6':
6008 if six.PY3:
6009 self.options['lhapdf_py3'] = pjoin(prefix,'lhapdf6_py3','bin', 'lhapdf-config')
6010 self.exec_cmd('save options %s lhapdf_py3' % config_file)
6011 self.options['lhapdf'] = self.options['lhapdf_py3']
6012 else:
6013 self.options['lhapdf_py2'] = pjoin(prefix,'lhapdf6','bin', 'lhapdf-config')
6014 self.exec_cmd('save options %s lhapdf_py2' % config_file)
6015 self.options['lhapdf'] = self.options['lhapdf_py2']
6016
6017 elif tool == 'lhapdf5':
6018 self.options['lhapdf'] = pjoin(prefix,'lhapdf5','bin', 'lhapdf-config')
6019 self.exec_cmd('save options %s lhapdf' % config_file, printcmd=False, log=False)
6020 elif tool == 'madanalysis5':
6021 self.options['madanalysis5_path'] = pjoin(prefix, 'madanalysis5','madanalysis5')
6022 self.exec_cmd('save options madanalysis5_path', printcmd=False, log=False)
6023 elif tool == 'mg5amc_py8_interface':
6024
6025 if self.options['pythia8_path'] in ['',None,'None']:
6026 self.options['pythia8_path'] = pjoin(prefix,'pythia8')
6027 self.options['mg5amc_py8_interface_path'] = pjoin(prefix, 'MG5aMC_PY8_interface')
6028 self.exec_cmd('save options %s mg5amc_py8_interface_path' % config_file,
6029 printcmd=False, log=False)
6030 elif tool == 'collier':
6031 self.options['collier'] = pjoin(prefix,'lib')
6032 self.exec_cmd('save options %s collier' % config_file, printcmd=False, log=False)
6033 elif tool == 'ninja':
6034 if not misc.get_ninja_quad_prec_support(pjoin(
6035 prefix,'ninja','lib')):
6036 logger.warning(
6037 """Successful installation of Ninja, but without support for quadruple precision
6038 arithmetics. If you want to enable this (hence improving the treatment of numerically
6039 unstable points in the loop matrix elements) you can try to reinstall Ninja with:
6040 MG5aMC>install ninja
6041 After having made sure to have selected a C++ compiler in the 'cpp' option of
6042 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""")
6043 self.options['ninja'] = pjoin(prefix,'lib')
6044 self.exec_cmd('save options %s ninja' % config_file, printcmd=False, log=False)
6045 elif '%s_path' % tool in self.options:
6046 self.options['%s_path' % tool] = pjoin(prefix, tool)
6047 self.exec_cmd('save options %s %s_path' % (config_file,tool), printcmd=False, log=False)
6048
6049
6050
6051 path_to_be_set = []
6052 if sys.platform == "darwin":
6053 library_variables = ["DYLD_LIBRARY_PATH"]
6054 else:
6055 library_variables = ["LD_LIBRARY_PATH"]
6056 for variable in library_variables:
6057 if (variable not in os.environ) or \
6058 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\
6059 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)):
6060 path_to_be_set.append((variable,
6061 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))))
6062 for variable in ["PATH"]:
6063 if (variable not in os.environ) or \
6064 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\
6065 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)):
6066 path_to_be_set.append((variable,
6067 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))))
6068 if (variable not in os.environ) or \
6069 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\
6070 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)):
6071 path_to_be_set.append((variable,
6072 os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))))
6073
6074 if len(path_to_be_set)>0:
6075 shell_type = misc.get_shell_type()
6076 if shell_type in ['bash',None]:
6077 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.bashrc"%\
6078 (r'\n'.join('export %s=%s%s'%
6079 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set))
6080 elif shell_type=='tcsh':
6081 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.cshrc"%\
6082 (r'\n'.join('setenv %s %s%s'%
6083 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set))
6084
6085 logger.debug("==========")
6086 logger.debug("We recommend that you add to the following paths"+\
6087 " to your environment variables, so that you are guaranteed that"+\
6088 " at runtime, MG5_aMC will use the tools you have just installed"+\
6089 " and not some other versions installed elsewhere on your system.\n"+\
6090 "You can do so by running the following command in your terminal:"
6091 "\n %s"%modification_line)
6092 logger.debug("==========")
6093
6094
6095 return True
6096
6097 install_plugin = ['maddm', 'maddump', 'MadSTR']
6098 install_ad = {'pythia-pgs':['arXiv:0603175'],
6099 'Delphes':['arXiv:1307.6346'],
6100 'Delphes2':['arXiv:0903.2225'],
6101 'SysCalc':['arXiv:1801.08401'],
6102 'Golem95':['arXiv:0807.0605'],
6103 'QCDLoop':['arXiv:0712.1851'],
6104 'pythia8':['arXiv:1410.3012'],
6105 'lhapdf6':['arXiv:1412.7420'],
6106 'lhapdf5':['arXiv:0605240'],
6107 'hepmc':['CPC 134 (2001) 41-46'],
6108 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'],
6109 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'],
6110 'MadAnalysis5':['arXiv:1206.1599'],
6111 'MadAnalysis':['arXiv:1206.1599'],
6112 'collier':['arXiv:1604.06792'],
6113 'oneloop':['arXiv:1007.4716'],
6114 'maddm':['arXiv:1804.00444'],
6115 'maddump':['arXiv:1812.06771'],
6116 'MadSTR':['arXiv:1612.00440']}
6117
6118 install_server = ['http://madgraph.phys.ucl.ac.be/package_info.dat',
6119 'http://madgraph.physics.illinois.edu/package_info.dat']
6120 install_name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes',
6121 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs',
6122 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'madanalysis5',
6123 'MadAnalysis4':'MadAnalysis',
6124 'SysCalc':'SysCalc', 'Golem95': 'golem95',
6125 'lhapdf6' : 'lhapdf6' if six.PY2 else 'lhapdf6_py3',
6126 'QCDLoop':'QCDLoop','MadAnalysis5':'madanalysis5',
6127 'maddm':'maddm'
6128 }
6129
6130 - def do_install(self, line, paths=None, additional_options=[]):
6131 """Install optional package from the MG suite.
6132 The argument 'additional_options' will be passed to the advanced_install
6133 functions. If it contains the option '--force', then the advanced_install
6134 function will overwrite any existing installation of the tool without
6135 warnings.
6136 """
6137
6138
6139 add_options = list(additional_options)
6140
6141 args = self.split_arg(line)
6142
6143 install_options = self.check_install(args)
6144
6145 if sys.platform == "darwin":
6146 program = "curl"
6147 else:
6148 program = "wget"
6149
6150
6151 if args[0] == 'update':
6152 self.install_update(['update']+install_options['update_options'],wget=program)
6153 return
6154 elif args[0] == 'looptools':
6155 self.install_reduction_library(force=True)
6156 return
6157
6158
6159 plugin = self.install_plugin
6160
6161 advertisements = self.install_ad
6162
6163
6164 if args[0] in advertisements:
6165
6166
6167
6168
6169
6170 logger.info(" You are installing '%s', please cite ref(s): \033[92m%s\033[0m. " % (args[0], ', '.join(advertisements[args[0]])), '$MG:BOLD')
6171
6172 source = None
6173
6174 import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
6175 if paths:
6176 path = paths
6177 else:
6178 path = {}
6179
6180 data_path = self.install_server
6181
6182
6183 if any(a.startswith('--source=') for a in args):
6184 source = [a[9:] for a in args if a.startswith('--source=')][-1]
6185 if source == 'uiuc':
6186 r = [1]
6187 elif source == 'ucl':
6188 r = [0]
6189 else:
6190 if source[-1].isdigit() or source[-1] == '/':
6191 source += '/package_info.dat'
6192 data_path.append(source)
6193 r = [2]
6194 else:
6195 r = random.randint(0,1)
6196 r = [r, (1-r)]
6197 if 'MG5aMC_WWW' in os.environ and os.environ['MG5aMC_WWW']:
6198 data_path.append(os.environ['MG5aMC_WWW']+'/package_info.dat')
6199 r.insert(0, 2)
6200
6201
6202
6203 for index in r:
6204 cluster_path = data_path[index]
6205 try:
6206 data = six.moves.urllib.request.urlopen(cluster_path)
6207 except Exception as error:
6208 misc.sprint(str(error), cluster_path)
6209 continue
6210 if data.getcode() != 200:
6211 continue
6212
6213 break
6214
6215 else:
6216 raise MadGraph5Error('''Impossible to connect any of us servers.
6217 Please check your internet connection or retry later''')
6218 for wwwline in data:
6219 split = wwwline.decode().split()
6220 if len(split)!=2:
6221 if '--source' not in line:
6222 source = {0:'uiuc',1:'ucl'}[index]
6223 return self.do_install(line+' --source='+source, paths=paths, additional_options=additional_options)
6224 path[split[0]] = split[1]
6225
6226
6227
6228
6229
6230
6231
6232 if args[0] == 'Delphes':
6233 args[0] = 'Delphes3'
6234
6235
6236 try:
6237 name = self.install_name
6238 name = name[args[0]]
6239 except KeyError:
6240 name = args[0]
6241 if args[0] == 'MadAnalysis4':
6242 args[0] = 'MadAnalysis'
6243 elif args[0] in ['madstr', 'madSTR']:
6244 args[0] = 'MadSTR'
6245 name = 'MadSTR'
6246
6247 if args[0] in self._advanced_install_opts:
6248
6249
6250
6251
6252 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \
6253 'MG5aMC_PY8_interface' in path else 'NA'
6254 add_options.append('--mg5amc_py8_interface_tarball=%s'%\
6255 MG5aMC_PY8_interface_path)
6256 add_options.extend(install_options['options_for_HEPToolsInstaller'])
6257 if not any(opt.startswith('--logging=') for opt in add_options):
6258 add_options.append('--logging=%d' % logger.level)
6259
6260
6261 return self.advanced_install(name, path['HEPToolsInstaller'],
6262 additional_options = add_options)
6263
6264
6265 if args[0] == 'Delphes':
6266 args[0] = 'Delphes3'
6267
6268
6269
6270 substitution={'Delphes2':'Delphes','pythia-pgs':'pythia8'}
6271 if args[0] in substitution:
6272 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\
6273 " You should consider installing and using %s, with:\n"%substitution[args[0]]+
6274 " > install %s"%substitution[args[0]])
6275
6276 try:
6277 os.system('rm -rf %s' % pjoin(MG5DIR, name))
6278 except Exception:
6279 pass
6280
6281 if args[0] not in path:
6282 if not source:
6283 if index ==1:
6284 othersource = 'ucl'
6285 else:
6286 othersource = 'uiuc'
6287
6288 misc.sprint('try other mirror', othersource, ' '.join(args))
6289 return self.do_install('%s --source=%s' % (' '.join(args), othersource),
6290 paths, additional_options)
6291 else:
6292 if 'xxx' in advertisements[name][0]:
6293 logger.warning("Program not yet released. Please try later")
6294 else:
6295 raise Exception("Online server are corrupted. No tarball available for %s" % name)
6296 return
6297
6298
6299 logger.info('Downloading %s' % path[args[0]])
6300 misc.wget(path[args[0]], '%s.tgz' % name, cwd=MG5DIR)
6301
6302
6303 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR,
6304 stdout=open(os.devnull, 'w'))
6305
6306 if returncode:
6307 raise MadGraph5Error('Fail to download correctly the File. Stop')
6308
6309
6310
6311 if not os.path.exists(pjoin(MG5DIR, name)):
6312 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith(
6313 name.lower()) and not n.endswith('gz')]
6314 if not created_name:
6315 raise MadGraph5Error('The file was not loaded correctly. Stop')
6316 else:
6317 created_name = created_name[0]
6318 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name))
6319
6320 if hasattr(self, 'post_install_%s' %name):
6321 return getattr(self, 'post_install_%s' %name)()
6322
6323 logger.info('compile %s. This might take a while.' % name)
6324
6325
6326 if args[0] == "pythia-pgs" and sys.maxsize > 2**32:
6327 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts')
6328 text = open(path).read()
6329 text = text.replace('MBITS=32','MBITS=64')
6330 open(path, 'w').writelines(text)
6331 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')):
6332 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib'))
6333
6334 make_flags = []
6335
6336
6337 if 'FC' not in os.environ or not os.environ['FC']:
6338 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None':
6339 compiler = self.options['fortran_compiler']
6340 elif misc.which('gfortran'):
6341 compiler = 'gfortran'
6342 elif misc.which('g77'):
6343 compiler = 'g77'
6344 else:
6345 raise self.InvalidCmd('Require g77 or Gfortran compiler')
6346
6347 path = None
6348 base_compiler= ['FC=g77','FC=gfortran']
6349 if args[0] == "pythia-pgs":
6350 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts')
6351 elif args[0] == 'MadAnalysis':
6352 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile')
6353 if path:
6354 text = open(path).read()
6355 for base in base_compiler:
6356 text = text.replace(base,'FC=%s' % compiler)
6357 open(path, 'w').writelines(text)
6358 os.environ['FC'] = compiler
6359
6360
6361 if name == 'golem95':
6362
6363 ld_path = misc.Popen(['./configure',
6364 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']],
6365 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0].decode()
6366
6367
6368
6369 if name == 'QCDLoop':
6370
6371 ld_path = misc.Popen(['./configure',
6372 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'],
6373 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name),
6374 stdout=subprocess.PIPE).communicate()[0].decode()
6375
6376
6377 if args[0] == 'Delphes3':
6378
6379
6380
6381
6382 rootsys = os.environ['ROOTSYS']
6383 text = open(pjoin(MG5DIR, 'Delphes','Makefile')).read()
6384 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)',
6385 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys)
6386 open(pjoin(MG5DIR, 'Delphes','Makefile'),'w').write(text)
6387
6388
6389 if name == 'SysCalc':
6390 if self.options['lhapdf']:
6391 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'],
6392 stdout=subprocess.PIPE).communicate()[0].decode()
6393 ld_path = ld_path.replace('\n','')
6394 if 'LD_LIBRARY_PATH' not in os.environ:
6395 os.environ['LD_LIBRARY_PATH'] = ld_path
6396 elif not os.environ['LD_LIBRARY_PATH']:
6397 os.environ['LD_LIBRARY_PATH'] = ld_path
6398 elif ld_path not in os.environ['LD_LIBRARY_PATH']:
6399 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path
6400 if self.options['lhapdf'] != 'lhapdf-config':
6401 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']):
6402 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH'])
6403 else:
6404 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6')
6405 if self.options['cpp_compiler']:
6406 make_flags.append('CXX=%s' % self.options['cpp_compiler'])
6407
6408
6409 if name in plugin:
6410 logger.info('no compilation needed for plugin. Loading plugin information')
6411 try:
6412 shutil.rmtree(pjoin(MG5DIR, 'PLUGIN', name))
6413 except Exception:
6414 pass
6415 shutil.move(pjoin(os.path.join(MG5DIR, name)), os.path.join(MG5DIR, 'PLUGIN', name))
6416
6417 pyvers=sys.version[0]
6418 try:
6419 __import__('PLUGIN.%s' % name, globals(), locals(), [], -1)
6420 plugin = sys.modules['PLUGIN.%s' % name]
6421 new_interface = plugin.new_interface
6422 new_output = plugin.new_output
6423 latest_validated_version = plugin.latest_validated_version
6424 minimal_mg5amcnlo_version = plugin.minimal_mg5amcnlo_version
6425 maximal_mg5amcnlo_version = plugin.maximal_mg5amcnlo_version
6426 except Exception as error:
6427 if six.PY2:
6428 raise Exception('Plugin %s fail to be loaded. Please contact the author of the PLUGIN\n Error %s' % (name, error))
6429 elif six.PY3:
6430 logger.warning('Plugin not python3 compatible! It will run with python2')
6431 text = open(os.path.join(MG5DIR, 'PLUGIN', name, '__init__.py')).read()
6432 if re.search('^\s*new_interface\s*=\s*(?!None).', text, re.M):
6433 new_interface = True
6434 pyvers = 2
6435 else:
6436 misc.sprint(text)
6437 new_output = []
6438 latest_validated_version = ''
6439 minimal_mg5amcnlo_version = ''
6440 maximal_mg5amcnlo_version = ''
6441 misc.sprint(pyvers)
6442
6443 logger.info('Plugin %s correctly interfaced. Latest official validition for MG5aMC version %s.' % (name, '.'.join(repr(i) for i in latest_validated_version)))
6444 if new_interface:
6445 ff = open(pjoin(MG5DIR, 'bin', '%s.py' % name) , 'w')
6446 if __debug__:
6447 text = '''#! /usr/bin/env python{1}
6448 import os
6449 import sys
6450 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
6451 exe_path = os.path.join(root_path,'bin','mg5_aMC')
6452 sys.argv.pop(0)
6453 os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) ))
6454 '''.format(name,'' if pyvers == 2 else pyvers)
6455 else:
6456 text = '''#! /usr/bin/env python{1}
6457 import os
6458 import sys
6459 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
6460 exe_path = os.path.join(root_path,'bin','mg5_aMC')
6461 sys.argv.pop(0)
6462 os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) ))
6463 '''.format(name,'' if pyvers == 2 else pyvers)
6464 ff.write(text)
6465 ff.close()
6466 import stat
6467 os.chmod(pjoin(MG5DIR, 'bin', '%s.py' % name), stat.S_IRWXU)
6468 logger.info('To use this module, you need to quit MG5aMC and run the executable bin/%s.py' % name)
6469 status=0
6470
6471 elif logger.level <= logging.INFO:
6472 devnull = open(os.devnull,'w')
6473 try:
6474 misc.call(['make', 'clean'], stdout=devnull, stderr=-2)
6475 except Exception:
6476 pass
6477 if name == 'pythia-pgs':
6478
6479 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib'))
6480 if name in ['golem95','QCDLoop']:
6481 status = misc.call(['make','install'],
6482 cwd = os.path.join(MG5DIR, name))
6483 else:
6484 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name))
6485 devnull.close()
6486 else:
6487 try:
6488 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name))
6489 except Exception:
6490 pass
6491 if name == 'pythia-pgs':
6492
6493 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib'))
6494 if name in ['golem95','QCDLoop']:
6495 status = misc.compile(['install'], mode='',
6496 cwd = os.path.join(MG5DIR, name))
6497 else:
6498 status = self.compile(make_flags, mode='',
6499 cwd = os.path.join(MG5DIR, name))
6500
6501 if not status:
6502 logger.info('Installation succeeded')
6503 else:
6504
6505 if name == 'pythia-pgs':
6506 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio',
6507 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch']
6508 for f in to_comment:
6509 f = pjoin(MG5DIR, name, *f.split('/'))
6510 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l)
6511 fsock = open(f,'w').write(text)
6512 try:
6513 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name))
6514 except Exception:
6515 pass
6516 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name))
6517 if not status:
6518 logger.info('Compilation succeeded')
6519 else:
6520 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.')
6521
6522
6523
6524 if args[0] == 'MadAnalysis':
6525 try:
6526 os.system('rm -rf td')
6527 os.mkdir(pjoin(MG5DIR, 'td'))
6528 except Exception as error:
6529 print(error)
6530 pass
6531
6532 if sys.platform == "darwin":
6533 logger.info('Downloading TD for Mac')
6534 target = 'https://home.fnal.gov/~parke/TD/td_mac_intel64.tar.gz'
6535 misc.wget(target, 'td.tgz', cwd=pjoin(MG5DIR,'td'))
6536 misc.call(['tar', '-xzpvf', 'td.tgz'],
6537 cwd=pjoin(MG5DIR,'td'))
6538 files.mv(MG5DIR + '/td/td_intel_mac64',MG5DIR+'/td/td')
6539 else:
6540 if sys.maxsize > 2**32:
6541 logger.info('Downloading TD for Linux 64 bit')
6542 target = 'https://home.fnal.gov/~parke/TD/td_linux_64bit.tar.gz'
6543
6544
6545
6546 else:
6547 logger.info('Downloading TD for Linux 32 bit')
6548 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td'
6549 misc.wget(target, 'td', cwd=pjoin(MG5DIR,'td'))
6550 os.chmod(pjoin(MG5DIR,'td','td'), 0o775)
6551 self.options['td_path'] = pjoin(MG5DIR,'td')
6552
6553 if not misc.which('gs'):
6554 logger.warning('''gosthscript not install on your system. This is not required to run MA.
6555 but this prevent to create jpg files and therefore to have the plots in the html output.''')
6556 if sys.platform == "darwin":
6557 logger.warning('''You can download this program at the following link:
6558 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''')
6559
6560 if args[0] == 'Delphes2':
6561 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read()
6562 data = data.replace('data/', 'DELPHESDIR/data/')
6563 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w')
6564 out.write(data)
6565 if args[0] == 'Delphes3':
6566 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')):
6567 card_dir = pjoin(MG5DIR, 'Delphes','cards')
6568 else:
6569 card_dir = pjoin(MG5DIR, 'Delphes','examples')
6570 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'),
6571 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat'))
6572 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'),
6573 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat'))
6574 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'),
6575 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat'))
6576
6577 if not self.options['pythia-pgs_path'] and not self.options['pythia8_path']:
6578 logger.warning("We noticed that no parton-shower module are installed/linked. \n In order to use Delphes from MG5aMC please install/link pythia8.")
6579
6580
6581 options_name = {'Delphes': 'delphes_path',
6582 'Delphes2': 'delphes_path',
6583 'Delphes3': 'delphes_path',
6584 'ExRootAnalysis': 'exrootanalysis_path',
6585 'MadAnalysis': 'madanalysis_path',
6586 'SysCalc': 'syscalc_path',
6587 'pythia-pgs':'pythia-pgs_path',
6588 'Golem95': 'golem'}
6589
6590 if args[0] in options_name:
6591 opt = options_name[args[0]]
6592 if opt=='golem':
6593 self.options[opt] = pjoin(MG5DIR,name,'lib')
6594 self.exec_cmd('save options %s' % opt, printcmd=False)
6595 elif self.options[opt] != self.options_configuration[opt]:
6596 self.options[opt] = self.options_configuration[opt]
6597 self.exec_cmd('save options %s' % opt, printcmd=False)
6598
6599
6600
6602 """ check if the current version of mg5 is up-to-date.
6603 and allow user to install the latest version of MG5 """
6604
6605 def apply_patch(filetext):
6606 """function to apply the patch"""
6607 text = filetext.read().decode()
6608
6609 pattern = re.compile(r'''=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''')
6610
6611 for orig, new in pattern.findall(text):
6612 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP'))
6613 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/')
6614 for i, name in enumerate(full_path):
6615 path = os.path.sep.join(full_path[:i+1])
6616 if path and not os.path.isdir(path):
6617 os.mkdir(path)
6618 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new))
6619 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP'))
6620
6621 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''')
6622
6623 for orig, new in pattern.findall(text):
6624 print('move %s to %s' % (orig, new))
6625 try:
6626 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True)
6627 except IOError:
6628 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/')
6629 for i, name in enumerate(full_path):
6630 path = os.path.sep.join(full_path[:i+1])
6631 if path and not os.path.isdir(path):
6632 os.mkdir(path)
6633 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True)
6634
6635 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M)
6636 all_add = pattern.findall(text)
6637
6638
6639 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S)
6640 print('this step can take a few minuts. please be patient')
6641 all_rm_add = pattern.findall(text)
6642
6643 for new in all_add:
6644 if new in all_rm_add:
6645 continue
6646 if os.path.isfile(pjoin(MG5DIR, new)):
6647 os.remove(pjoin(MG5DIR, new))
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE,
6660 cwd=MG5DIR)
6661 p.communicate(text.encode())
6662
6663
6664
6665
6666
6667 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S)
6668 for match in pattern.findall(text):
6669 new = pjoin(MG5DIR, match[0])
6670 old = pjoin(MG5DIR, match[1])
6671 if new == old:
6672 continue
6673 elif os.path.exists(old):
6674 if not os.path.exists(os.path.dirname(new)):
6675 split = new.split('/')
6676 for i in range(1,len(split)):
6677 path = '/'.join(split[:i])
6678 if not os.path.exists(path):
6679 print('mkdir', path)
6680 os.mkdir(path)
6681 files.cp(old,new)
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702 for path in misc.glob('*', pjoin(MG5DIR, 'bin')):
6703 misc.call(['chmod', '+x', path])
6704 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')):
6705 misc.call(['chmod', '+x', path])
6706 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')):
6707 misc.call(['chmod', '+x', path])
6708 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')):
6709 misc.call(['chmod', '+x', path])
6710 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')):
6711 misc.call(['chmod', '+x', path])
6712
6713
6714 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M)
6715 for match in pattern.findall(text):
6716 if match[0] == 'file':
6717 new = os.path.dirname(pjoin(MG5DIR, match[1]))
6718 else:
6719 new = pjoin(MG5DIR, match[1])
6720 if not os.path.exists(new):
6721 split = new.split('/')
6722 for i in range(1,len(split)+1):
6723 path = '/'.join(split[:i])
6724 if path and not os.path.exists(path):
6725 print('mkdir', path)
6726 os.mkdir(path)
6727 if match[0] == 'file':
6728 print('touch ', pjoin(MG5DIR, match[1]))
6729 misc.call(['touch', pjoin(MG5DIR, match[1])])
6730
6731 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M)
6732 for new, old in pattern.findall(text):
6733 if not os.path.exists(pjoin(MG5DIR, new)):
6734 files.ln(pjoin(MG5DIR,old), os.path.dirname(pjoin(MG5DIR,new)), os.path.basename(new))
6735
6736
6737 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')):
6738 misc.compile(arg=['-j1'],cwd=pjoin(MG5DIR,'vendor','CutTools'),nb_core=1)
6739 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')):
6740 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src'))
6741
6742
6743 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M)
6744 if pattern.search(text):
6745 return True
6746 else:
6747 return False
6748
6749 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')]
6750 if mode:
6751 mode = mode[-1]
6752 else:
6753 mode = "userrequest"
6754 force = any([arg=='-f' for arg in args])
6755 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')]
6756 if timeout:
6757 try:
6758 timeout = int(timeout[-1])
6759 except ValueError:
6760 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1])
6761 else:
6762 timeout = self.options['timeout']
6763 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')]
6764
6765 if input_path:
6766 fsock = open(input_path[0])
6767 need_binary = apply_patch(fsock)
6768 logger.info('manual patch apply. Please test your version.')
6769 if need_binary:
6770 logger.warning('Note that some files need to be loaded separately!')
6771 sys.exit(0)
6772
6773 options = ['y','n','on_exit']
6774 if mode == 'mg5_start':
6775 timeout = 2
6776 default = 'n'
6777 update_delay = self.options['auto_update'] * 24 * 3600
6778 if update_delay == 0:
6779 return
6780 elif mode == 'mg5_end':
6781 timeout = 5
6782 default = 'n'
6783 update_delay = self.options['auto_update'] * 24 * 3600
6784 if update_delay == 0:
6785 return
6786 options.remove('on_exit')
6787 elif mode == "userrequest":
6788 default = 'y'
6789 update_delay = 0
6790 else:
6791 raise self.InvalidCmd('Unknown mode for command install update')
6792
6793 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')) or \
6794 os.path.exists(os.path.join(MG5DIR,'.bzr')):
6795 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are:
6796 1) This version was loaded via bazaar (use bzr pull to update instead).
6797 2) This version is a beta release of MG5."""
6798 if mode == 'userrequest':
6799 raise self.ConfigurationError(error_text)
6800 return
6801
6802 if not misc.which('patch'):
6803 error_text = """Not able to find program \'patch\'. Please reload a clean version
6804 or install that program and retry."""
6805 if mode == 'userrequest':
6806 raise self.ConfigurationError(error_text)
6807 return
6808
6809
6810 data = {}
6811 for line in open(os.path.join(MG5DIR,'input','.autoupdate')):
6812 if not line.strip():
6813 continue
6814 sline = line.split()
6815 data[sline[0]] = int(sline[1])
6816
6817
6818 if 'version_nb' not in data:
6819 if mode == 'userrequest':
6820 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)'
6821 raise self.ConfigurationError(error_text)
6822 return
6823 elif 'last_check' not in data:
6824 data['last_check'] = time.time()
6825
6826
6827 if time.time() - float(data['last_check']) < float(update_delay):
6828 return
6829
6830 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout)
6831 class TimeOutError(Exception): pass
6832
6833 def handle_alarm(signum, frame):
6834 raise TimeOutError
6835
6836 signal.signal(signal.SIGALRM, handle_alarm)
6837 signal.alarm(timeout)
6838 to_update = 0
6839 try:
6840 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/mg5amc_build_nb')
6841 signal.alarm(0)
6842 web_version = int(filetext.read().strip())
6843 except (TimeOutError, ValueError, IOError):
6844 signal.alarm(0)
6845 print('failed to connect server')
6846 if mode == 'mg5_end':
6847
6848 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6849 fsock.write("version_nb %s\n" % data['version_nb'])
6850 fsock.write("last_check %s\n" % \
6851 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1))
6852 fsock.close()
6853 return
6854
6855 if web_version == data['version_nb']:
6856 logger.info('No new version of MG5 available')
6857
6858 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6859 fsock.write("version_nb %s\n" % data['version_nb'])
6860 fsock.write("last_check %s\n" % int(time.time()))
6861 fsock.close()
6862 return
6863 elif data['version_nb'] > web_version:
6864 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version))
6865 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6866 fsock.write("version_nb %s\n" % data['version_nb'])
6867 fsock.write("last_check %s\n" % int(time.time()))
6868 fsock.close()
6869 return
6870 else:
6871 if not force:
6872 answer = self.ask('New Version of MG5 available! Do you want to update your current version?',
6873 default, options)
6874 else:
6875 answer = default
6876
6877
6878 if answer == 'y':
6879 logger.info('start updating code')
6880 fail = 0
6881 for i in range(data['version_nb'], web_version):
6882 try:
6883 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1))
6884 except Exception:
6885 print('fail to load patch to build #%s' % (i+1))
6886 fail = i
6887 break
6888 need_binary = apply_patch(filetext)
6889 if need_binary:
6890 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1)
6891 name = "extra_file%i" % (i+1)
6892 misc.wget(path, '%s.tgz' % name, cwd=MG5DIR)
6893
6894 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR,
6895 stdout=open(os.devnull, 'w'))
6896
6897 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6898 if not fail:
6899 fsock.write("version_nb %s\n" % web_version)
6900 else:
6901 fsock.write("version_nb %s\n" % fail)
6902 fsock.write("last_check %s\n" % int(time.time()))
6903 fsock.close()
6904 logger.info('Refreshing installation of MG5aMC_PY8_interface.')
6905 self.do_install('mg5amc_py8_interface',additional_options=['--force'])
6906 logger.info('Checking current version. (type ctrl-c to bypass the check)')
6907 subprocess.call([os.path.join('tests','test_manager.py')],
6908 cwd=MG5DIR)
6909 print('new version installed, please relaunch mg5')
6910 try:
6911 os.remove(pjoin(MG5DIR, 'Template','LO','Source','make_opts'))
6912 shutil.copy(pjoin(MG5DIR, 'Template','LO','Source','.make_opts'),
6913 pjoin(MG5DIR, 'Template','LO','Source','make_opts'))
6914 except:
6915 pass
6916 sys.exit(0)
6917 elif answer == 'n':
6918
6919 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w')
6920 fsock.write("version_nb %s\n" % data['version_nb'])
6921 fsock.write("last_check %s\n" % int(time.time()))
6922 fsock.close()
6923 logger.info('Update bypassed.')
6924 logger.info('The next check for a new version will be performed in %s days' \
6925 % abs(self.options['auto_update']))
6926 logger.info('In order to change this delay. Enter the command:')
6927 logger.info('set auto_update X')
6928 logger.info('Putting X to zero will prevent this check at anytime.')
6929 logger.info('You can upgrade your version at any time by typing:')
6930 logger.info('install update')
6931 else:
6932
6933
6934 self.options['auto_update'] = -1 * self.options['auto_update']
6935
6936
6937
6939 """ assign all configuration variable from file
6940 ./input/mg5_configuration.txt. assign to default if not define """
6941
6942 if not self.options:
6943 self.options = dict(self.options_configuration)
6944 self.options.update(self.options_madgraph)
6945 self.options.update(self.options_madevent)
6946
6947 if not config_path:
6948 if 'MADGRAPH_BASE' in os.environ:
6949 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt')
6950 self.set_configuration(config_path, final=False)
6951 if 'HOME' in os.environ:
6952 config_path = pjoin(os.environ['HOME'],'.mg5',
6953 'mg5_configuration.txt')
6954 if os.path.exists(config_path):
6955 self.set_configuration(config_path, final=False)
6956 config_path = os.path.relpath(pjoin(MG5DIR,'input',
6957 'mg5_configuration.txt'))
6958 return self.set_configuration(config_path, final)
6959
6960 if not os.path.exists(config_path):
6961 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path)
6962 config_file = open(config_path)
6963
6964
6965 logger.info('load MG5 configuration from %s ' % config_file.name)
6966 for line in config_file:
6967 if '#' in line:
6968 line = line.split('#',1)[0]
6969 line = line.replace('\n','').replace('\r\n','')
6970 try:
6971 name, value = line.split('=')
6972 except ValueError:
6973 pass
6974 else:
6975 name = name.strip()
6976 value = value.strip()
6977 if name != 'mg5_path':
6978 self.options[name] = value
6979 if value.lower() == "none" or value=="":
6980 self.options[name] = None
6981 config_file.close()
6982 self.options['stdout_level'] = logging.getLogger('madgraph').level
6983 if not final:
6984 return self.options
6985
6986
6987
6988
6989 for key in self.options:
6990 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path',
6991 'mg5amc_py8_interface_path','madanalysis5_path']:
6992 if self.options[key] in ['None', None]:
6993 self.options[key] = None
6994 continue
6995 path = self.options[key]
6996
6997 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')):
6998 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')):
6999 self.options['pythia8_path'] = None
7000 else:
7001 continue
7002
7003 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')):
7004 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')):
7005 self.options['mg5amc_py8_interface_path'] = None
7006 else:
7007 continue
7008
7009 if key == 'madanalysis5_path' and not os.path.isfile(pjoin(MG5DIR, path,'bin','ma5')):
7010 if not os.path.isfile(pjoin(path,'bin','ma5')):
7011 self.options['madanalysis5_path'] = None
7012 else:
7013 ma5path = pjoin(MG5DIR, path) if os.path.isfile(pjoin(MG5DIR, path)) else path
7014 message = misc.is_MA5_compatible_with_this_MG5(ma5path)
7015 if not message is None:
7016 self.options['madanalysis5_path'] = None
7017 logger.warning(message)
7018 continue
7019
7020
7021 if key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')):
7022 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')):
7023 self.options['hwpp_path'] = None
7024 else:
7025 continue
7026
7027 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')):
7028 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')):
7029 self.options['thepeg_path'] = None
7030 else:
7031 continue
7032
7033 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')):
7034 if not os.path.isfile(pjoin(path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')):
7035 self.options['hepmc_path'] = None
7036 else:
7037 continue
7038
7039 elif key in ['golem','samurai']:
7040 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto':
7041
7042 program = misc.which_lib('lib%s.a'%key)
7043 if program != None:
7044 fpath, _ = os.path.split(program)
7045 logger.info('Using %s library in %s' % (key,fpath))
7046 self.options[key]=fpath
7047 else:
7048
7049 local_install = { 'golem':'golem95',
7050 'samurai':'samurai'}
7051 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)):
7052 self.options[key]=pjoin(MG5DIR,local_install[key],'lib')
7053 else:
7054 self.options[key]=None
7055
7056 if key=='samurai' and \
7057 isinstance(self.options[key],str) and \
7058 self.options[key].lower() != 'auto':
7059 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')):
7060 try:
7061 version = open(pjoin(self.options[key],os.pardir,
7062 'VERSION'),'r').read()
7063 except IOError:
7064 version = None
7065 if version is None:
7066 self.options[key] = None
7067 logger.info('--------')
7068 logger.info(
7069 """The version of 'samurai' automatically detected seems too old to be compatible
7070 with MG5aMC and it will be turned off. Ask the authors for the latest version if
7071 you want to use samurai.
7072 If you want to enforce its use as-it-is, then specify directly its library folder
7073 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""")
7074 logger.info('--------')
7075
7076 elif key.endswith('path'):
7077 pass
7078 elif key in ['run_mode', 'auto_update']:
7079 self.options[key] = int(self.options[key])
7080 elif key in ['cluster_type','automatic_html_opening']:
7081 pass
7082 elif key in ['notification_center']:
7083 if self.options[key] in ['False', 'True']:
7084 self.allow_notification_center = eval(self.options[key])
7085 self.options[key] = self.allow_notification_center
7086 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']:
7087
7088 try:
7089 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False)
7090 except MadGraph5Error as error:
7091 print(error)
7092 logger.warning("Option %s from config file not understood" \
7093 % key)
7094 else:
7095 if key in self.options_madgraph:
7096 self.history.append('set %s %s' % (key, self.options[key]))
7097
7098 warnings = madevent_interface.MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options)
7099 if warnings:
7100 logger.warning(warnings)
7101
7102
7103 launch_ext.open_file.configure(self.options)
7104 return self.options
7105
7107 """Check if the files is in a valid export directory and assign it to
7108 export path if if is"""
7109
7110
7111 if self._export_dir:
7112 return
7113
7114 if os.path.exists(pjoin(os.getcwd(), 'Cards')):
7115 self._export_dir = os.getcwd()
7116 return
7117
7118 path_split = filepath.split(os.path.sep)
7119 if len(path_split) > 2 and path_split[-2] == 'Cards':
7120 self._export_dir = os.path.sep.join(path_split[:-2])
7121 return
7122
7124 """Main commands: Ask for editing the parameter and then
7125 Execute the code (madevent/standalone/...)
7126 """
7127
7128
7129 current_options = dict([(name, self.options[name]) for name in self.options_madgraph])
7130 start_cwd = os.getcwd()
7131
7132 args = self.split_arg(line)
7133
7134 (options, args) = _launch_parser.parse_args(args)
7135 self.check_launch(args, options)
7136 options = options.__dict__
7137
7138
7139 if args[0].startswith('standalone'):
7140 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\
7141 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\
7142 os.getcwd(),args[1],'SubProcesses','check_poles.f')):
7143 ext_program = launch_ext.MadLoopLauncher(self, args[1], \
7144 options=self.options, **options)
7145 else:
7146 ext_program = launch_ext.SALauncher(self, args[1], \
7147 options=self.options, **options)
7148 elif args[0] == 'madevent':
7149 if options['interactive']:
7150
7151 if isinstance(self, cmd.CmdShell):
7152 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options)
7153 else:
7154 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options)
7155 ME.pass_in_web_mode()
7156 stop = self.define_child_cmd_interface(ME)
7157 return stop
7158
7159
7160 if not self._generate_info:
7161
7162
7163 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read()
7164 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1]
7165 generate_info = generate_info.split('#')[0]
7166 else:
7167 generate_info = self._generate_info
7168
7169 if len(generate_info.split('>')[0].strip().split())>1:
7170 ext_program = launch_ext.MELauncher(args[1], self,
7171 shell = isinstance(self, cmd.CmdShell),
7172 options=self.options,**options)
7173 else:
7174
7175 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV',
7176 shell = isinstance(self, cmd.CmdShell),
7177 options=self.options,**options)
7178
7179 elif args[0] == 'pythia8':
7180 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options)
7181
7182 elif args[0] == 'aMC@NLO':
7183 if options['interactive']:
7184 if isinstance(self, cmd.CmdShell):
7185 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options)
7186 else:
7187 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options)
7188 ME.pass_in_web_mode()
7189
7190 config_line = [l for l in self.history if l.strip().startswith('set')]
7191 for line in config_line:
7192 ME.exec_cmd(line)
7193 stop = self.define_child_cmd_interface(ME)
7194 return stop
7195 ext_program = launch_ext.aMCatNLOLauncher( args[1], self,
7196 shell = isinstance(self, cmd.CmdShell),
7197 **options)
7198 elif args[0] == 'madweight':
7199 import madgraph.interface.madweight_interface as madweight_interface
7200 if options['interactive']:
7201 if isinstance(self, cmd.CmdShell):
7202 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options)
7203 else:
7204 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options)
7205
7206 config_line = [l for l in self.history if l.strip().startswith('set')]
7207 for line in config_line:
7208 MW.exec_cmd(line)
7209 stop = self.define_child_cmd_interface(MW)
7210 return stop
7211 ext_program = launch_ext.MWLauncher( self, args[1],
7212 shell = isinstance(self, cmd.CmdShell),
7213 options=self.options,**options)
7214 else:
7215 os.chdir(start_cwd)
7216 raise self.InvalidCmd('%s cannot be run from MG5 interface' % args[0])
7217
7218
7219 ext_program.run()
7220 os.chdir(start_cwd)
7221
7222 for key, value in current_options.items():
7223 self.options[key] = value
7224
7281
7282
7284 """create a restriction card in a interactive way"""
7285
7286 args = self.split_arg(line)
7287 self.check_customize_model(args)
7288
7289 model_path = self._curr_model.get('modelpath')
7290 if not os.path.exists(pjoin(model_path,'build_restrict.py')):
7291 raise self.InvalidCmd('''Model not compatible with this option.''')
7292
7293
7294 self._curr_model = import_ufo.import_model(model_path, restrict=False)
7295
7296
7297 out_path = StringIO.StringIO()
7298 param_writer.ParamCardWriter(self._curr_model, out_path)
7299
7300 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n'))
7301
7302
7303 all_categories = self.ask('','0',[], ask_class=AskforCustomize)
7304 put_to_one = []
7305
7306 for block in param_card:
7307 value_dict = {}
7308 for param in param_card[block]:
7309 value = param.value
7310 if value == 0:
7311 param.value = 0.000001e-99
7312 elif value == 1:
7313 if block != 'qnumbers':
7314 put_to_one.append((block,param.lhacode))
7315 param.value = random.random()
7316 elif abs(value) in value_dict:
7317 param.value += value_dict[abs(value)] * 1e-4 * param.value
7318 value_dict[abs(value)] += 1
7319 else:
7320 value_dict[abs(value)] = 1
7321
7322 for category in all_categories:
7323 for options in category:
7324 if not options.status:
7325 continue
7326 param = param_card[options.lhablock].get(options.lhaid)
7327 param.value = options.value
7328
7329 logger.info('Loading the resulting model')
7330
7331 self._curr_model = import_ufo.RestrictModel(self._curr_model)
7332 model_name = self._curr_model.get('name')
7333 if model_name == 'mssm':
7334 keep_external=True
7335 else:
7336 keep_external=False
7337 self._curr_model.restrict_model(param_card,keep_external=keep_external)
7338
7339 if args:
7340 name = args[0].split('=',1)[1]
7341 path = pjoin(model_path,'restrict_%s.dat' % name)
7342 logger.info('Save restriction file as %s' % path)
7343 param_card.write(path)
7344 self._curr_model['name'] += '-%s' % name
7345
7346
7347 if put_to_one:
7348 out_path = StringIO.StringIO()
7349 param_writer.ParamCardWriter(self._curr_model, out_path)
7350
7351 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n'))
7352
7353 for (block, lhacode) in put_to_one:
7354 try:
7355 param_card[block].get(lhacode).value = 1
7356 except:
7357 pass
7358 self._curr_model.set_parameters_and_couplings(param_card)
7359
7360 if args:
7361 name = args[0].split('=',1)[1]
7362 path = pjoin(model_path,'paramcard_%s.dat' % name)
7363 logger.info('Save default card file as %s' % path)
7364 param_card.write(path)
7365
7366 - def do_save(self, line, check=True, to_keep={}, log=True):
7367 """Not in help: Save information to file"""
7368
7369
7370 args = self.split_arg(line)
7371
7372 if check:
7373 self.check_save(args)
7374
7375 if args[0] == 'model':
7376 if self._curr_model:
7377
7378 if save_load_object.save_to_file(args[1], self._curr_model):
7379 logger.info('Saved model to file %s' % args[1])
7380 else:
7381 raise self.InvalidCmd('No model to save!')
7382 elif args[0] == 'processes':
7383 if self._curr_amps:
7384 if save_load_object.save_to_file(args[1], (self._curr_amps,self._curr_proc_defs) ):
7385 logger.info('Saved processes to file %s' % args[1])
7386 else:
7387 raise self.InvalidCmd('No processes to save!')
7388
7389 elif args[0] == 'options':
7390 partial_save = False
7391 to_define = {}
7392
7393 if any(not arg.startswith('--') and arg in self.options
7394 for arg in args):
7395
7396 partial_save = True
7397 all_arg = [arg for arg in args[1:] if not arg.startswith('--') and
7398 arg in self.options]
7399 for key in all_arg:
7400 to_define[key] = self.options[key]
7401 else:
7402
7403 for key, default in self.options_configuration.items():
7404 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None:
7405 to_define[key] = self.options[key]
7406
7407 if not '--auto' in args:
7408 for key, default in self.options_madevent.items():
7409 if self.options_madevent[key] != self.options[key] != None:
7410 if '_path' in key and os.path.basename(self.options[key]) == 'None':
7411 continue
7412 to_define[key] = self.options[key]
7413 elif key == 'cluster_queue' and self.options[key] is None:
7414 to_define[key] = self.options[key]
7415
7416 if '--all' in args:
7417 for key, default in self.options_madgraph.items():
7418 if self.options_madgraph[key] != self.options[key] != None and \
7419 key != 'stdout_level':
7420 to_define[key] = self.options[key]
7421 elif not '--auto' in args:
7422 for key, default in self.options_madgraph.items():
7423 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level':
7424 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \
7425 % (key,self.options_madgraph[key]) )
7426 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'')
7427
7428 if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options:
7429 filepath = args[1]
7430 else:
7431 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
7432
7433 basedir = MG5DIR
7434 if partial_save:
7435 basefile = filepath
7436 else:
7437 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt')
7438
7439
7440
7441 if to_keep:
7442 to_define = to_keep
7443 self.write_configuration(filepath, basefile, basedir, to_define)
7444
7445
7446 - def do_set(self, line, log=True, model_reload=True):
7447 """Set an option, which will be default for coming generations/outputs.
7448 """
7449
7450
7451
7452 args = self.split_arg(line)
7453
7454
7455 self.check_set(args)
7456
7457 if args[0] == 'ignore_six_quark_processes':
7458 if args[1].lower() == 'false':
7459 self.options[args[0]] = False
7460 return
7461 self.options[args[0]] = list(set([abs(p) for p in \
7462 self._multiparticles[args[1]]\
7463 if self._curr_model.get_particle(p).\
7464 is_fermion() and \
7465 self._curr_model.get_particle(abs(p)).\
7466 get('color') == 3]))
7467 if log:
7468 logger.info('Ignore processes with >= 6 quarks (%s)' % \
7469 ",".join([\
7470 self._curr_model.get_particle(q).get('name') \
7471 for q in self.options[args[0]]]))
7472
7473 elif args[0] == 'group_subprocesses':
7474 if args[1].lower() not in ['auto', 'nlo']:
7475 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, name="group_subprocesses")
7476 else:
7477 if args[1].lower() == 'nlo':
7478 self.options[args[0]] = "NLO"
7479 else:
7480 self.options[args[0]] = "Auto"
7481 if log:
7482 logger.info('Set group_subprocesses to %s' % \
7483 str(self.options[args[0]]))
7484 logger.info('Note that you need to regenerate all processes')
7485 self._curr_amps = diagram_generation.AmplitudeList()
7486 self._curr_proc_defs = base_objects.ProcessDefinitionList()
7487 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7488
7489 elif args[0] == "stdout_level":
7490 if args[1].isdigit():
7491 level = int(args[1])
7492 else:
7493 level = eval('logging.' + args[1])
7494 logging.root.setLevel(level)
7495 logging.getLogger('madgraph').setLevel(level)
7496 logging.getLogger('madevent').setLevel(level)
7497 self.options[args[0]] = level
7498 if log:
7499 logger.info('set output information to level: %s' % level)
7500 elif args[0].lower() == "ewscheme":
7501 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." %\
7502 (self._curr_model.get('name'), args[1]))
7503 logger.info("Importing a model will restore the default scheme")
7504 self._curr_model.change_electroweak_mode(args[1])
7505 elif args[0] == "complex_mass_scheme":
7506 old = self.options[args[0]]
7507 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, "complex_mass_scheme")
7508 aloha.complex_mass = self.options[args[0]]
7509 aloha_lib.KERNEL.clean()
7510 if self.options[args[0]]:
7511 if old:
7512 if log:
7513 logger.info('Complex mass already activated.')
7514 return
7515 if log:
7516 logger.info('Activate complex mass scheme.')
7517 else:
7518 if not old:
7519 if log:
7520 logger.info('Complex mass already desactivated.')
7521 return
7522 if log:
7523 logger.info('Desactivate complex mass scheme.')
7524 if not self._curr_model:
7525 return
7526 self.exec_cmd('import model %s' % self._curr_model.get('name'))
7527
7528 elif args[0] == "gauge":
7529
7530 if not self._curr_model:
7531 if args[1] == 'unitary':
7532 aloha.unitary_gauge = True
7533 elif args[1] == 'axial':
7534 aloha.unitary_gauge = 2
7535 else:
7536 aloha.unitary_gauge = False
7537 aloha_lib.KERNEL.clean()
7538 self.options[args[0]] = args[1]
7539 if log: logger.info('Passing to gauge %s.' % args[1])
7540 return
7541
7542
7543 able_to_mod = True
7544 if args[1] == 'unitary':
7545 if 0 in self._curr_model.get('gauge'):
7546 aloha.unitary_gauge = True
7547 else:
7548 able_to_mod = False
7549 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \
7550 % self._curr_model.get('name'))
7551 elif args[1] == 'axial':
7552 if 0 in self._curr_model.get('gauge'):
7553 aloha.unitary_gauge = 2
7554 else:
7555 able_to_mod = False
7556 if log: logger.warning('Note that parton-shower gauge is not allowed for your current model %s' \
7557 % self._curr_model.get('name'))
7558 else:
7559 if 1 in self._curr_model.get('gauge'):
7560 aloha.unitary_gauge = False
7561 else:
7562 able_to_mod = False
7563 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \
7564 % self._curr_model.get('name'))
7565
7566 if self.options['gauge'] == args[1]:
7567 return
7568
7569
7570 self.options[args[0]] = args[1]
7571
7572 if able_to_mod and log and args[0] == 'gauge' and \
7573 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \
7574 isinstance(self._curr_model,loop_base_objects.LoopModel) and \
7575 not self._curr_model['perturbation_couplings'] in [[],['QCD']]:
7576 logger.warning('You will only be able to do tree level'+\
7577 ' and QCD corrections in the unitary gauge.')
7578
7579
7580
7581
7582 model_name = self._curr_model.get('modelpath+restriction')
7583 self._curr_model = None
7584 self._curr_amps = diagram_generation.AmplitudeList()
7585 self._curr_proc_defs = base_objects.ProcessDefinitionList()
7586 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7587 self._curr_helas_model = None
7588 self._curr_exporter = None
7589 self._done_export = False
7590 import_ufo._import_once = []
7591 logger.info('Passing to gauge %s.' % args[1])
7592
7593 if able_to_mod:
7594
7595
7596
7597 if 'modelname' in self.history.get('full_model_line'):
7598 opts = '--modelname'
7599 else:
7600 opts=''
7601 MadGraphCmd.do_import(self,'model %s %s' % (model_name, opts), force=True)
7602 elif log:
7603 logger.info('Note that you have to reload the model')
7604
7605 elif args[0] == 'fortran_compiler':
7606 if args[1] != 'None':
7607 if log:
7608 logger.info('set fortran compiler to %s' % args[1])
7609 self.options['fortran_compiler'] = args[1]
7610 else:
7611 self.options['fortran_compiler'] = None
7612 elif args[0] == 'default_unset_couplings':
7613 self.options['default_unset_couplings'] = banner_module.ConfigFile.format_variable(args[1], int, name="default_unset_couplings")
7614 elif args[0].startswith('f2py_compiler'):
7615 to_do = True
7616 if args[0].endswith('_py2') and six.PY3:
7617 to_do = False
7618 elif args[0].endswith('_py3') and six.PY2:
7619 to_do = False
7620 if to_do:
7621 if args[1] != 'None':
7622 if log:
7623 logger.info('set f2py compiler to %s' % args[1])
7624
7625 self.options['f2py_compiler'] = args[1]
7626 else:
7627 self.options['f2py_compiler'] = None
7628
7629 elif args[0] == 'loop_optimized_output':
7630
7631 if log:
7632 logger.info('set loop optimized output to %s' % args[1])
7633 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7634 self.options[args[0]] = args[1]
7635 if not self.options['loop_optimized_output'] and \
7636 self.options['loop_color_flows']:
7637 logger.warning("Turning off option 'loop_color_flows'"+\
7638 " since it is not available for non-optimized loop output.")
7639 self.do_set('loop_color_flows False',log=False)
7640 elif args[0] == 'loop_color_flows':
7641 if log:
7642 logger.info('set loop color flows to %s' % args[1])
7643 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7644 self.options[args[0]] = args[1]
7645 if self.options['loop_color_flows'] and \
7646 not self.options['loop_optimized_output']:
7647 logger.warning("Turning on option 'loop_optimized'"+\
7648 " needed for loop color flow computation.")
7649 self.do_set('loop_optimized_output True',False)
7650
7651 elif args[0] == 'fastjet':
7652 try:
7653 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE,
7654 stderr=subprocess.PIPE)
7655 output, error = p.communicate()
7656 output = output.decode()
7657 res = 0
7658 except Exception:
7659 res = 1
7660
7661 if res != 0 or error:
7662 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \
7663 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \
7664 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' +
7665 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n')
7666 self.options[args[0]] = None
7667 if self.history and 'fastjet' in self.history[-1]:
7668 self.history.pop()
7669 elif int(output.split('.')[0]) < 3:
7670 logger.warning('%s is not ' % args[1] + \
7671 'v3 or greater. Please install FastJet v3+.')
7672 self.options[args[0]] = None
7673 self.history.pop()
7674 else:
7675 logger.info('set fastjet to %s' % args[1])
7676 self.options[args[0]] = args[1]
7677
7678 elif args[0] in ['golem','samurai','ninja','collier'] and \
7679 not (args[0] in ['ninja','collier'] and args[1]=='./HEPTools/lib'):
7680 if args[1] in ['None',"''",'""']:
7681 self.options[args[0]] = None
7682 else:
7683 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0]))
7684 if program!=None:
7685 res = 0
7686 logger.info('set %s to %s' % (args[0],args[1]))
7687 self.options[args[0]] = args[1]
7688 else:
7689 res = 1
7690
7691 if res != 0 :
7692 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \
7693 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \
7694 'You will NOT be able to run %s otherwise.\n'%args[0])
7695
7696 elif args[0].startswith('lhapdf'):
7697 to_do = True
7698 if args[0].endswith('_py2') and six.PY3:
7699 to_do = False
7700 elif args[0].endswith('_py3') and six.PY2:
7701 to_do = False
7702 if to_do:
7703 try:
7704 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE,
7705 stderr=subprocess.PIPE)
7706 logger.info('set lhapdf to %s' % args[1])
7707 self.options['lhapdf'] = args[1]
7708 self.options[args[0]] = args[1]
7709 except Exception:
7710 res = 1
7711 if res != 0:
7712 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \
7713 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \
7714 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \
7715 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \
7716 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n')
7717
7718 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry', 'max_t_for_channel',
7719 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']:
7720 self.options[args[0]] = int(args[1])
7721
7722 elif args[0] in ['cluster_local_path']:
7723 self.options[args[0]] = args[1].strip()
7724
7725 elif args[0] == 'cluster_status_update':
7726 if '(' in args[1]:
7727 data = ' '.join([a for a in args[1:] if not a.startswith('-')])
7728 data = data.replace('(','').replace(')','').replace(',',' ').split()
7729 first, second = data[:2]
7730 else:
7731 first, second = args[1:3]
7732
7733 self.options[args[0]] = (int(first), int(second))
7734
7735 elif args[0] == 'madanalysis5_path':
7736 ma5path = pjoin(MG5DIR, args[1]) if os.path.isfile(pjoin(MG5DIR, args[1])) else args[1]
7737 message = misc.is_MA5_compatible_with_this_MG5(ma5path)
7738 if message is None:
7739 self.options['madanalysis5_path'] = args[1]
7740 else:
7741 logger.warning(message)
7742
7743 elif args[0] == 'OLP':
7744 if six.PY3 and self.options['low_mem_multicore_nlo_generation']:
7745 raise self.InvalidCmd('Not possible to set OLP with both \"low_mem_multicore_nlo_generation\" and python3')
7746
7747
7748 self._curr_amps = diagram_generation.AmplitudeList()
7749 self._curr_proc_defs = base_objects.ProcessDefinitionList()
7750 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
7751 self._curr_exporter = None
7752 self.options[args[0]] = args[1]
7753
7754 elif args[0] =='output_dependencies':
7755 self.options[args[0]] = args[1]
7756 elif args[0] =='notification_center':
7757 if args[1] in ['None','True','False']:
7758 self.options[args[0]] = eval(args[1])
7759 self.allow_notification_center = self.options[args[0]]
7760 else:
7761 raise self.InvalidCmd('expected bool for notification_center')
7762
7763 elif args[0] in ['crash_on_error']:
7764 try:
7765 tmp = banner_module.ConfigFile.format_variable(args[1], bool, 'crash_on_error')
7766 except Exception:
7767 if args[1].lower() in ['never']:
7768 tmp = args[1].lower()
7769 else:
7770 raise
7771 self.options[args[0]] = tmp
7772 elif args[0] in ['zerowidth_tchannel']:
7773 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, args[0])
7774 elif args[0] in ['cluster_queue']:
7775 self.options[args[0]] = args[1].strip()
7776 elif args[0] in ['low_mem_multicore_nlo_generation']:
7777 if six.PY3 and self.options['OLP'] != 'MadLoop':
7778 raise self.InvalidCmd('Not possible to set \"low_mem_multicore_nlo_generation\" for an OLP different of MadLoop when running python3')
7779 else:
7780 self.options[args[0]] = args[1]
7781 elif args[0] in self.options:
7782 if args[1] in ['None','True','False']:
7783 self.options[args[0]] = eval(args[1])
7784 else:
7785 self.options[args[0]] = args[1]
7786
7787 - def post_set(self, stop, line):
7788 """Check if we need to save this in the option file"""
7789
7790 args = self.split_arg(line)
7791
7792 try:
7793 self.check_set(args, log=False)
7794 except Exception:
7795 return stop
7796
7797 if args[0] in self.options_configuration and '--no_save' not in args:
7798 self.exec_cmd('save options %s' % args[0] , log=False)
7799 elif args[0] in self.options_madevent:
7800 if not '--no_save' in line:
7801 logger.info('This option will be the default in any output that you are going to create in this session.')
7802 logger.info('In order to keep this changes permanent please run \'save options\'')
7803 else:
7804
7805 if not self.history or self.history[-1].split() != line.split():
7806 self.history.append('set %s' % line)
7807 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set'])
7808 return stop
7809
7819
7821 """Main commands: Initialize a new Template or reinitialize one"""
7822
7823 args = self.split_arg(line)
7824
7825 self.check_output(args)
7826
7827 noclean = '-noclean' in args
7828 force = '-f' in args
7829 nojpeg = '-nojpeg' in args
7830 if '--noeps=True' in args:
7831 nojpeg = True
7832 flaglist = []
7833
7834 if '--postpone_model' in args:
7835 flaglist.append('store_model')
7836
7837 line_options = dict(arg[2:].split('=') for arg in args if arg.startswith('--') and '=' in arg)
7838 main_file_name = ""
7839 try:
7840 main_file_name = args[args.index('-name') + 1]
7841 except Exception:
7842 pass
7843
7844
7845
7846
7847
7848 if self._export_format == 'aloha':
7849
7850 format = [d[9:] for d in args if d.startswith('--format=')]
7851 if not format:
7852 format = 'Fortran'
7853 else:
7854 format = format[-1]
7855
7856 output = [d for d in args if d.startswith('--output=')]
7857 if not output:
7858 output = import_ufo.find_ufo_path(self._curr_model['name'])
7859 output = pjoin(output, format)
7860 if not os.path.isdir(output):
7861 os.mkdir(output)
7862 else:
7863 output = output[-1]
7864 if not os.path.isdir(output):
7865 raise self.InvalidCmd('%s is not a valid directory' % output)
7866 logger.info('creating routines in directory %s ' % output)
7867
7868 names = [d for d in args if not d.startswith('-')]
7869 wanted_lorentz = aloha_fct.guess_routine_from_name(names)
7870
7871 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name'))
7872 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz'))
7873 if wanted_lorentz:
7874 aloha_model.compute_subset(wanted_lorentz)
7875 else:
7876 aloha_model.compute_all(save=False)
7877 aloha_model.write(output, format)
7878 return
7879
7880
7881
7882
7883
7884
7885
7886
7887 config = {}
7888 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
7889 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'}
7890 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
7891 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'}
7892 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'}
7893 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'}
7894 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'}
7895 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'}
7896 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'}
7897 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'}
7898 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
7899
7900 if self._export_format == 'plugin':
7901 options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output}
7902 else:
7903 options = config[self._export_format]
7904
7905
7906 if os.path.realpath(self._export_dir) == os.getcwd():
7907 if len(args) == 0:
7908 i=0
7909 while 1:
7910 if os.path.exists('Pythia8_proc_%i' %i):
7911 i+=1
7912 else:
7913 break
7914 os.mkdir('Pythia8_proc_%i' %i)
7915 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i)
7916 logger.info('Create output in %s' % self._export_dir)
7917 elif not args[0] in ['.', '-f']:
7918 raise self.InvalidCmd('Wrong path directory to create in local directory use \'.\'')
7919 elif not noclean and os.path.isdir(self._export_dir) and options['check']:
7920 if not force:
7921
7922 logger.info('INFO: directory %s already exists.' % self._export_dir)
7923 logger.info('If you continue this directory will be deleted and replaced.')
7924 answer = self.ask('Do you want to continue?', 'y', ['y','n'])
7925 else:
7926 answer = 'y'
7927 if answer != 'y':
7928 raise self.InvalidCmd('Stopped by user request')
7929 else:
7930 shutil.rmtree(self._export_dir)
7931
7932
7933
7934 if self.options['group_subprocesses'] in [True, False]:
7935 group_processes = self.options['group_subprocesses']
7936 elif self.options['group_subprocesses'] == 'Auto':
7937
7938 group_processes = True
7939
7940
7941
7942
7943 if self._curr_amps[0].get_ninitial() == 1 and \
7944 len(self._curr_amps)>1:
7945
7946 processes = [amp.get('process') for amp in self._curr_amps if 'process' in list(amp.keys())]
7947 if len(set(proc.get('id') for proc in processes))!=len(processes):
7948
7949 if any(proc['perturbation_couplings'] != [] for proc in
7950 processes) and self._export_format == 'madevent':
7951 logger.warning("""
7952 || The loop-induced decay process you have specified contains several
7953 || subprocesses and, in order to be able to compute individual branching ratios,
7954 || MG5_aMC will *not* group them. Integration channels will also be considered
7955 || for each diagrams and as a result integration will be inefficient.
7956 || It is therefore recommended to perform this simulation by setting the MG5_aMC
7957 || option 'group_subprocesses' to 'True' (before the output of the process).
7958 || Notice that when doing so, processes for which one still wishes to compute
7959 || branching ratios independently can be specified using the syntax:
7960 || -> add process <proc_def>
7961 """)
7962 group_processes = False
7963
7964
7965 if options['exporter'] == 'v4':
7966 self._curr_exporter = export_v4.ExportV4Factory(self, noclean,
7967 group_subprocesses=group_processes,
7968 cmd_options=line_options)
7969 elif options['exporter'] == 'cpp':
7970 self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes,
7971 cmd_options=line_options)
7972
7973 self._curr_exporter.pass_information_from_cmd(self)
7974
7975 if options['output'] == 'Template':
7976 self._curr_exporter.copy_template(self._curr_model)
7977 elif options['output'] == 'dir' and not os.path.isdir(self._export_dir):
7978 os.makedirs(self._export_dir)
7979
7980
7981 self._done_export = False
7982
7983 if self._export_format == "madevent":
7984
7985
7986 if self.options['max_npoint_for_channel']:
7987 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel']
7988 else:
7989 base_objects.Vertex.max_n_loop_for_multichanneling = 3
7990 base_objects.Vertex.max_tpropa = self.options['max_t_for_channel']
7991
7992
7993 self.export(nojpeg, main_file_name, group_processes, args)
7994
7995
7996 self.finalize(nojpeg, flaglist=flaglist)
7997
7998
7999 self._done_export = (self._export_dir, self._export_format)
8000
8001
8002 self._export_dir = None
8003
8004
8005 - def export(self, nojpeg = False, main_file_name = "", group_processes=True,
8006 args=[]):
8007 """Export a generated amplitude to file."""
8008
8009
8010
8011 if self._curr_exporter.exporter == 'cpp':
8012 self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model)
8013 elif self._model_v4_path:
8014 assert self._curr_exporter.exporter == 'v4'
8015 self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model)
8016 else:
8017 assert self._curr_exporter.exporter == 'v4'
8018 options = {'zerowidth_tchannel': True}
8019 if self._curr_amps and self._curr_amps[0].get_ninitial() == 1:
8020 options['zerowidth_tchannel'] = False
8021
8022 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
8023
8024 version = [arg[10:] for arg in args if arg.startswith('--version=')]
8025 if version:
8026 version = version[-1]
8027 else:
8028 version = '8.2'
8029
8030 def generate_matrix_elements(self, group_processes=True):
8031 """Helper function to generate the matrix elements before
8032 exporting. Uses the main function argument 'group_processes' to decide
8033 whether to use group_subprocess or not. (it has been set in do_output to
8034 the appropriate value if the MG5 option 'group_subprocesses' was set
8035 to 'Auto'."""
8036
8037 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']:
8038 to_distinguish = []
8039 for part in self._curr_model.get('particles'):
8040 if part.get('name') in args and part.get('antiname') in args and\
8041 part.get('name') != part.get('antiname'):
8042 to_distinguish.append(abs(part.get('pdg_code')))
8043
8044
8045 self._curr_amps.sort(key=lambda x: x.get_number_of_diagrams(),reverse=True)
8046
8047 cpu_time1 = time.time()
8048 ndiags = 0
8049 if not self._curr_matrix_elements.get_matrix_elements():
8050 if group_processes:
8051 cpu_time1 = time.time()
8052 dc_amps = diagram_generation.DecayChainAmplitudeList(\
8053 [amp for amp in self._curr_amps if isinstance(amp, \
8054 diagram_generation.DecayChainAmplitude)])
8055 non_dc_amps = diagram_generation.AmplitudeList(\
8056 [amp for amp in self._curr_amps if not \
8057 isinstance(amp, \
8058 diagram_generation.DecayChainAmplitude)])
8059 subproc_groups = group_subprocs.SubProcessGroupList()
8060 matrix_elements_opts = {'optimized_output':
8061 self.options['loop_optimized_output']}
8062
8063 grouping_criteria = self._curr_exporter.grouped_mode
8064 if non_dc_amps:
8065 subproc_groups.extend(\
8066 group_subprocs.SubProcessGroup.group_amplitudes(\
8067 non_dc_amps,grouping_criteria,
8068 matrix_elements_opts=matrix_elements_opts))
8069
8070 if dc_amps:
8071 dc_subproc_group = \
8072 group_subprocs.DecayChainSubProcessGroup.\
8073 group_amplitudes(dc_amps, grouping_criteria,
8074 matrix_elements_opts=matrix_elements_opts)
8075 subproc_groups.extend(dc_subproc_group.\
8076 generate_helas_decay_chain_subproc_groups())
8077
8078 ndiags = sum([len(m.get('diagrams')) for m in \
8079 subproc_groups.get_matrix_elements()])
8080 self._curr_matrix_elements = subproc_groups
8081
8082 uid = 0
8083 for group in subproc_groups:
8084 uid += 1
8085 for me in group.get('matrix_elements'):
8086 me.get('processes')[0].set('uid', uid)
8087 else:
8088 mode = {}
8089 if self._export_format in [ 'standalone_msP' ,
8090 'standalone_msF', 'standalone_rw']:
8091 mode['mode'] = 'MadSpin'
8092
8093
8094 if isinstance(self._curr_amps[0],
8095 loop_diagram_generation.LoopAmplitude):
8096 mode['optimized_output']=self.options['loop_optimized_output']
8097 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess
8098 compute_loop_nc = True
8099 else:
8100 HelasMultiProcessClass = helas_objects.HelasMultiProcess
8101 compute_loop_nc = False
8102
8103 self._curr_matrix_elements = HelasMultiProcessClass(
8104 self._curr_amps, compute_loop_nc=compute_loop_nc,
8105 matrix_element_opts=mode)
8106
8107 ndiags = sum([len(me.get('diagrams')) for \
8108 me in self._curr_matrix_elements.\
8109 get_matrix_elements()])
8110
8111 uid = 0
8112 for me in self._curr_matrix_elements.get_matrix_elements()[:]:
8113 uid += 1
8114 me.get('processes')[0].set('uid', uid)
8115
8116 cpu_time2 = time.time()
8117
8118
8119 return ndiags, cpu_time2 - cpu_time1
8120
8121
8122
8123 ndiags, cpu_time = generate_matrix_elements(self,group_processes)
8124
8125 calls = 0
8126
8127 path = self._export_dir
8128
8129 cpu_time1 = time.time()
8130
8131
8132
8133
8134
8135 if self._export_format == 'madevent':
8136 calls += self._curr_exporter.export_processes(self._curr_matrix_elements,
8137 self._curr_helas_model)
8138
8139
8140
8141
8142
8143
8144
8145
8146 elif self._export_format == 'pythia8':
8147
8148 process_names = []
8149 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList):
8150 for (group_number, me_group) in enumerate(self._curr_matrix_elements):
8151 exporter = self._curr_exporter.generate_process_directory(\
8152 me_group.get('matrix_elements'), self._curr_helas_model,
8153 process_string = me_group.get('name'),
8154 process_number = group_number+1,
8155 version = version)
8156 process_names.append(exporter.process_name)
8157 else:
8158 exporter = self._curr_exporter.generate_process_directory(\
8159 self._curr_matrix_elements, self._curr_helas_model,
8160 process_string = self._generate_info, version = version)
8161 process_names.append(exporter.process_file_name)
8162
8163
8164 model_name, model_path = exporter.convert_model_to_pythia8(\
8165 self._curr_model, self._export_dir)
8166
8167
8168 filename, make_filename = \
8169 self._curr_exporter.generate_example_file_pythia8(path,
8170 model_path,
8171 process_names,
8172 exporter,
8173 main_file_name)
8174
8175
8176 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
8177
8178 if self._export_format == 'matrix':
8179 for me in matrix_elements:
8180 filename = pjoin(path, 'matrix_' + \
8181 me.get('processes')[0].shell_string() + ".f")
8182 if os.path.isfile(filename):
8183 logger.warning("Overwriting existing file %s" % filename)
8184 else:
8185 logger.info("Creating new file %s" % filename)
8186 calls = calls + self._curr_exporter.write_matrix_element_v4(\
8187 writers.FortranWriter(filename),\
8188 me, self._curr_helas_model)
8189 elif self._export_format in ['madevent', 'pythia8']:
8190 pass
8191
8192 elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\
8193 self._curr_exporter.grouped_mode:
8194 modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements)
8195 if modify:
8196 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
8197
8198 for me_number, me in enumerate(self._curr_matrix_elements):
8199 calls = calls + \
8200 self._curr_exporter.generate_subprocess_directory(\
8201 me, self._curr_helas_model, me_number)
8202
8203
8204 else:
8205 for nb,me in enumerate(matrix_elements[:]):
8206 new_calls = self._curr_exporter.generate_subprocess_directory(\
8207 me, self._curr_helas_model, nb)
8208 if isinstance(new_calls, int):
8209 if new_calls ==0:
8210 matrix_elements.remove(me)
8211 else:
8212 calls = calls + new_calls
8213
8214 if self._generate_info and hasattr(self._curr_exporter, 'write_procdef_mg5'):
8215
8216 card_path = pjoin(self._export_dir ,'SubProcesses', \
8217 'procdef_mg5.dat')
8218 self._curr_exporter.write_procdef_mg5(card_path,
8219 self._curr_model['name'],
8220 self._generate_info)
8221
8222
8223 cpu_time2 = time.time() - cpu_time1
8224
8225 logger.info(("Generated helas calls for %d subprocesses " + \
8226 "(%d diagrams) in %0.3f s") % \
8227 (len(matrix_elements),
8228 ndiags, cpu_time))
8229
8230 if calls:
8231 if "cpu_time2" in locals():
8232 logger.info("Wrote files for %d helas calls in %0.3f s" % \
8233 (calls, cpu_time2))
8234 else:
8235 logger.info("Wrote files for %d helas calls" % \
8236 (calls))
8237
8238 if self._export_format == 'pythia8':
8239 logger.info("- All necessary files for Pythia 8 generated.")
8240 logger.info("- Run \"launch\" and select %s.cc," % filename)
8241 logger.info(" or go to %s/examples and run" % path)
8242 logger.info(" make -f %s" % make_filename)
8243 logger.info(" (with process_name replaced by process name).")
8244 logger.info(" You can then run ./%s to produce events for the process" % \
8245 filename)
8246
8247
8248
8249
8250 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
8251 self._curr_amps = diagram_generation.AmplitudeList(\
8252 [me.get('base_amplitude') for me in \
8253 matrix_elements])
8254
8255 - def finalize(self, nojpeg, online = False, flaglist=[]):
8256 """Make the html output, write proc_card_mg5.dat and create
8257 madevent.tar.gz for a MadEvent directory"""
8258
8259 compiler_dict = {'fortran': self.options['fortran_compiler'],
8260 'cpp': self.options['cpp_compiler'],
8261 'f2py': self.options['f2py_compiler']}
8262
8263
8264 if self._model_v4_path:
8265 logger.info('Copy %s model files to directory %s' % \
8266 (os.path.basename(self._model_v4_path), self._export_dir))
8267 self._curr_exporter.export_model_files(self._model_v4_path)
8268 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS'))
8269 else:
8270
8271
8272
8273 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz()
8274 wanted_couplings = self._curr_matrix_elements.get_used_couplings()
8275
8276
8277 if hasattr(self, 'previous_lorentz'):
8278 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz))
8279 wanted_couplings = list(set(self.previous_couplings + wanted_couplings))
8280 del self.previous_lorentz
8281 del self.previous_couplings
8282 if 'store_model' in flaglist:
8283 self.previous_lorentz = wanted_lorentz
8284 self.previous_couplings = wanted_couplings
8285 else:
8286 self._curr_exporter.convert_model(self._curr_model,
8287 wanted_lorentz,
8288 wanted_couplings)
8289
8290
8291 if nojpeg:
8292 flaglist.append('nojpeg')
8293 if online:
8294 flaglist.append('online')
8295
8296
8297
8298 if self._export_format in ['NLO']:
8299
8300
8301 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt')
8302 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path',
8303 'hepmc_path']
8304 to_keep = {}
8305 for opt in opts_to_keep:
8306 if self.options[opt]:
8307 to_keep[opt] = self.options[opt]
8308 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \
8309 to_keep = to_keep)
8310
8311 elif self._export_format in ['madevent', 'madweight']:
8312
8313 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt')
8314 self.do_save('options %s' % filename.replace(' ', '\ '), check=False,
8315 to_keep={'mg5_path':MG5DIR})
8316
8317
8318 self._curr_exporter.finalize(self._curr_matrix_elements,
8319 self.history,
8320 self.options,
8321 flaglist)
8322
8323 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']:
8324 logger.info('Output to directory ' + self._export_dir + ' done.')
8325
8326 if self._export_format in ['madevent', 'NLO']:
8327 logger.info('Type \"launch\" to generate events from this process, or see')
8328 logger.info(self._export_dir + '/README')
8329 logger.info('Run \"open index.html\" to see more information about this process.')
8330
8332 """ propose some usefull possible action """
8333
8334 super(MadGraphCmd,self).do_help(line)
8335
8336 if line:
8337 return
8338
8339 if len(self.history) == 0:
8340 last_action_2 = 'mg5_start'
8341 last_action = 'mg5_start'
8342 else:
8343 args = self.history[-1].split()
8344 last_action = args[0]
8345 if len(args)>1:
8346 last_action_2 = '%s %s' % (last_action, args[1])
8347 else:
8348 last_action_2 = 'none'
8349
8350
8351
8352
8354 """Documented commands:Generate amplitudes for decay width calculation, with fixed
8355 number of final particles (called level)
8356 syntax; compute_widths particle [other particles] [--options=]
8357
8358 - particle/other particles can also be multiparticle name (can also be
8359 pid of the particle)
8360
8361 --body_decay=X [default=4.0025] allow to choose the precision.
8362 if X is an integer: compute all X body decay
8363 if X is a float <1: compute up to the time that total error < X
8364 if X is a float >1: stops at the first condition.
8365
8366 --path=X. Use a given file for the param_card. (default UFO built-in)
8367
8368 special argument:
8369 - skip_2body: allow to not consider those decay (use FR)
8370 - model: use the model pass in argument.
8371
8372 """
8373
8374
8375
8376 self.change_principal_cmd('MadGraph')
8377 if '--nlo' not in line:
8378 warning_text = """Please note that the automatic computation of the width is
8379 only valid in narrow-width approximation and at tree-level."""
8380 logger.warning(warning_text)
8381
8382 if not model:
8383 modelname = self._curr_model.get('modelpath+restriction')
8384 with misc.MuteLogger(['madgraph'], ['INFO']):
8385 model = import_ufo.import_model(modelname, decay=True)
8386 self._curr_model = model
8387
8388 if not isinstance(model, model_reader.ModelReader):
8389 model = model_reader.ModelReader(model)
8390
8391 if '--nlo' in line:
8392
8393 self.compute_widths_SMWidth(line, model=model)
8394 return
8395
8396
8397 particles, opts = self.check_compute_widths(self.split_arg(line))
8398
8399 if opts['path']:
8400 correct = True
8401 param_card = check_param_card.ParamCard(opts['path'])
8402 for param in param_card['decay']:
8403 if param.value == "auto":
8404 param.value = 1
8405 param.format = 'float'
8406 correct = False
8407 if not correct:
8408 if opts['output']:
8409 param_card.write(opts['output'])
8410 opts['path'] = opts['output']
8411 else:
8412 param_card.write(opts['path'])
8413
8414 data = model.set_parameters_and_couplings(opts['path'])
8415
8416
8417
8418 if do2body:
8419 skip_2body = True
8420 decay_info = {}
8421 for pid in particles:
8422 particle = model.get_particle(pid)
8423 if not hasattr(particle, 'partial_widths'):
8424 skip_2body = False
8425 break
8426 elif not decay_info:
8427 logger_mg.info('Get two body decay from FeynRules formula')
8428 decay_info[pid] = []
8429 mass = abs(eval(str(particle.get('mass')), data).real)
8430 data = model.set_parameters_and_couplings(opts['path'], scale= mass)
8431 total = 0
8432
8433
8434 if 'aS' in data and data['aS'] == 0 and particle.get('color') != 1:
8435 logger.warning("aS set to zero for this particle since the running is not defined for such low mass.")
8436
8437 for mode, expr in particle.partial_widths.items():
8438 tmp_mass = mass
8439 for p in mode:
8440 try:
8441 value_mass = eval(str(p.mass), data)
8442 except Exception:
8443
8444
8445 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data)
8446 tmp_mass -= abs(value_mass)
8447 if tmp_mass <=0:
8448 continue
8449
8450 decay_to = [p.get('pdg_code') for p in mode]
8451 value = eval(expr,{'cmath':cmath},data).real
8452 if -1e-10 < value < 0:
8453 value = 0
8454 if -1e-5 < value < 0:
8455 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' %
8456 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value))
8457 value = 0
8458 elif value < 0:
8459 raise Exception('Partial width for %s > %s negative: %s' % \
8460 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value))
8461 elif 0 < value < 0.1 and particle['color'] !=1:
8462 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \
8463 % (particle.get('name'), value, decay_to))
8464 value = 0
8465
8466 decay_info[particle.get('pdg_code')].append([decay_to, value])
8467 total += value
8468 else:
8469 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info,
8470 opts['path'], opts['output'])
8471 if float(opts['body_decay']) == 2:
8472 return decay_info
8473 else:
8474 skip_2body = True
8475
8476
8477
8478
8479
8480 self.do_decay_diagram('%s %s' % (' '.join([repr(id) for id in particles]),
8481 ' '.join('--%s=%s' % (key,value)
8482 for key,value in opts.items()
8483 if key not in ['precision_channel'])
8484 ), skip_2body=skip_2body, model=decaymodel)
8485
8486 if self._curr_amps:
8487 logger.info('Pass to numerical integration for computing the widths:')
8488 else:
8489 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output'])
8490
8491
8492
8493 return decay_info
8494
8495
8496 with misc.TMP_directory(dir=os.getcwd()) as path:
8497 decay_dir = pjoin(path,'temp_decay')
8498 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir))
8499 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]):
8500 self.exec_cmd('output madevent %s -f' % decay_dir,child=False)
8501
8502
8503 run_card = banner_module.RunCard(pjoin(decay_dir,'Cards','run_card.dat'))
8504 if run_card['ickkw']:
8505 run_card['ickkw'] = 0
8506 run_card['xqcut'] = 0
8507 run_card.remove_all_cut()
8508 run_card.write(pjoin(decay_dir,'Cards','run_card.dat'))
8509
8510
8511 if os.path.exists(opts['output']):
8512 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat'))
8513 else:
8514 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat'))
8515 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'):
8516 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat'))
8517
8518 me_cmd = madevent_interface.MadEventCmd(decay_dir)
8519 for name, val in self.options.items():
8520 if name in me_cmd.options and me_cmd.options[name] != val:
8521 self.exec_cmd('set %s %s --no_save' % (name, val))
8522
8523
8524
8525 me_cmd.model_name = self._curr_model['name']
8526 me_cmd.options['automatic_html_opening'] = False
8527
8528 me_opts=[('accuracy', opts['precision_channel']),
8529 ('points', 1000),
8530 ('iterations',9)]
8531 me_cmd.exec_cmd('survey decay -f %s' % (
8532 " ".join(['--%s=%s' % val for val in me_opts])),
8533 postcmd=False)
8534 me_cmd.exec_cmd('combine_events', postcmd=False)
8535
8536 me_cmd.collect_decay_widths()
8537 me_cmd.do_quit('')
8538
8539 del me_cmd
8540
8541 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat'))
8542
8543 for pid in particles:
8544 width = param['decay'].get((pid,)).value
8545 particle = self._curr_model.get_particle(pid)
8546
8547
8548
8549
8550
8551
8552 if not pid in param['decay'].decay_table:
8553 continue
8554 if pid not in decay_info:
8555 decay_info[pid] = []
8556 for BR in param['decay'].decay_table[pid]:
8557 if len(BR.lhacode) == 3 and skip_2body:
8558 continue
8559 if 0 < BR.value * width <0.1 and particle['color'] !=1:
8560 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \
8561 % (particle.get('name'), BR.value * width, BR.lhacode[1:]))
8562
8563 continue
8564
8565 decay_info[pid].append([BR.lhacode[1:], BR.value * width])
8566
8567 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info,
8568 opts['path'], opts['output'])
8569
8570 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'):
8571 check_param_card.convert_to_slha1(opts['output'])
8572 return decay_info
8573
8574
8575
8576
8578 """Compute widths with SMWidth.
8579 """
8580
8581
8582 particles, opts = self.check_compute_widths(self.split_arg(line))
8583
8584 if opts['path']:
8585 correct = True
8586 param_card = check_param_card.ParamCard(opts['path'])
8587 for param in param_card['decay']:
8588 if param.value == "auto":
8589 param.value = 1
8590 param.format = 'float'
8591 correct = False
8592 if not correct:
8593 if opts['output']:
8594 param_card.write(opts['output'])
8595 opts['path'] = opts['output']
8596 else:
8597 param_card.write(opts['path'])
8598
8599 if not model:
8600 model_path = self._curr_model.get('modelpath')
8601 model_name = self._curr_model.get('name')
8602 currmodel = self._curr_model
8603 else:
8604 model_path = model.get('modelpath')
8605 model_name = model.get('name')
8606 currmodel = model
8607
8608 if not os.path.exists(pjoin(model_path, 'SMWidth')):
8609 raise self.InvalidCmd("Model %s is not valid for computing NLO width with SMWidth"%model_name)
8610
8611
8612 externparam = [(param.lhablock.lower(),param.name.lower()) for param \
8613 in currmodel.get('parameters')[('external',)]]
8614
8615 if ('sminputs','aewm1') in externparam:
8616
8617 arg2 = "1"
8618 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam:
8619
8620 arg2 = "2"
8621 else:
8622 raise Exception("Do not know the EW scheme in the model %s"%model_name)
8623
8624
8625 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')):
8626 logger.info('Compiling SMWidth. This has to be done only once and'+\
8627 ' can take a couple of minutes.','$MG:BOLD')
8628 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth',
8629 'makefile_MW5'))
8630 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \
8631 self.options_configuration['fortran_compiler']
8632 if current != new:
8633 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current)
8634 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current)
8635 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current)
8636 misc.compile(cwd=pjoin(model_path, 'SMWidth'))
8637
8638
8639 identpath=" "
8640 carddir=os.path.dirname(opts['path'])
8641 if 'ident_card.dat' in os.listdir(carddir):
8642 identpath=pjoin(carddir,'ident_card.dat')
8643
8644 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2],
8645 stdout=subprocess.PIPE,
8646 stdin=subprocess.PIPE,
8647 cwd=pjoin(model_path, 'SMWidth')).communicate()
8648 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I)
8649 width_list = pattern.findall(output.decode())
8650 width_dict = {}
8651 for pid,width in width_list:
8652 width_dict[int(pid)] = float(width)
8653
8654 for pid in particles:
8655 if not pid in width_dict:
8656 width = 0
8657 else:
8658 width = width_dict[pid]
8659 param = param_card['decay'].get((pid,))
8660 param.value = width
8661 param.format = 'float'
8662 if pid not in param_card['decay'].decay_table:
8663 continue
8664 del param_card['decay'].decay_table[pid]
8665
8666 if opts['output']:
8667 param_card.write(opts['output'])
8668 logger.info('Results are written in %s' % opts['output'])
8669 else:
8670 param_card.write(opts['path'])
8671 logger.info('Results are written in %s' % opts['path'])
8672 return
8673
8674
8676 """Not in help: Generate amplitudes for decay width calculation, with fixed
8677 number of final particles (called level)
8678 syntax; decay_diagram part_name level param_path
8679 args; part_name level param_path
8680 part_name = name of the particle you want to calculate width
8681 level = a.) when level is int,
8682 it means the max number of decay products
8683 b.) when level is float,
8684 it means the required precision for width.
8685 param_path = path for param_card
8686 (this is necessary to determine whether a channel is onshell or not)
8687 e.g. calculate width for higgs up to 2-body decays.
8688 calculate_width h 2 [path]
8689 N.B. param_card must be given so that the program knows which channel
8690 is on shell and which is not.
8691
8692 special argument:
8693 - skip_2body: allow to not consider those decay (use FR)
8694 - model: use the model pass in argument.
8695 """
8696
8697 if model:
8698 self._curr_decaymodel = model
8699
8700
8701 args = self.split_arg(line)
8702
8703 particles, args = self.check_decay_diagram(args)
8704
8705 pids = particles
8706 level = float(args['body_decay'])
8707 param_card_path = args['path']
8708 min_br = float(args['min_br'])
8709
8710
8711 self._curr_amps = diagram_generation.AmplitudeList()
8712 self._curr_proc_defs = base_objects.ProcessDefinitionList()
8713
8714 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
8715
8716 self._done_export = False
8717
8718 self._export_format = None
8719
8720
8721
8722 if not model:
8723 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model,
8724 True)
8725 self._curr_decaymodel.read_param_card(param_card_path)
8726 else:
8727 self._curr_decaymodel = model
8728 model = self._curr_decaymodel
8729
8730 if isinstance(pids, int):
8731 pids = [pids]
8732
8733 first =True
8734 for part_nb,pid in enumerate(pids):
8735 part = self._curr_decaymodel.get_particle(pid)
8736 if part.get('width').lower() == 'zero':
8737 continue
8738 logger_mg.info('get decay diagram for %s' % part['name'])
8739
8740 if level // 1 == level and level >1:
8741 level = int(level)
8742 self._curr_decaymodel.find_channels(part, level, min_br)
8743 if not skip_2body:
8744 amp = part.get_amplitudes(2)
8745 if amp:
8746 self._curr_amps.extend(amp)
8747
8748 for l in range(3, level+1):
8749 amp = part.get_amplitudes(l)
8750 if amp:
8751 self._curr_amps.extend(amp)
8752 else:
8753 max_level = level // 1
8754 if max_level < 2:
8755 max_level = 999
8756 precision = level % 1
8757 if first:
8758 model.find_all_channels(2,generate_abstract=False)
8759 first = False
8760 if not skip_2body:
8761 amp = part.get_amplitudes(2)
8762 if amp:
8763 self._curr_amps.extend(amp)
8764 clevel = 2
8765 while part.get('apx_decaywidth_err').real > precision:
8766 clevel += 1
8767 if clevel > max_level:
8768 logger_mg.info(' stop to %s body-decay. approximate error: %s' %
8769 (max_level, part.get('apx_decaywidth_err')) )
8770 break
8771 if clevel > 3:
8772 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\
8773 (part.get('apx_decaywidth_err'), clevel))
8774 part.find_channels_nextlevel(model, min_br)
8775
8776 amp = part.get_amplitudes(clevel)
8777 if amp:
8778 self._curr_amps.extend(amp)
8779 part.update_decay_attributes(False, True, True, model)
8780
8781
8782
8783 if len(self._curr_amps) > 0:
8784 process = self._curr_amps[0]['process'].nice_string()
8785
8786 self._generate_info = process[9:]
8787
8788 else:
8789 logger.info("No decay is found")
8790
8792 """Temporary parser"""
8793
8794
8795
8796
8797
8798 _draw_usage = "draw FILEPATH [options]\n" + \
8799 "-- draw the diagrams in eps format\n" + \
8800 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \
8801 " Example: draw plot_dir . \n"
8802 _draw_parser = misc.OptionParser(usage=_draw_usage)
8803 _draw_parser.add_option("", "--horizontal", default=False,
8804 action='store_true', help="force S-channel to be horizontal")
8805 _draw_parser.add_option("", "--external", default=0, type='float',
8806 help="authorizes external particles to end at top or " + \
8807 "bottom of diagram. If bigger than zero this tune the " + \
8808 "length of those line.")
8809 _draw_parser.add_option("", "--max_size", default=1.5, type='float',
8810 help="this forbids external line bigger than max_size")
8811 _draw_parser.add_option("", "--non_propagating", default=True, \
8812 dest="contract_non_propagating", action='store_false',
8813 help="avoid contractions of non propagating lines")
8814 _draw_parser.add_option("", "--add_gap", default=0, type='float', \
8815 help="set the x-distance between external particles")
8816
8817
8818 _launch_usage = "launch [DIRPATH] [options]\n" + \
8819 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \
8820 " By default DIRPATH is the latest created directory \n" + \
8821 " (for pythia8, it should be the Pythia 8 main directory) \n" + \
8822 " Example: launch PROC_sm_1 --name=run2 \n" + \
8823 " Example: launch ../pythia8 \n"
8824 _launch_parser = misc.OptionParser(usage=_launch_usage)
8825 _launch_parser.add_option("-f", "--force", default=False, action='store_true',
8826 help="Use the card present in the directory in order to launch the different program")
8827 _launch_parser.add_option("-n", "--name", default='', type='str',
8828 help="Provide a name to the run (for madevent run)")
8829 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true',
8830 help="submit the job on the cluster")
8831 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true',
8832 help="submit the job on multicore core")
8833
8834 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true',
8835 help="Use Interactive Console [if available]")
8836 _launch_parser.add_option("-s", "--laststep", default='',
8837 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]")
8838 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true',
8839 help="Run the reweight module (reweighting by different model parameter")
8840 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true',
8841 help="Run the madspin package")
8847 """A class for asking a question where in addition you can have the
8848 set command define and modifying the param_card/run_card correctly"""
8849
8850 - def __init__(self, question, allow_arg=[], default=None,
8851 mother_interface=None, *arg, **opt):
8852
8853 model_path = mother_interface._curr_model.get('modelpath')
8854
8855 ufo_model = ufomodels.load_model(model_path)
8856 self.all_categories = ufo_model.build_restrict.all_categories
8857
8858 question = self.get_question()
8859
8860
8861 allow_arg = ['0']
8862 self.name2options = {}
8863 for category in self.all_categories:
8864 for options in category:
8865 if not options.first:
8866 continue
8867 self.name2options[str(len(allow_arg))] = options
8868 self.name2options[options.name.replace(' ','')] = options
8869 allow_arg.append(len(allow_arg))
8870 allow_arg.append('done')
8871
8872 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8873
8874
8875
8877 """Default action if line is not recognized"""
8878
8879 line = line.strip()
8880 args = line.split()
8881 if line == '' and self.default_value is not None:
8882 self.value = self.default_value
8883
8884 elif hasattr(self, 'do_%s' % args[0]):
8885 self.do_set(' '.join(args[1:]))
8886 elif line.strip() != '0' and line.strip() != 'done' and \
8887 str(line) != 'EOF' and line.strip() in self.allow_arg:
8888 option = self.name2options[line.strip()]
8889 option.status = not option.status
8890 self.value = 'repeat'
8891 else:
8892 self.value = line
8893
8894 return self.all_categories
8895
8896 - def reask(self, reprint_opt=True):
8901
8903 """ """
8904 self.value = 'repeat'
8905
8906 args = line.split()
8907 if args[0] not in self.name2options:
8908 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' %
8909 (args[0], ', '.join(list(self.name2options.keys())) ))
8910 return
8911 elif len(args) != 2:
8912 logger.warning('Invalid set command. Not correct number of argument')
8913 return
8914
8915
8916 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']:
8917 self.name2options[args[0]].status = True
8918 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']:
8919 self.name2options[args[0]].status = False
8920 else:
8921 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8922
8923
8924
8926 """define the current question."""
8927 question = ''
8928 i=0
8929 for category in self.all_categories:
8930 question += category.name + ':\n'
8931 for options in category:
8932 if not options.first:
8933 continue
8934 i+=1
8935 question += ' %s: %s [%s]\n' % (i, options.name,
8936 options.display(options.status))
8937 question += 'Enter a number to change it\'s status or press enter to validate.\n'
8938 question += 'For scripting this function, please type: \'help\''
8939 return question
8940
8941
8943 """ Complete the set command"""
8944 signal.alarm(0)
8945 args = self.split_arg(line[0:begidx])
8946
8947 if len(args) == 1:
8948 possibilities = [x for x in self.name2options if not x.isdigit()]
8949 return self.list_completion(text, possibilities, line)
8950 else:
8951 return self.list_completion(text,['True', 'False'], line)
8952
8953
8955 '''help message'''
8956
8957 print('This allows you to optimize your model to your needs.')
8958 print('Enter the number associate to the possible restriction/add-on')
8959 print(' to change the status of this restriction/add-on.')
8960 print('')
8961 print('In order to allow scripting of this function you can use the ')
8962 print('function \'set\'. This function takes two argument:')
8963 print('set NAME VALUE')
8964 print(' NAME is the description of the option where you remove all spaces')
8965 print(' VALUE is either True or False')
8966 print(' Example: For the question')
8967 print(''' sm customization:
8968 1: diagonal ckm [True]
8969 2: c mass = 0 [True]
8970 3: b mass = 0 [False]
8971 4: tau mass = 0 [False]
8972 5: muon mass = 0 [True]
8973 6: electron mass = 0 [True]
8974 Enter a number to change it's status or press enter to validate.''')
8975 print(''' you can answer by''')
8976 print(' set diagonalckm False')
8977 print(' set taumass=0 True')
8978
8982
8983
8984
8985
8986
8987
8988
8989 if __name__ == '__main__':
8990
8991 run_option = sys.argv
8992 if len(run_option) > 1:
8993
8994 input_file = open(run_option[1], 'rU')
8995 cmd_line = MadGraphCmd(stdin=input_file)
8996 cmd_line.use_rawinput = False
8997 cmd_line.cmdloop()
8998 else:
8999
9000 MadGraphCmd().cmdloop()
9001