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