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