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