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