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