Package madgraph :: Package interface :: Module madgraph_interface
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.madgraph_interface

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2009 The MadGraph5_aMC@NLO Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph5_aMC@NLO project, an application which 
   6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
   7  # high-energy processes in the Standard Model and beyond. 
   8  # 
   9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this 
  10  # distribution. 
  11  # 
  12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
  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  #useful shortcut 
  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  # Special logger for the Cmd Interface 
 110  logger = logging.getLogger('cmdprint') # -> stdout 
 111  logger_check = logging.getLogger('check') # -> stdout 
 112  logger_mg = logging.getLogger('madgraph.interface') # -> stdout 
 113  logger_stderr = logging.getLogger('fatalerror') # ->stderr 
 114  logger_tuto = logging.getLogger('tutorial') # -> stdout include instruction in 
 115                                              #order to learn MG5 
 116  logger_tuto_nlo = logging.getLogger('tutorial_aMCatNLO') # -> stdout include instruction in 
 117                                                          #order to learn aMC@NLO 
 118   
 119  logger_tuto_madloop = logging.getLogger('tutorial_MadLoop') # -> stoud for MadLoop tuto 
120 121 #=============================================================================== 122 # CmdExtended 123 #=============================================================================== 124 -class CmdExtended(cmd.Cmd):
125 """Particularisation of the cmd command for MG5""" 126 127 #suggested list of command 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 # Define the Error Class # Define how error are handle 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
185 - def __init__(self, *arg, **opt):
186 """Init history and line continuation""" 187 188 # If possible, build an info line with current version number 189 # and date, from the VERSION text file 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 # Create a header for the history file. 227 # Remember to fill in time at writeout time! 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
242 - def default(self, line):
243 """Default action if line is not recognized""" 244 245 # Faulty command 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 # Print additional information in case of routines fails 260 if stop == False: 261 return False 262 263 args=line.split() 264 # Return for empty line 265 if len(args)==0: 266 return stop 267 268 # try to print linked to the first word in command 269 #as import_model,... if you don't find then try print with only 270 #the first word. 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
303 - def get_history_header(self):
304 """return the history header""" 305 return self.history_header % misc.get_time_info()
306
307 #=============================================================================== 308 # HelpToCmd 309 #=============================================================================== 310 -class HelpToCmd(cmd.HelpCmd):
311 """ The Series of help routine for the MadGraphCmd""" 312
313 - def help_save(self):
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
323 - def help_load(self):
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
327 - def help_import(self):
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
360 - def help_install(self):
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
380 - def help_display(self):
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
391 - def help_launch(self):
392 """help for launch command""" 393 # Using the built-in parser help is not convenient when one wants to use 394 # color schemes. 395 #_launch_parser.print_help() 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
428 - def help_tutorial(self):
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
434 - def help_open(self):
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
442 - def help_customize_model(self):
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
448 - def help_output(self):
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
489 - def help_check(self):
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
585 - def help_generate(self):
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
627 - def help_add(self):
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
675 - def help_convert(self):
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
679 - def help_compute_widths(self):
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
705 - def help_decay_diagram(self):
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
729 - def help_define(self):
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
736 - def help_set(self):
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
827 #=============================================================================== 828 # CheckValidForCmd 829 #=============================================================================== 830 -class CheckValidForCmd(cmd.CheckCmd):
831 """ The Series of help routine for the MadGraphCmd""" 832
833 - class RWError(MadGraph5Error):
834 """a class for read/write errors"""
835
836 - def check_add(self, args):
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
855 - def check_define(self, args):
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
882 - def check_display(self, args):
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 # check that either _curr_amps or _fks_multi_proc exists 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
907 - def check_draw(self, args):
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
921 - def check_check(self, args):
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 # If the first argument after 'stability' is not the integer 954 # specifying the desired statistics (i.e. number of points), then 955 # we insert the default value 100 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 # increase the default energy to 5000 977 user_options['--energy']='5000' 978 # The first argument gives the name of the coupling order in which 979 # the cms expansion is carried, and the expression following the 980 # comma gives the relation of an external parameter with the 981 # CMS expansions parameter called 'lambdaCMS'. 982 parameters = ['aewm1->10.0/lambdaCMS','as->0.1*lambdaCMS'] 983 user_options['--cms']='QED&QCD,'+'&'.join(parameters) 984 # Widths are assumed to scale linearly with lambdaCMS unless 985 # --force_recompute_width='always' or 'first_time' is used. 986 user_options['--recompute_width']='auto' 987 # It can be negative so as to be offshell below the resonant mass 988 user_options['--offshellness']='10.0' 989 # Pick the lambdaCMS values for the test. Instead of a python list 990 # we specify here (low,N) which means that do_check will automatically 991 # pick lambda values up to the value low and with N values uniformly 992 # spread in each interval [1.0e-i,1.0e-(i+1)]. 993 # Some points close to each other will be added at the end for the 994 # stability test. 995 user_options['--lambdaCMS']='(1.0e-6,5)' 996 # Set the RNG seed, -1 is default (random). 997 user_options['--seed']=666 998 # The option below can help the user re-analyze existing pickled check 999 user_options['--analyze']='None' 1000 # Decides whether to show plot or not during the analysis 1001 user_options['--show_plot']='True' 1002 # Decides what kind of report 1003 user_options['--report']='concise' 1004 # 'secret' option to chose by which lambda power one should divide 1005 # the nwa-cms difference. Useful to set to 2 when doing the Born check 1006 # to see whether the NLO check will have sensitivity to the CMS 1007 # implementation 1008 user_options['--diff_lambda_power']='1' 1009 # Sets the range of lambda values to plot 1010 user_options['--lambda_plot_range']='[-1.0,-1.0]' 1011 # Sets a filter to apply at generation. See name of available 1012 # filters in loop_diagram_generations.py, function user_filter 1013 user_options['--loop_filter']='None' 1014 # Apply tweaks to the check like multiplying a certain width by a 1015 # certain parameters or changing the analytical continuation of the 1016 # logarithms of the UV counterterms 1017 user_options['--tweak']='default()' 1018 # Give a name to the run for the files to be saved 1019 user_options['--name']='auto' 1020 # Select what resonances must be run 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 # If we are just re-analyzing saved data or displaying options then we 1033 # shouldn't check the process format. 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
1045 - def check_generate(self, args):
1046 """check the validity of args""" 1047 1048 if not self._curr_model: 1049 logger.info("No model currently active, so we import the Standard Model") 1050 self.do_import('model sm') 1051 1052 if args[-1].startswith('--optimize'): 1053 if args[2] != '>': 1054 raise self.InvalidCmd('optimize mode valid only for 1->N processes. (See model restriction for 2->N)') 1055 if '=' in args[-1]: 1056 path = args[-1].split('=',1)[1] 1057 if not os.path.exists(path) or \ 1058 self.detect_file_type(path) != 'param_card': 1059 raise self.InvalidCmd('%s is not a valid param_card') 1060 else: 1061 path=None 1062 # Update the default value of the model here. 1063 if not isinstance(self._curr_model, model_reader.ModelReader): 1064 self._curr_model = model_reader.ModelReader(self._curr_model) 1065 self._curr_model.set_parameters_and_couplings(path) 1066 self.check_process_format(' '.join(args[1:-1])) 1067 else: 1068 self.check_process_format(' '.join(args[1:]))
1069 1070
1071 - def check_process_format(self, process):
1072 """ check the validity of the string given to describe a format """ 1073 1074 #check balance of paranthesis 1075 if process.count('(') != process.count(')'): 1076 raise self.InvalidCmd('Invalid Format, no balance between open and close parenthesis') 1077 #remove parenthesis for fututre introspection 1078 process = process.replace('(',' ').replace(')',' ') 1079 1080 # split following , (for decay chains) 1081 subprocesses = process.split(',') 1082 if len(subprocesses) > 1: 1083 for subprocess in subprocesses: 1084 self.check_process_format(subprocess) 1085 return 1086 1087 # request that we have one or two > in the process 1088 nbsep = len(re.findall('>\D', process)) # not use process.count because of QCD^2>2 1089 if nbsep not in [1,2]: 1090 raise self.InvalidCmd( 1091 'wrong format for \"%s\" this part requires one or two symbols \'>\', %s found' 1092 % (process, nbsep)) 1093 1094 # we need at least one particles in each pieces 1095 particles_parts = re.split('>\D', process) 1096 for particles in particles_parts: 1097 if re.match(r'^\s*$', particles): 1098 raise self.InvalidCmd( 1099 '\"%s\" is a wrong process format. Please try again' % process) 1100 1101 # '/' and '$' sould be used only after the process definition 1102 for particles in particles_parts[:-1]: 1103 if re.search('\D/', particles): 1104 raise self.InvalidCmd( 1105 'wrong process format: restriction should be place after the final states') 1106 if re.search('\D\$', particles): 1107 raise self.InvalidCmd( 1108 'wrong process format: restriction should be place after the final states') 1109 1110 # '{}' should only be used for onshell particle (including initial/final state) 1111 # check first that polarization are not include between > > 1112 if nbsep == 2: 1113 if '{' in particles_parts[1]: 1114 raise self.InvalidCmd('Polarization restriction can not be used as required s-channel') 1115 split = re.split('\D[$|/]',particles_parts[-1],1) 1116 if len(split)==2: 1117 if '{' in split[1]: 1118 raise self.InvalidCmd('Polarization restriction can not be used in forbidding particles') 1119 1120 if '[' in process and '{' in process: 1121 valid = False 1122 if 'noborn' in process or 'sqrvirt' in process: 1123 valid = True 1124 else: 1125 raise self.InvalidCmd('Polarization restriction can not be used for NLO processes') 1126 1127 # below are the check when [QCD] will be valid for computation 1128 order = process.split('[')[1].split(']')[0] 1129 if '=' in order: 1130 order = order.split('=')[1] 1131 if order.strip().lower() != 'qcd': 1132 raise self.InvalidCmd('Polarization restriction can not be used for generic NLO computations') 1133 1134 1135 for p in particles_parts[1].split(): 1136 if '{' in p: 1137 part = p.split('{')[0] 1138 else: 1139 continue 1140 if self._curr_model: 1141 p = self._curr_model.get_particle(part) 1142 if not p: 1143 if part in self._multiparticles: 1144 for part2 in self._multiparticles[part]: 1145 p = self._curr_model.get_particle(part2) 1146 if p.get('color') != 1: 1147 raise self.InvalidCmd('Polarization restriction can not be used for color charged particles') 1148 continue 1149 if p.get('color') != 1: 1150 raise self.InvalidCmd('Polarization restriction can not be used for color charged particles')
1151 1152 1153
1154 - def check_tutorial(self, args):
1155 """check the validity of the line""" 1156 if len(args) == 1: 1157 if not args[0] in self._tutorial_opts: 1158 self.help_tutorial() 1159 raise self.InvalidCmd('Invalid argument for tutorial') 1160 elif len(args) == 0: 1161 #this means mg5 tutorial 1162 args.append('MadGraph5') 1163 else: 1164 self.help_tutorial() 1165 raise self.InvalidCmd('Too many arguments for tutorial')
1166 1167 1168
1169 - def check_import(self, args):
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 # finding last created directory 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 # The type of the import is not given -> guess it 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
1237 - def check_install(self, args):
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 # Options related to the MadGraph installer can be treated here, i.e 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 # Other options will be directly added to the call to HEPToolsInstallers 1264 # in the advanced_install function 1265 install_options['options_for_HEPToolsInstaller'].append(arg) 1266 # Now that the options have been treated keep only the target tool 1267 # to install as argument. 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
1294 - def check_launch(self, args, options):
1295 """check the validity of the line""" 1296 # modify args in order to be MODE DIR 1297 # mode being either standalone or madevent 1298 if not( 0 <= int(options.cluster) <= 2): 1299 return self.InvalidCmd( 'cluster mode should be between 0 and 2') 1300 1301 if not args: 1302 if self._done_export: 1303 mode = self.find_output_type(self._done_export[0]) 1304 if (self._done_export[1] == 'plugin' and mode in self._export_formats): 1305 args.append(mode) 1306 args.append(self._done_export[0]) 1307 elif self._done_export[1].startswith(mode): 1308 args.append(self._done_export[1]) 1309 args.append(self._done_export[0]) 1310 else: 1311 raise self.InvalidCmd('%s not valid directory for launch' % self._done_export[0]) 1312 return 1313 else: 1314 logger.warning('output command missing, run it automatically (with default argument)') 1315 self.do_output('') 1316 logger.warning('output done: running launch') 1317 return self.check_launch(args, options) 1318 1319 if len(args) != 1: 1320 self.help_launch() 1321 return self.InvalidCmd( 'Invalid Syntax: Too many argument') 1322 1323 # search for a valid path 1324 if os.path.isdir(args[0]): 1325 path = os.path.realpath(args[0]) 1326 elif os.path.isdir(pjoin(MG5DIR,args[0])): 1327 path = pjoin(MG5DIR,args[0]) 1328 elif MG4DIR and os.path.isdir(pjoin(MG4DIR,args[0])): 1329 path = pjoin(MG4DIR,args[0]) 1330 else: 1331 raise self.InvalidCmd('%s is not a valid directory' % args[0]) 1332 1333 mode = self.find_output_type(path) 1334 1335 args[0] = mode 1336 args.append(path) 1337 # inform where we are for future command 1338 self._done_export = [path, mode]
1339 1340
1341 - def find_import_type(self, path):
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 # Check if they are a valid directory 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 # Not valid directory so maybe a file 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
1377 - def find_output_type(self, path):
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
1407 - def check_load(self, args):
1408 """ check the validity of the line""" 1409 1410 if len(args) != 2 or args[0] not in self._save_opts: 1411 self.help_load() 1412 raise self.InvalidCmd('wrong \"load\" format')
1413
1414 - def check_customize_model(self, args):
1415 """check the validity of the line""" 1416 1417 # Check argument validity 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
1433 - def check_save(self, args):
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
1481 - def check_set(self, args, log=True):
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 #else: 1549 # raise Exception('python3.x does not support such functionalities please use python2.7') 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
1578 - def check_open(self, args):
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 # if special : create the path. 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 # special for card with _default define: copy the default and open it 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
1617 - def check_output(self, args, default='madevent'):
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 # check for PLUGIN format 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 # This is a path 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 # Check for special directory treatment 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 # No valid path 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
1697 - def check_compute_widths(self, args):
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 # check that the firsts argument is valid 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 # check for pid 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 #sometimes the multiparticle all is not define 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 # check that the path is indeed a param_card: 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
1787 - def get_default_path(self):
1788 """Set self._export_dir to the default (\'auto\') path""" 1789 1790 if self._export_format in ['madevent', 'standalone']: 1791 # Detect if this script is launched from a valid copy of the Template, 1792 # if so store this position as standard output directory 1793 if 'TemplateVersion.txt' in os.listdir('.'): 1794 #Check for ./ 1795 self._export_dir = os.path.realpath('.') 1796 return 1797 elif 'TemplateVersion.txt' in os.listdir('..'): 1798 #Check for ../ 1799 self._export_dir = os.path.realpath('..') 1800 return 1801 elif self.stdin != sys.stdin: 1802 #Check for position defined by the input files 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
1865 1866 #=============================================================================== 1867 # CheckValidForCmdWeb 1868 #=============================================================================== 1869 -class CheckValidForCmdWeb(CheckValidForCmd):
1870 """ Check the validity of input line for web entry 1871 (no explicit path authorized)""" 1872
1873 - class WebRestriction(MadGraph5Error):
1874 """class for WebRestriction"""
1875
1876 - def check_draw(self, args):
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
1882 - def check_display(self, args):
1883 """ check the validity of line in web mode """ 1884 1885 if args[0] == 'mg5_variable': 1886 raise self.WebRestriction('Display internal variable is forbidden on the web') 1887 1888 CheckValidForCmd.check_history(self, args)
1889
1890 - def check_check(self, args):
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
1905 - def check_import(self, args):
1906 """check the validity of line 1907 No Path authorize for the Web""" 1908 1909 if not args: 1910 raise self.WebRestriction('import requires at least one option') 1911 1912 if args[0] not in self._import_formats: 1913 args[:] = ['command', './proc_card_mg5.dat'] 1914 elif args[0] == 'proc_v4': 1915 args[:] = [args[0], './proc_card.dat'] 1916 elif args[0] == 'command': 1917 args[:] = [args[0], './proc_card_mg5.dat'] 1918 1919 CheckValidForCmd.check_import(self, args)
1920
1921 - def check_install(self, args):
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
1928 - def check_load(self, args):
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
1943 - def check_save(self, args):
1944 """ not authorize on web""" 1945 raise self.WebRestriction('\"save\" command not authorize online')
1946
1947 - def check_open(self, args):
1948 """ not authorize on web""" 1949 raise self.WebRestriction('\"open\" command not authorize online')
1950
1951 - def check_output(self, args, default='madevent'):
1952 """ check the validity of the line""" 1953 1954 # first pass to the default 1955 CheckValidForCmd.check_output(self, args, default=default) 1956 args[:] = ['.', '-f'] 1957 1958 self._export_dir = os.path.realpath(os.getcwd()) 1959 # Check that we output madevent 1960 if 'madevent' != self._export_format: 1961 raise self.WebRestriction('only available output format is madevent (at current stage)')
1962
1963 #=============================================================================== 1964 # CompleteForCmd 1965 #=============================================================================== 1966 -class CompleteForCmd(cmd.CompleteCmd):
1967 """ The Series of help routine for the MadGraphCmd""" 1968 1969
1970 - def nlo_completion(self,args,text,line,allowed_loop_mode=None):
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 # We are now editing the loop related options 1976 # Automatically allow for QCD perturbation if in the sm because the 1977 # loop_sm would then automatically be loaded 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 # Find wether the loop mode is already set or not 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 # Simplify obvious loop completion 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 # Automatically add a space if not present after [ or = 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 # First check if we are within squared brackets so that specific 2038 # input for NLO settings must be completed 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 # Do no complete the @ for the process number. 2050 if len(args) > 1 and args[-1]=='@': 2051 return 2052 2053 # Automatically allow for QCD perturbation if in the sm because the 2054 # loop_sm would then automatically be loaded 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 # Remove possible identical names 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 # Force '>' if two initial particles. 2067 if n_part_entered == 2 and args[-1] != '>': 2068 return self.list_completion(text, '>') 2069 2070 # Add non-particle names 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 # If information for the virtuals has been specified already, do not 2083 # propose syntax or particles input anymore 2084 if '[' in line: 2085 syntax = [] 2086 particles = [] 2087 # But still allow for defining the process id 2088 couplings.append('@') 2089 2090 if not categories: 2091 # The direct completion (might be needed for some completion using 2092 # this function but adding some other completions (like in check)). 2093 # For those, it looks ok in the categorie mode on my mac, but if 2094 # someone sees wierd result on Linux systems, then use the 2095 # default completion for these features. 2096 return self.list_completion(text, particles+syntax+couplings) 2097 else: 2098 # A more elaborate one with categories 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
2111 - def complete_generate(self, text, line, begidx, endidx, formatting=True):
2112 "Complete the generate command" 2113 2114 # Return list of particle names and multiparticle names, as well as 2115 # coupling orders and allowed symbols 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 #if len(args) > 1 and args[-1] != '>': 2142 # couplings = ['>'] 2143 #if '>' in args and args.index('>') < len(args) - 1: 2144 # couplings = [c + "=" for c in self._couplings] + ['@','$','/','>'] 2145 #return self.list_completion(text, self._particle_names + \ 2146 # self._multiparticles.keys() + couplings) 2147
2148 - def complete_convert(self, text, line, begidx, endidx,formatting=True):
2149 "Complete the compute_widths command" 2150 2151 args = self.split_arg(line[0:begidx]) 2152 2153 # Format 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
2163 - def complete_compute_widths(self, text, line, begidx, endidx,formatting=True):
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 # Format 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
2206 - def complete_customize_model(self, text, line, begidx, endidx):
2207 "Complete the customize_model command" 2208 2209 args = self.split_arg(line[0:begidx]) 2210 2211 # Format 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 # Format 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 # Directory continuation 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 # autocompletion for particles/couplings 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 #Special rules for check cms completion 2253 if cms_check_mode: 2254 # A couple of useful value completions 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 # ['%d: %s'%(i+1,ex) for i, ex in enumerate(example)]}, 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
2331 - def complete_tutorial(self, text, line, begidx, endidx):
2332 "Complete the tutorial command" 2333 2334 # Format 2335 if len(self.split_arg(line[0:begidx])) == 1: 2336 return self.list_completion(text, self._tutorial_opts)
2337
2338 - def complete_define(self, text, line, begidx, endidx):
2339 """Complete particle information""" 2340 return self.model_completion(text, line[6:],line)
2341
2342 - def complete_display(self, text, line, begidx, endidx):
2343 "Complete the display command" 2344 2345 args = self.split_arg(line[0:begidx]) 2346 # Format 2347 if len(args) == 1: 2348 return self.list_completion(text, self._display_opts) 2349 2350 if len(args) == 2 and args[1] == 'checks': 2351 return self.list_completion(text, ['failed']) 2352 2353 if len(args) == 2 and args[1] == 'particles': 2354 return self.model_completion(text, line[begidx:],line)
2355
2356 - def complete_draw(self, text, line, begidx, endidx):
2357 "Complete the draw command" 2358 2359 args = self.split_arg(line[0:begidx]) 2360 2361 # Directory continuation 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 # Format 2367 if len(args) == 1: 2368 return self.path_completion(text, '.', only_dirs = True) 2369 2370 2371 #option 2372 if len(args) >= 2: 2373 opt = ['horizontal', 'external=', 'max_size=', 'add_gap=', 2374 'non_propagating', '--'] 2375 return self.list_completion(text, opt)
2376
2377 - def complete_launch(self, text, line, begidx, endidx,formatting=True):
2378 """ complete the launch command""" 2379 args = self.split_arg(line[0:begidx]) 2380 2381 # Directory continuation 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 # Format 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 #option 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
2413 - def complete_load(self, text, line, begidx, endidx):
2414 "Complete the load command" 2415 2416 args = self.split_arg(line[0:begidx]) 2417 2418 # Format 2419 if len(args) == 1: 2420 return self.list_completion(text, self._save_opts) 2421 2422 # Directory continuation 2423 if args[-1].endswith(os.path.sep): 2424 return self.path_completion(text, 2425 pjoin(*[a for a in args if \ 2426 a.endswith(os.path.sep)])) 2427 2428 # Filename if directory is not given 2429 if len(args) == 2: 2430 return self.path_completion(text)
2431
2432 - def complete_save(self, text, line, begidx, endidx):
2433 "Complete the save command" 2434 2435 args = self.split_arg(line[0:begidx]) 2436 2437 # Format 2438 if len(args) == 1: 2439 return self.list_completion(text, self._save_opts) 2440 2441 # Directory continuation 2442 if args[-1].endswith(os.path.sep): 2443 return self.path_completion(text, 2444 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2445 only_dirs = True) 2446 2447 # Filename if directory is not given 2448 if len(args) == 2: 2449 return self.path_completion(text) + self.list_completion(text, ['global'])
2450 2451 @cmd.debug()
2452 - def complete_open(self, text, line, begidx, endidx):
2453 """ complete the open command """ 2454 2455 args = self.split_arg(line[0:begidx]) 2456 2457 # Directory continuation 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 #don't propose directory use by MG_ME 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 #name of the run =>proposes old run name 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 # Directory continuation 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 # options 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 # Formats 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 # directory names 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
2534 - def aloha_complete_output(self, text, line, begidx, endidx,formatting=True):
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 # options 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 # Directory continuation 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
2575 - def complete_set(self, text, line, begidx, endidx):
2576 "Complete the set command" 2577 #misc.sprint([text,line,begidx, endidx]) 2578 args = self.split_arg(line[0:begidx]) 2579 2580 # Format 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 # directory names 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 # Format 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 # restriction continuation (for UFO) 2648 if mode in ['model', 'all'] and '-' in text: 2649 # deal with - in readline splitting (different on some computer) 2650 path = '-'.join([part for part in text.split('-')[:-1]]) 2651 # remove the final - for the model name 2652 # find the different possibilities 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 # select the possibility according to the current line 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 # Path continuation 2673 if os.path.sep in args[-1]: 2674 if mode.startswith('model') or mode == 'all': 2675 # Directory continuation 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 # Only UFO model here 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 # Model directory name if directory is not given 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 # need to update the list with the possible restriction 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 #avoid duplication 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 # Options 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 = [] # fill by model on the db if user do "display modellist" 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 # check if the model_name should be keeped as a possibility 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 # check that the model is a valid model 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 # not valid UFO model 2827 return output 2828 2829 if model_name.endswith(os.path.sep): 2830 model_name = model_name[:-1] 2831 2832 # look for _default and treat this case 2833 if os.path.exists(pjoin(base_dir, model_name, 'restrict_default.dat')): 2834 output.append('%s-full' % model_name) 2835 2836 # look for other restrict_file 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] #remove restrict and .dat 2841 while model_name.endswith(os.path.sep): 2842 model_name = model_name[:-1] 2843 output.append('%s-%s' % (model_name, tag)) 2844 2845 # return 2846 return output
2847
2848 - def complete_install(self, text, line, begidx, endidx):
2849 "Complete the import command" 2850 2851 args = self.split_arg(line[0:begidx]) 2852 # Format 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 #options.append('--no_MA5_further_install') 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 # MadGraphCmd 2881 #=============================================================================== 2882 -class MadGraphCmd(HelpToCmd, CheckValidForCmd, CompleteForCmd, CmdExtended):
2883 """The command line processor of MadGraph""" 2884 2885 writing_dir = '.' 2886 2887 # Options and formats available 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 # The targets below are installed using the HEPToolsInstaller.py script 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 # The three options categories are treated on a different footage when a 2936 # set/save configuration occur. current value are kept in self.options 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, # 0 means automaticly adapted 2993 'default_unset_couplings': 99, # 99 means infinity 2994 'max_t_for_channel': 99, # means no restrictions 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 # Variables to store object information 3007 _curr_model = None #base_objects.Model() 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
3019 - def preloop(self):
3020 """Initializing before starting the main loop""" 3021 3022 self.prompt = 'MG5_aMC>' 3023 if madgraph.ReadWrite: # prevent on read-only disk 3024 self.do_install('update --mode=mg5_start') 3025 3026 # By default, load the UFO Standard Model 3027 logger.info("Loading default model: sm") 3028 self.exec_cmd('import model sm', printcmd=False, precmd=True) 3029 3030 # preloop mother 3031 CmdExtended.preloop(self)
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 # Set MG/ME directory path 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 # check that make_opts exists 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 # Variables to store state information 3058 self._multiparticles = {} 3059 self.options = {} 3060 self._generate_info = "" # store the first generated process 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 # Load the configuration file,i.e.mg5_configuration.txt 3072 self.set_configuration()
3073
3074 - def setup(self):
3075 """ Actions to carry when switching to this interface """ 3076 3077 # Refresh all the interface stored value as things like generated 3078 # processes and amplitudes are not to be reused in between different 3079 # interfaces 3080 # Clear history, amplitudes and matrix elements when a model is imported 3081 # Remove previous imports, generations and outputs from history 3082 self.history.clean(remove_bef_last='import',keep_switch=True) 3083 # Reset amplitudes and matrix elements 3084 self._done_export=False 3085 self._curr_amps = diagram_generation.AmplitudeList() 3086 self._curr_proc_defs = base_objects.ProcessDefinitionList() 3087 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 3088 3089 self._v4_export_formats = ['madevent', 'standalone','standalone_msP','standalone_msF', 3090 'matrix', 'standalone_rw'] 3091 self._export_formats = self._v4_export_formats + ['standalone_cpp', 'pythia8'] 3092 self._nlo_modes_for_completion = ['all','virt','real']
3093
3094 - def do_quit(self, line):
3095 """Not in help: Do quit""" 3096 3097 if self._done_export and \ 3098 os.path.exists(pjoin(self._done_export[0],'RunWeb')): 3099 os.remove(pjoin(self._done_export[0],'RunWeb')) 3100 3101 value = super(MadGraphCmd, self).do_quit(line) 3102 if madgraph.ReadWrite: #prevent to run on Read Only disk 3103 self.do_install('update --mode=mg5_end') 3104 misc.EasterEgg('quit') 3105 3106 3107 return value
3108 3109 # Add a process to the existing multiprocess definition 3110 # Generate a new amplitude
3111 - def do_add(self, line):
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 # Check the validity of the arguments 3136 self.check_add(args) 3137 3138 if args[0] == 'model': 3139 return self.add_model(args[1:]) 3140 3141 # special option for 1->N to avoid generation of kinematically forbidden 3142 #decay. 3143 if args[-1].startswith('--optimize'): 3144 optimize = True 3145 args.pop() 3146 else: 3147 optimize = False 3148 3149 if args[0] == 'process': 3150 # Rejoin line 3151 line = ' '.join(args[1:]) 3152 3153 # store the first process (for the perl script) 3154 if not self._generate_info: 3155 self._generate_info = line 3156 3157 # Reset Helas matrix elements 3158 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 3159 3160 # Extract process from process definition 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 # Redundant with above, but not completely as in the future 3173 # one might think of allowing the core process to be 3174 # corrected by loops. 3175 if myprocdef.are_decays_perturbed(): 3176 raise MadGraph5Error("Decay processes cannot be perturbed.") 3177 # The two limitations below have some redundancy, but once 3178 # again, they might be relieved (one at a time or together) 3179 # int he future. 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 # Check that we have something 3194 if not myprocdef: 3195 raise self.InvalidCmd("Empty or wrong format process, please try again.") 3196 # Check that we have the same number of initial states as 3197 # existing processes 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 #Check that we do not have situation like z{T} z 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 # Negative coupling order contraints can be given on at most one 3220 # coupling order (and either in squared orders or orders, not both) 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 # Generate processes 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 # Reset _done_export, since we have new process 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
3279 - def add_model(self, args):
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 #Need to do the work!!! 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
3346 - def do_convert(self, line):
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
3355 - def do_convert_model(self, args):
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 #Object_library 3370 text = open(pjoin(model_dir, 'object_library.py')).read() 3371 #(.iteritems() -> .items()) 3372 text = text.replace('.iteritems()', '.items()') 3373 # raise UFOError, "" -> raise UFOError() 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 # write_param_card.dat -> copy the one of the sm model 3379 files.cp(pjoin(MG5DIR, 'models','sm','write_param_card.py'), 3380 pjoin(model_dir, 'write_param_card.py')) 3381 3382 # __init__.py check that function_library and object_library are imported 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 # Define a multiparticle label
3399 - def do_define(self, line, log=True):
3400 """Define a multiparticle""" 3401 3402 self.avoid_history_duplicate('define %s' % line, ['define']) 3403 if not self._curr_model: 3404 self.do_import('model sm') 3405 self.history.append('define %s' % line) 3406 if not self._curr_model['case_sensitive']: 3407 # Particle names lowercase 3408 line = line.lower() 3409 # Make sure there are spaces around =, | and / 3410 line = line.replace("=", " = ") 3411 line = line.replace("|", " | ") 3412 line = line.replace("/", " / ") 3413 args = self.split_arg(line) 3414 # check the validity of the arguments 3415 self.check_define(args) 3416 3417 label = args[0] 3418 remove_ids = [] 3419 try: 3420 remove_index = args.index("/") 3421 except ValueError: 3422 pass 3423 else: 3424 remove_ids = args[remove_index + 1:] 3425 args = args[:remove_index] 3426 3427 pdg_list = self.extract_particle_ids(args[1:]) 3428 remove_list = self.extract_particle_ids(remove_ids) 3429 pdg_list = [p for p in pdg_list if p not in remove_list] 3430 3431 self.optimize_order(pdg_list) 3432 self._multiparticles[label] = pdg_list 3433 if log: 3434 logger.info("Defined multiparticle %s" % \ 3435 self.multiparticle_string(label))
3436 3437 # Display
3438 - def do_display(self, line, output=sys.stdout):
3439 """Display current internal status""" 3440 3441 args = self.split_arg(line) 3442 #check the validity of the arguments 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 # check that all particles are selected at least once 3522 if set(present_part) != set(request_part): 3523 continue 3524 # check if a particle is asked more than once 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 #self._curr_model.get_order_hierarchy().items() 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 #local model #use 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 # Still have to add the one with internal information 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 # other downloadable model 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
3849 - def do_tutorial(self, line):
3850 """Activate/deactivate the tutorial mode.""" 3851 3852 args = self.split_arg(line) 3853 self.check_tutorial(args) 3854 tutorials = {'MadGraph5': logger_tuto, 3855 'aMCatNLO': logger_tuto_nlo, 3856 'MadLoop': logger_tuto_madloop} 3857 try: 3858 tutorials[args[0]].setLevel(logging.INFO) 3859 for mode in [m for m in tutorials.keys() if m != args[0]]: 3860 tutorials[mode].setLevel(logging.ERROR) 3861 except KeyError: 3862 logger_tuto.info("\n\tThanks for using the tutorial!") 3863 logger_tuto.setLevel(logging.ERROR) 3864 logger_tuto_nlo.info("\n\tThanks for using the aMC@NLO tutorial!") 3865 logger_tuto_nlo.setLevel(logging.ERROR) 3866 logger_tuto_madloop.info("\n\tThanks for using MadLoop tutorial!") 3867 logger_tuto_madloop.setLevel(logging.ERROR) 3868 3869 if not self._mgme_dir: 3870 logger_tuto.info(\ 3871 "\n\tWarning: To use all features in this tutorial, " + \ 3872 "please run from a" + \ 3873 "\n\t valid MG_ME directory.")
3874 3875 3876
3877 - def draw(self, line,selection='all',Dtype=''):
3878 """ draw the Feynman diagram for the given process. 3879 Dtype refers to born, real or loop""" 3880 3881 args = self.split_arg(line) 3882 # Check the validity of the arguments 3883 self.check_draw(args) 3884 3885 # Check if we plot a decay chain 3886 if any([isinstance(a, diagram_generation.DecayChainAmplitude) for \ 3887 a in self._curr_amps]) and not self._done_export: 3888 warn = 'WARNING: You try to draw decay chain diagrams without first running output.\n' 3889 warn += '\t The decay processes will be drawn separately' 3890 logger.warning(warn) 3891 3892 (options, args) = _draw_parser.parse_args(args) 3893 if madgraph.iolibs.drawing_eps.EpsDiagramDrawer.april_fool: 3894 options.horizontal = True 3895 options.external = True 3896 options.max_size = 0.3 3897 options.add_gap = 0.5 3898 options = draw_lib.DrawOption(options) 3899 start = time.time() 3900 3901 3902 3903 3904 # Collect amplitudes 3905 amplitudes = diagram_generation.AmplitudeList() 3906 3907 for amp in self._curr_amps: 3908 amplitudes.extend(amp.get_amplitudes()) 3909 3910 for amp in amplitudes: 3911 filename = pjoin(args[0], 'diagrams_' + \ 3912 amp.get('process').shell_string() + ".eps") 3913 3914 if selection=='all' and Dtype != 'loop': 3915 diags=amp.get('diagrams') 3916 elif selection=='born': 3917 diags=amp.get('born_diagrams') 3918 elif selection=='loop' or Dtype == 'loop': 3919 diags=base_objects.DiagramList([d for d in 3920 amp.get('loop_diagrams') if d.get('type')>0]) 3921 if len(diags) > 5000: 3922 logger.warning('Displaying only the first 5000 diagrams') 3923 diags = base_objects.DiagramList(diags[:5000]) 3924 3925 plot = draw.MultiEpsDiagramDrawer(diags, 3926 filename, 3927 model=self._curr_model, 3928 amplitude=amp, 3929 legend=amp.get('process').input_string(), 3930 diagram_type=Dtype) 3931 3932 3933 logger.info("Drawing " + \ 3934 amp.get('process').nice_string()) 3935 plot.draw(opt=options) 3936 logger.info("Wrote file " + filename) 3937 self.exec_cmd('open %s' % filename) 3938 3939 stop = time.time() 3940 logger.info('time to draw %s' % (stop - start))
3941 3942 # Perform checks
3943 - def do_check(self, line):
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 ###### BEGIN do_check 3970 3971 args = self.split_arg(line) 3972 # Check args validity 3973 param_card = self.check_check(args) 3974 3975 options= {'events':None} # If the momentum needs to be picked from a event file 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 # Back up the gauge for later 3985 gauge = str(self.options['gauge']) 3986 options['reuse'] = args[1]=="-reuse" 3987 args = args[:1]+args[2:] 3988 # For the stability check the user can specify the statistics (i.e 3989 # number of trial PS points) as a second argument 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 # Lists the sets of custom and widths modifications to apply 4073 value = option[1] 4074 # Set a shortcuts for applying all relevant tweaks 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 # for safety prefix parameters, because 'as' for alphas 4122 # is a python reserved name for example 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 # Specify a loop, filter. See functions get_loop_filter and 4144 # user_filter in loop_diagram_generation.LoopAmplitude for 4145 # information on usage. 4146 CMS_options['loop_filter'] = '='.join(option[1:]) 4147 elif option[0]=='--diff_lambda_power': 4148 #'secret' option to chose by which lambda power one should divide 4149 # the nwa-cms difference. Useful to set to 2 when doing the Born check 4150 # to see whether the NLO check will have sensitivity to the CMS 4151 # implementation 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 # Format here is then (lower_bound, N) were lower_bound is 4185 # the minimum lambdaCMS value that must be probed and the 4186 # integer N is the number of such values that must be 4187 # uniformly distributed in each intervale [1.0e-i,1.0e-(i+1)] 4188 if isinstance(lambda_values, float): 4189 # Use default of 10 for the number of lambda values 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 # and finally add 5 points for stability test on the last values 4206 # Depending on how the stab test will behave at NLO, we can 4207 # consider automatically adding the values below 4208 # for stab in range(1,6): 4209 # lambda_values.append((1.0+(stab/100.0))*lower_bound) 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 # for safety prefix parameters, because 'as' for alphas 4231 # is a python reserved name for example 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 # Put everything lower case as it will be done when 4244 # accessing model variables 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 # Simple printout of the check command options 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 # Simple printout of the special check cms options 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 # Set the seed here if not in cms check and if specified 4272 if args[0]!='cms' and options['seed']!=-1: 4273 # Not necessarily optimal as there could be additional call to 4274 # random() as the code develops, but at least it will encompass 4275 # everything in this way. 4276 logger_check.info('Setting random seed to %d.'%options['seed']) 4277 random.seed(options['seed']) 4278 4279 proc_line = " ".join(args[1:]) 4280 # Don't try to extract the process if just re-analyzing a saved run 4281 if not (args[0]=='cms' and options['analyze']!='None'): 4282 myprocdef = self.extract_process(proc_line) 4283 4284 # Check that we have something 4285 if not myprocdef: 4286 raise self.InvalidCmd("Empty or wrong format process, please try again.") 4287 # For the check command, only the mode 'virt' make sense. 4288 if myprocdef.get('NLO_mode')=='all': 4289 myprocdef.set('NLO_mode','virt') 4290 else: 4291 myprocdef = None 4292 4293 # If the test has to write out on disk, it should do so at the location 4294 # specified below where the user must be sure to have writing access. 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 # Disable some loggers 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 # run the check 4328 cpu_time1 = time.time() 4329 # Run matrix element generation check on processes 4330 4331 # The aloha python output has trouble when doing (tree level of course) 4332 # python output and that loop_mode is True at the beginning. 4333 # So as a temporary fix for the problem that after doing a check at NLO 4334 # then a check at LO will fail, I make sure I set it to False if the 4335 # process is a tree-level one 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 # directories for TIR 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 # In this case timing and stability will be checked one after the 4429 # other without re-generating the process. 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 # restore previous settings 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 # The CMS check is typically more complicated and slower than others 4508 # so we don't run it automatically with 'full'. 4509 if args[0] in ['cms']: 4510 4511 cms_original_setup = self.options['complex_mass_scheme'] 4512 process_line = " ".join(args[1:]) 4513 # Merge in the CMS_options to the options 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 # Try to guess the save path and try to load it before running 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 # Now set the correct save path 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 # restore previous settings 4569 self.do_set('complex_mass_scheme %s'%str(cms_original_setup), 4570 log=False) 4571 # Use here additional key 'ordered_processes' 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 # We use the reuse tag for an alternative way of skipping the pager. 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 # Restore diagram logger 4649 for i, log in enumerate(loggers): 4650 log.setLevel(old_levels[i]) 4651 4652 # Output the result to the interface directly if short enough or if it 4653 # was anyway not output to the pager 4654 if len(text.split('\n'))<=20 or options['reuse']: 4655 # Useful to really specify what logger is used for ML acceptance tests 4656 logging.getLogger('madgraph.check_cmd').info(text) 4657 else: 4658 logging.getLogger('madgraph.check_cmd').debug(text) 4659 4660 # clean the globals created. 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
4666 - def clean_process(self):
4667 """ensure that all processes are cleaned from memory. 4668 typically called from import model and generate XXX command 4669 """ 4670 4671 aloha_lib.KERNEL.clean() 4672 # Reset amplitudes 4673 self._curr_amps = diagram_generation.AmplitudeList() 4674 # Reset Process definition 4675 self._curr_proc_defs = base_objects.ProcessDefinitionList() 4676 # Reset Helas matrix elements 4677 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4678 self._generate_info = "" 4679 # Reset _done_export, since we have new process 4680 self._done_export = False 4681 # Also reset _export_format and _export_dir 4682 self._export_format = None
4683 4684 4685 # Generate a new amplitude
4686 - def do_generate(self, line):
4687 """Main commands: Generate an amplitude for a given process""" 4688 4689 self.clean_process() 4690 self._generate_info = line 4691 4692 # Call add process 4693 args = self.split_arg(line) 4694 args.insert(0, 'process') 4695 self.do_add(" ".join(args))
4696
4697 - def extract_process(self, line, proc_number = 0, overall_orders = {}):
4698 """Extract a process definition from a string. Returns 4699 a ProcessDefinition.""" 4700 4701 orig_line = line 4702 # Check basic validity of the line 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 # Perform sanity modifications on the lines: 4709 # Add a space before and after any > , $ / | [ ] 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 # Use regular expressions to extract s-channel propagators, 4714 # forbidden s-channel propagators/particles, coupling orders 4715 # and process number, starting from the back 4716 4717 # Start with process number (identified by "@") 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 #overall_order are already handle but it is better to pass the info to each group 4724 4725 # Now check for perturbation orders, specified in between squared brackets 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 ## Now check for orders/squared orders/constrained orders 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 # define the various coupling order alias 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 ## The 'split_orders' (i.e. those for which individual matrix element 4781 ## evalutations must be provided for each corresponding order value) are 4782 ## defined from the orders specified in between [] and any order for 4783 ## which there are squared order constraints. 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:#name not in orders: 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 # handle the case where default is not 99 and some coupling defined 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 #only allow amplitue restrctions >/ == for LO/tree level 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 # If the squared orders are defined but not the orders, assume 4859 # orders=sq_orders. In case the squared order has a negative value or is 4860 # defined with the '>' operato, then this order correspondingly set to 4861 # be maximal (99) since there is no way to know, during generation, if 4862 # the amplitude being contstructed will be leading or not. 4863 # This only applies when no perturbation couplings are provided, ie 4864 # for LO-only generation 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 # Particle names lowercase 4875 line = line.lower() 4876 4877 # Now check for forbidden particles, specified using "/" 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 # Now check for forbidden schannels, specified using "$$" 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 # Now check for forbidden onshell schannels, specified using "$" 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 # Now check for required schannels, specified using "> >" 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 # Extract process 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 # check for duplication flag! 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 # Apply the keyword 'all' for perturbed coupling orders. 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 # We have a valid process 5051 # Extract perturbation orders 5052 perturbation_couplings_list = perturbation_couplings.split() 5053 if perturbation_couplings_list==['']: 5054 perturbation_couplings_list=[] 5055 # Correspondingly set 'split_order' from the squared orders and the 5056 # perturbation couplings list 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 # If the loopOption is 'tree' then the user used the syntax 5069 # [tree= Orders] for the sole purpose of setting split_orders. We 5070 # then empty the perturbation_couplings_list at this stage. 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 # Now extract restrictions 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 # 'is_decay_chain': decay_process\ 5143 5144
5145 - def create_loop_induced(self, line, myprocdef=None):
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 # Check the validity of the arguments 5156 self.check_add(args) 5157 if args[0] == 'process': 5158 args = args[1:] 5159 5160 # special option for 1->N to avoid generation of kinematically forbidden 5161 #decay. 5162 if args[-1].startswith('--optimize'): 5163 optimize = True 5164 args.pop() 5165 else: 5166 optimize = False 5167 5168 # Extract potential loop_filter 5169 loop_filter=None 5170 for arg in args: 5171 if arg.startswith('--loop_filter='): 5172 loop_filter = arg[14:] 5173 #if not isinstance(self, extended_cmd.CmdShell): 5174 # raise self.InvalidCmd, "loop_filter is not allowed in web mode" 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 # store the first process (for the perl script) 5183 if not self._generate_info: 5184 self._generate_info = line 5185 5186 # Reset Helas matrix elements 5187 #self._curr_matrix_elements = helas_objects.HelasLoopInducedMultiProcess() 5188 5189 5190 # Check that we have the same number of initial states as 5191 # existing processes 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 # Negative coupling order contraints can be given on at most one 5201 # coupling order (and either in squared orders or orders, not both) 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 # Generate processes 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 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 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 # Reset _done_export, since we have new process 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
5254 - def split_process_line(procline):
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 # remove the tag "[*]": this tag is used in aMC@LNO , 5263 # but it is not a valid syntax for LO 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 # Extract the options: 5272 # 5273 # A. Remove process number (identified by "@") 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 # B. search for the beginning of the option string 5280 pos=1000 5281 # start with order 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 # then look for slash or dollar 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
5302 - def get_final_part(self, procline):
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 # method. 5312 # 1) look for decay. 5313 # in presence of decay call this routine recursively and veto 5314 # the particles which are decayed 5315 5316 # Deal with decay chain 5317 if ',' in procline: 5318 core, decay = procline.split(',', 1) 5319 core_final = self.get_final_part(core) 5320 5321 #split the decay 5322 all_decays = decay.split(',') 5323 nb_level, tmp_decay = 0, '' 5324 decays = [] 5325 # deal with () 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 # remove from the final states all particles which are decayed 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 # NO DECAY CHAIN 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 # This is an "or-multiparticle" 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 # Flatten id list, to take care of multiparticles and 5408 # or-multiparticles 5409 res_lists = [] 5410 for i, id_list in enumerate(all_ids): 5411 res_lists.extend(diagram_generation.expand_list_list(id_list)) 5412 # Trick to avoid duplication while keeping ordering 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
5423 - def optimize_order(self, pdg_list):
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
5441 - def extract_decay_chain_process(self, line, level_down=False, proc_number=0):
5442 """Recursively extract a decay chain process definition from a 5443 string. Returns a ProcessDefinition.""" 5444 5445 # Start with process number (identified by "@") and overall orders 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 #level_down = False 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 # special cases: parenthesis but no , => remove the paranthesis! 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 # Go down one level in process hierarchy 5491 #level_down = True 5492 line = line.lstrip()[1:] 5493 # This is where recursion happens 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 # Return the core process (ends recursion when there are no 5528 # more decays) 5529 return core_process, line
5530 5531 5532 # Import files
5533 - def do_import(self, line, force=False):
5534 """Main commands: Import files with external formats""" 5535 5536 args = self.split_arg(line) 5537 # Check argument's validity 5538 self.check_import(args) 5539 if args[0].startswith('model'): 5540 self._model_v4_path = None 5541 # Reset amplitudes and matrix elements 5542 self.clean_process() 5543 # Import model 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 # avoid loading the qcd/qed model twice 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 # Do post-processing of model 5619 self.process_model() 5620 # Reset amplitudes and matrix elements and global checks 5621 self._curr_amps = diagram_generation.AmplitudeList() 5622 # Reset proc defs 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 # Check the status of export and try to use file position if no 5633 #self._export dir are define 5634 self.check_for_export_dir(args[1]) 5635 # Execute the card 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 # Check that this is MG5 banner 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 # Check the status of export and try to use file position is no 5668 # self._export dir are define 5669 self.check_for_export_dir(os.path.realpath(proc_card)) 5670 else: 5671 raise MadGraph5Error('No default directory in output') 5672 5673 5674 #convert and excecute the card 5675 self.import_mg4_proc_card(proc_card)
5676
5677 - def remove_pointless_decay(self, param_card):
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 # Collect amplitudes 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 # No BR for this particle -> accept all. 5699 # create the tuple associate to the decay mode 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 #check if the decay is present or not: 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
5722 - def import_ufo_model(self, model_name):
5723 """ import the UFO model """ 5724 5725 self._curr_model = import_ufo.import_model(model_name)
5726
5727 - def process_model(self):
5728 """Set variables _particle_names and _couplings for tab 5729 completion, define multiparticles""" 5730 5731 # Set variables for autocomplete 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
5743 - def import_mg4_proc_card(self, filepath):
5744 """ read a V4 proc card, convert it and run it in mg5""" 5745 5746 # change the status of this line in the history -> pass in comment 5747 if self.history and self.history[-1].startswith('import proc_v4'): 5748 self.history[-1] = '#%s' % self.history[-1] 5749 5750 # read the proc_card.dat 5751 reader = files.read_from_file(filepath, import_v4.read_proc_card_v4) 5752 if not reader: 5753 raise self.InvalidCmd('\"%s\" is not a valid path' % filepath) 5754 5755 if self._mgme_dir: 5756 # Add comment to history 5757 self.exec_cmd("# Import the model %s" % reader.model, precmd=True) 5758 line = self.exec_cmd('import model_v4 %s -modelname' % \ 5759 (reader.model), precmd=True) 5760 else: 5761 logging.error('No MG_ME installation detected') 5762 return 5763 5764 5765 # Now that we have the model we can split the information 5766 lines = reader.extract_command_lines(self._curr_model) 5767 for line in lines: 5768 self.exec_cmd(line, precmd=True) 5769 5770 return
5771
5772 - def add_default_multiparticles(self):
5773 """ add default particle from file interface.multiparticles_default.txt 5774 """ 5775 5776 defined_multiparticles = list(self._multiparticles.keys()) 5777 removed_multiparticles = [] 5778 # First check if the defined multiparticles are allowed in the 5779 # new model 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 # Now add default multiparticles 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 #self.do_define(line) 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 # check if the photon has to be added to j and p 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 # add all tag 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 # prevent border effects 5892 add_options = list(additional_options) 5893 5894 # Always refresh the installer if already present 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 # Guess if it is a local or web address 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 # If it is a local tarball, then just copy it 5915 shutil.copyfile(HepToolsInstaller_web_address, 5916 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5917 5918 # Untar the file 5919 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'], 5920 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w')) 5921 5922 # Remove the tarball 5923 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5924 5925 5926 # FOR DEBUGGING ONLY, Take HEPToolsInstaller locally 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 # Potential change in naming convention 5935 name_map = {'lhapdf6_py3': 'lhapdf6'} 5936 try: 5937 tool = name_map[tool_to_install] 5938 except: 5939 tool = tool_to_install 5940 5941 # Compiler options 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 # Add the path of pythia8 if known and the MG5 path 5967 if tool=='mg5amc_py8_interface': 5968 #add_options.append('--mg5_path=%s'%MG5DIR) 5969 # Warn about the soft dependency to gnuplot 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 # Special rules for certain tools 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 # All what's below is to handle the lhapdf dependency of Pythia8 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 # Make sure each otion in add_options appears only once 6045 add_options = list(set(add_options)) 6046 # And that the option '--force' is placed last. 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 # Make sure each otion in add_options appears only once 6056 add_options.append('--mg5_path=%s'%MG5DIR) 6057 add_options = list(set(add_options)) 6058 add_options.append('--mg5_path=%s'%MG5DIR) 6059 # And that the option '--force' is placed last. 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 # Post-installation treatment 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 # Automatically re-install the mg5amc_py8_interface after a fresh 6112 # Pythia8 installation 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 # At this stage, pythia is guaranteed to be installed 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 # Now warn the user if he didn't add HEPTools first in his environment 6157 # variables. 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 # Return true for successful installation 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 # Make sure to avoid any border effect on custom_additional_options 6246 add_options = list(additional_options) 6247 6248 args = self.split_arg(line) 6249 #check the validity of the arguments 6250 install_options = self.check_install(args) 6251 6252 if sys.platform == "darwin": 6253 program = "curl" 6254 else: 6255 program = "wget" 6256 6257 # special command for auto-update 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 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6273 # logger.info('{:^80}'.format("You are installing '%s', please cite ref(s):"%args[0]), '$MG:BOLD') 6274 # logger.info('{:^80}'.format(', '.join(advertisements[args[0]])), '$MG:color:GREEN') 6275 # logger.info('{:^80}'.format("when using results produced with this tool."), '$MG:BOLD') 6276 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 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 # Load file with path of the different program: 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 # Force here to choose one particular server 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 # TEMPORARY HACK WHERE WE ADD ENTRIES TO WHAT WILL BE EVENTUALLY ON THE WEB 6335 ################################################################################ 6336 # path['XXX'] = 'YYY' 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 # Now launch the advanced installation of the tool args[0] 6356 # path['HEPToolsInstaller'] is the online adress where to downlaod 6357 # the installers if necessary. 6358 # Specify the path of the MG5_aMC_interface 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 #check outdated install 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 # try with the mirror 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 # Load that path 6409 logger.info('Downloading %s' % path[args[0]]) 6410 misc.wget(path[args[0]], '%s.tgz' % name, cwd=MG5DIR) 6411 6412 # Untar the file 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 # Check that the directory has the correct name 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 # Modify Makefile for pythia-pgs on Mac 64 bit 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 = [] #flags for the compilation 6445 # Compile the file 6446 # Check for F77 compiler 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 # For Golem95, use autotools. 6471 if name == 'golem95': 6472 # Run the configure script 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 # For QCDLoop, use autotools. 6479 if name == 'QCDLoop': 6480 # Run the configure script 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 # For Delphes edit the makefile to add the proper link to correct library 6487 if args[0] == 'Delphes3': 6488 #change in the makefile 6489 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) 6490 # to 6491 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,/Applications/root_v6.04.08/lib/ 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 # For SysCalc link to lhapdf 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 # read the __init__.py to check if we need to add a new executable 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 #SLC6 needs to have this first (don't ask why) 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 #SLC6 needs to have this first (don't ask why) 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 # For pythia-pgs check when removing the "-fno-second-underscore" flag 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 # Special treatment for TD/Ghostscript program (require by MadAnalysis) 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 #logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer. 6654 #In 99% of the case, this is perfectly fine. If you do not have plot, please follow 6655 #instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''') 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 #reset the position of the executable 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
6711 - def install_update(self, args, wget):
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 #= = = renamed directory 'Template' => 'Template/LO' 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 # track rename since patch fail to apply those correctly. 6731 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6732 #=== renamed file 'Template/SubProcesses/addmothers.f' => 'madgraph/iolibs/template_files/addmothers.f' 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 # track remove/re-added file: 6745 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M) 6746 all_add = pattern.findall(text) 6747 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6748 #all_rm = pattern.findall(text) 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 #=== added file 'tests/input_files/full_sm/interactions.dat' 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 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6759 #=== removed file 'tests/input_files/full_sm/interactions.dat' 6760 #for old in pattern.findall(text): 6761 # if not os.path.isfile(pjoin(MG5DIR, old)): 6762 # full_path = os.path.dirname(pjoin(MG5DIR, old)).split('/') 6763 # for i, _ in enumerate(full_path): 6764 # path = os.path.sep.join(full_path[:i+1]) 6765 # if path and not os.path.isdir(path): 6766 # os.mkdir(path) 6767 # subprocess.call(['touch', pjoin(MG5DIR, old)]) 6768 6769 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE, 6770 cwd=MG5DIR) 6771 p.communicate(text.encode()) 6772 6773 # check file which are not move 6774 #=== modified file 'Template/LO/Cards/run_card.dat' 6775 #--- old/Template/Cards/run_card.dat 2012-12-06 10:01:04 +0000 6776 #+++ new/Template/LO/Cards/run_card.dat 2013-12-09 02:35:59 +0000 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 #=== renamed file 'Template/bin/internal/run_delphes' => 'Template/Common/bin/internal/run_delphes' 6793 #--- old/Template/bin/internal/run_delphes 2011-12-09 07:28:10 +0000 6794 #+++ new/Template/Common/bin/internal/run_delphes 2012-10-23 02:41:37 +0000 6795 #pattern=re.compile('''=== renamed file \'(?P<old>[^\']*)\' => \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P=old)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6796 #for match in pattern.findall(text): 6797 # old = pjoin(MG5DIR, match[0]) 6798 # new = pjoin(MG5DIR, match[1]) 6799 # if new == old: 6800 # continue 6801 # elif os.path.exists(old): 6802 # if not os.path.exists(os.path.dirname(new)): 6803 # split = new.split('/') 6804 # for i in range(1,len(split)): 6805 # path = '/'.join(split[:i]) 6806 # if not os.path.exists(path): 6807 # print 'mkdir', path 6808 # os.mkdir(path) 6809 # files.cp(old,new) 6810 6811 # check that all files in bin directory are executable 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 #add empty files/directory 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 # add new symlink 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 # Re-compile CutTools and IREGI 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 # check if it need to download binary: 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')):# or \ 6904 #os.path.exists(os.path.join(MG5DIR,'.bzr')): 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 # read the data present in .autoupdate 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 #check validity of the file 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 #check if we need to update. 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 # wait 24h before next check 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 # update .autoupdate to prevent a too close check 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 # Untar the file 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 # prevent for a future check 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: #answer is on_exit 7068 #ensure that the test will be done on exit 7069 #Do not use the set command here!! 7070 self.options['auto_update'] = -1 * self.options['auto_update'] 7071 7072 7073
7074 - def set_configuration(self, config_path=None, final=True):
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 # read the file and extract information 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 # the return is usefull for unittest 7121 7122 # Treat each expected input 7123 # 1: Pythia8_path and hewrig++ paths 7124 # try absolute and relative path 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 #this is for pythia8 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 #this is for mg5amc_py8_interface_path 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 #this is for madanalysis5 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 #this is for hw++ 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 # this is for thepeg 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 # this is for hepmc 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 # try to find it automatically on the system 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 # Try to look for it locally 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 # Make sure that samurai version is recent enough 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 # Default: try to set parameter 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 # Configure the way to open a file: 7239 launch_ext.open_file.configure(self.options) 7240 return self.options
7241
7242 - def check_for_export_dir(self, filepath):
7243 """Check if the files is in a valid export directory and assign it to 7244 export path if if is""" 7245 7246 # keep previous if a previous one is defined 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
7259 - def do_launch(self, line):
7260 """Main commands: Ask for editing the parameter and then 7261 Execute the code (madevent/standalone/...) 7262 """ 7263 7264 #ensure that MG option are not modified by the launch routine 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 # check argument validity and normalise argument 7270 (options, args) = _launch_parser.parse_args(args) 7271 self.check_launch(args, options) 7272 options = options.__dict__ 7273 # args is now MODE PATH 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 #check if this is a cross-section 7296 if not self._generate_info: 7297 # This relaunch an old run -> need to check if this is a 7298 # cross-section or a width 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 # This is a width computation 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 # transfer interactive configuration 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 # transfer interactive configuration 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) #ensure to go to the initial path 7352 raise self.InvalidCmd('%s cannot be run from MG5 interface' % args[0]) 7353 7354 7355 ext_program.run() 7356 os.chdir(start_cwd) #ensure to go to the initial path 7357 # ensure that MG options are not changed! 7358 for key, value in current_options.items(): 7359 self.options[key] = value
7360
7361 - def do_load(self, line):
7362 """Not in help: Load information from file""" 7363 7364 args = self.split_arg(line) 7365 # check argument validity 7366 self.check_load(args) 7367 7368 cpu_time1 = time.time() 7369 if args[0] == 'model': 7370 self._curr_model = save_load_object.load_from_file(args[1]) 7371 if self._curr_model.get('parameters'): 7372 # This is a UFO model 7373 self._model_v4_path = None 7374 else: 7375 # This is a v4 model 7376 self._model_v4_path = import_v4.find_model_path(\ 7377 self._curr_model.get('name').replace("_v4", ""), 7378 self._mgme_dir) 7379 7380 # Do post-processing of model 7381 self.process_model() 7382 7383 #save_model.save_model(args[1], self._curr_model) 7384 if isinstance(self._curr_model, base_objects.Model): 7385 cpu_time2 = time.time() 7386 logger.info("Loaded model from file in %0.3f s" % \ 7387 (cpu_time2 - cpu_time1)) 7388 else: 7389 raise self.RWError('Could not load model from file %s' \ 7390 % args[1]) 7391 elif args[0] == 'processes': 7392 amps,proc_defs = save_load_object.load_from_file(args[1]) 7393 if isinstance(amps, diagram_generation.AmplitudeList): 7394 cpu_time2 = time.time() 7395 logger.info("Loaded processes from file in %0.3f s" % \ 7396 (cpu_time2 - cpu_time1)) 7397 if amps: 7398 model = amps[0].get('process').get('model') 7399 if not model.get('parameters'): 7400 # This is a v4 model. Look for path. 7401 self._model_v4_path = import_v4.find_model_path(\ 7402 model.get('name').replace("_v4", ""), 7403 self._mgme_dir) 7404 else: 7405 self._model_v4_path = None 7406 # If not exceptions from previous steps, set 7407 # _curr_amps and _curr_model 7408 self._curr_amps = amps 7409 self._curr_model = model 7410 self._curr_proc_defs = proc_defs 7411 logger.info("Model set from process.") 7412 # Do post-processing of model 7413 self.process_model() 7414 self._done_export = None 7415 else: 7416 raise self.RWError('Could not load processes from file %s' % args[1])
7417 7418
7419 - def do_customize_model(self, line):
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 # (re)import the full model (get rid of the default restriction) 7430 self._curr_model = import_ufo.import_model(model_path, restrict=False) 7431 7432 #1) create the full param_card 7433 out_path = StringIO.StringIO() 7434 param_writer.ParamCardWriter(self._curr_model, out_path) 7435 # and load it to a python object 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 ## Make a Temaplate for the restriction card. (card with no restrict) 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 # Applying the restriction 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 # if some need to put on one 7483 if put_to_one: 7484 out_path = StringIO.StringIO() 7485 param_writer.ParamCardWriter(self._curr_model, out_path) 7486 # and load it to a python object 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 # was removed of the model! 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 # Check argument validity 7508 if check: 7509 self.check_save(args) 7510 7511 if args[0] == 'model': 7512 if self._curr_model: 7513 #save_model.save_model(args[1], self._curr_model) 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 # store in file only those ones 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 # First look at options which should be put in MG5DIR/input 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 # Set an option
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 # Be careful: 7587 # This command is associated to a post_cmd: post_set. 7588 args = self.split_arg(line) 7589 7590 # Check the validity of the arguments 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 # Treat the case where they are no model loaded 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 # They are a valid model 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 #re-init all variable 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 # We don't want to go through the MasterCommand again 7731 # because it messes with the interface switching when 7732 # importing a loop model from MG5 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: #everything is fine 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 # Reset the amplitudes, MatrixElements and exporter as they might 7885 # depend on this option 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 # True/False formatting 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 # Check the validity of the arguments 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 #MadGraph5_aMC@NLO configuration 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
7948 - def do_open(self, line):
7949 """Open a text file/ eps file / html file""" 7950 7951 args = self.split_arg(line) 7952 # Check Argument validity and modify argument to be the real path 7953 self.check_open(args) 7954 file_path = args[0] 7955 7956 launch_ext.open_file(file_path)
7957
7958 - def do_output(self, line):
7959 """Main commands: Initialize a new Template or reinitialize one""" 7960 7961 args = self.split_arg(line) 7962 # Check Argument validity 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 # line_options = dict(arg[2:].split('=') for arg in args if arg.startswith('--') and '=' not in arg) 7980 main_file_name = "" 7981 try: 7982 main_file_name = args[args.index('-name') + 1] 7983 except Exception: 7984 pass 7985 7986 7987 ################ 7988 # ALOHA OUTPUT # 7989 ################ 7990 if self._export_format == 'aloha': 7991 # catch format 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 # catch output dir 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 # build the calling list for aloha 8010 names = [d for d in args if not d.startswith('-')] 8011 wanted_lorentz = aloha_fct.guess_routine_from_name(names) 8012 # Create and write ALOHA Routine 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 ## Other Output # 8024 ################# 8025 # Configuration of what to do: 8026 # check: check status of the directory 8027 # exporter: which exporter to use (v4/cpp/...) 8028 # output: [Template/dir/None] copy the Template, just create dir or do nothing 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 # check 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 # Don't ask if user already specified force or noclean 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 # Choose here whether to group subprocesses or not, if the option was 8075 # set to 'Auto' and propagate this choice down the line: 8076 if self.options['group_subprocesses'] in [True, False]: 8077 group_processes = self.options['group_subprocesses'] 8078 elif self.options['group_subprocesses'] == 'Auto': 8079 # By default we set it to True 8080 group_processes = True 8081 # But we turn if off for decay processes which 8082 # have been defined with multiparticle labels, because then 8083 # branching ratios necessitates to keep subprocesses independent. 8084 # That applies only if there is more than one subprocess of course. 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 # Special warning for loop-induced 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 #Exporter + Template 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 # Reset _done_export, since we have new directory 8123 self._done_export = False 8124 8125 if self._export_format == "madevent": 8126 # for MadEvent with MadLoop decide if we keep the box as channel of 8127 #integration or not. Forbid them for matching and for h+j 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 # Perform export and finalize right away 8135 self.export(nojpeg, main_file_name, group_processes, args) 8136 8137 # Automatically run finalize 8138 self.finalize(nojpeg, flaglist=flaglist) 8139 8140 # Remember that we have done export 8141 self._done_export = (self._export_dir, self._export_format) 8142 8143 # Reset _export_dir, so we don't overwrite by mistake later 8144 self._export_dir = None
8145 8146 # Export a matrix element
8147 - def export(self, nojpeg = False, main_file_name = "", group_processes=True, 8148 args=[]):
8149 """Export a generated amplitude to file.""" 8150 8151 8152 # Define the helas call writer 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 # Sort amplitudes according to number of diagrams, 8186 # to get most efficient multichannel output 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 # assign a unique id number to all groups 8224 uid = 0 8225 for group in subproc_groups: 8226 uid += 1 # update the identification number 8227 for me in group.get('matrix_elements'): 8228 me.get('processes')[0].set('uid', uid) 8229 else: # Not grouped subprocesses 8230 mode = {} 8231 if self._export_format in [ 'standalone_msP' , 8232 'standalone_msF', 'standalone_rw']: 8233 mode['mode'] = 'MadSpin' 8234 # The conditional statement tests whether we are dealing 8235 # with a loop induced process. 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 # assign a unique id number to all process 8253 uid = 0 8254 for me in self._curr_matrix_elements.get_matrix_elements()[:]: 8255 uid += 1 # update the identification number 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 # Start of the actual routine 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 # First treat madevent and pythia8 exports, where we need to 8274 # distinguish between grouped and ungrouped subprocesses 8275 8276 # MadEvent 8277 if self._export_format == 'madevent': 8278 calls += self._curr_exporter.export_processes(self._curr_matrix_elements, 8279 self._curr_helas_model) 8280 8281 #try: 8282 # cmd.Cmd.onecmd(self, 'history .') 8283 #except Exception: 8284 # misc.sprint('command history fails.', 10) 8285 # pass 8286 8287 # Pythia 8 8288 elif self._export_format == 'pythia8': 8289 # Output the process files 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 # Output the model parameter and ALOHA files 8306 model_name, model_path = exporter.convert_model_to_pythia8(\ 8307 self._curr_model, self._export_dir) 8308 8309 # Generate the main program file 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 # Just the matrix.f files 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 # grouping mode 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 # ungroup mode 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 # Write the procdef_mg5.dat file with process info 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 # Replace the amplitudes with the actual amplitudes from the 8390 # matrix elements, which allows proper diagram drawing also of 8391 # decay chain processes 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 # Handling of the model. 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 # wanted_lorentz are the lorentz structures which are 8413 # actually used in the wavefunctions and amplitudes in 8414 # these processes 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 # For a unique output of multiple type of exporter need to store this 8426 # information. 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 # move the old options to the flaglist system. 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 ## write fj_lhapdf_opts file 8450 # Create configuration file [path to executable] for amcatnlo 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 # Create configuration file [path to executable] for madevent 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 # Dedicated finalize function. 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
8481 - def do_help(self, line):
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 # Calculate decay width
8503 - def do_compute_widths(self, line, model=None, do2body=True, decaymodel=None):
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 # call SMWidth to calculate NLO Width 8543 self.compute_widths_SMWidth(line, model=model) 8544 return 8545 8546 # check the argument and return those in a dictionary format 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 # find UFO particles linked to the require names. 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 # check if the value of alphas is set to zero and raise warning if appropriate 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 # the p object can still be UFO reference. since the 8594 # mass name might hve change load back the MG5 one. 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 # add info from decay module 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 # Do the MadEvent integration!! 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 #modify some parameter of the default run_card 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 # Need to write the correct param_card in the correct place !!! 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 # call a ME interface and define as it as child for correct error handling 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 #me_cmd.options.update(self.options) 8673 #me_cmd.configure_run_mode(self.options['run_mode']) 8674 #self.define_child_cmd_interface(me_cmd, interface=False) 8675 me_cmd.model_name = self._curr_model['name'] #needed for mssm 8676 me_cmd.options['automatic_html_opening'] = False 8677 8678 me_opts=[('accuracy', opts['precision_channel']), # default 0.01 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 #me_cmd.exec_cmd('store_events', postcmd=False) 8686 me_cmd.collect_decay_widths() 8687 me_cmd.do_quit('') 8688 # cleaning 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 #if particle['color'] !=1 and 0 < width.real < 0.1: 8697 # logger.warning("width of colored particle \"%s(%s)\" lower than QCD scale: %s. Set width to zero " 8698 # % (particle.get('name'), pid, width.real)) 8699 # width = 0 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 # Calculate decay width with SMWidth
8727 - def compute_widths_SMWidth(self, line, model=None):
8728 """Compute widths with SMWidth. 8729 """ 8730 8731 # check the argument and return those in a dictionary format 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 # determine the EW scheme 8762 externparam = [(param.lhablock.lower(),param.name.lower()) for param \ 8763 in currmodel.get('parameters')[('external',)]] 8764 8765 if ('sminputs','aewm1') in externparam: 8766 # alpha(MZ) scheme 8767 arg2 = "1" 8768 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam: 8769 # Gmu scheme 8770 arg2 = "2" 8771 else: 8772 raise Exception("Do not know the EW scheme in the model %s"%model_name) 8773 8774 #compile the code 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 # look for the ident_card.dat 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 #run the code 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] # reset the BR 8818 # write the output file. (the new param_card) 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 # Calculate decay width
8828 - def do_decay_diagram(self, line, skip_2body=False, model=None):
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 #check the validity of the arguments 8856 particles, args = self.check_decay_diagram(args) 8857 #print args 8858 pids = particles 8859 level = float(args['body_decay']) 8860 param_card_path = args['path'] 8861 min_br = float(args['min_br']) 8862 8863 # Reset amplitudes 8864 self._curr_amps = diagram_generation.AmplitudeList() 8865 self._curr_proc_defs = base_objects.ProcessDefinitionList() 8866 # Reset Helas matrix elements 8867 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 8868 # Reset _done_export, since we have new process 8869 self._done_export = False 8870 # Also reset _export_format and _export_dir 8871 self._export_format = None 8872 8873 8874 # Setup before find_channels 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 # Find channels as requested 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 #part.group_channels_2_amplitudes(clevel, model, min_br) 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 # Set _generate_info 8936 if len(self._curr_amps) > 0: 8937 process = self._curr_amps[0]['process'].nice_string() 8938 #print process 8939 self._generate_info = process[9:] 8940 #print self._generate_info 8941 else: 8942 logger.info("No decay is found")
8943
8944 -class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd):
8945 """Temporary parser"""
8946 8947 #=============================================================================== 8948 # Command Parser 8949 #=============================================================================== 8950 # DRAW 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 # LAUNCH PROGRAM 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")
8995 8996 #=============================================================================== 8997 # Interface for customize question. 8998 #=============================================================================== 8999 -class AskforCustomize(cmd.SmartQuestion):
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 #2) Import the option available in the model 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 # determine the possible value and how they are linked to the restriction 9013 #options. 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
9029 - def default(self, line):
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 # check if input is a file 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):
9050 """ """ 9051 reprint_opt = True 9052 self.question = self.get_question() 9053 cmd.SmartQuestion.reask(self, reprint_opt)
9054
9055 - def do_set(self, line):
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
9078 - def get_question(self):
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
9095 - def complete_set(self, text, line, begidx, endidx):
9096 """ Complete the set command""" 9097 signal.alarm(0) # avoid timer if any 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
9107 - def do_help(self, line):
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
9132 - def cmdloop(self, intro=None):
9133 cmd.SmartQuestion.cmdloop(self, intro) 9134 return self.all_categories
9135 9136 9137 9138 #=============================================================================== 9139 # __main__ 9140 #=============================================================================== 9141 9142 if __name__ == '__main__': 9143 9144 run_option = sys.argv 9145 if len(run_option) > 1: 9146 # The first argument of sys.argv is the name of the program 9147 input_file = open(run_option[1], 'rU') 9148 cmd_line = MadGraphCmd(stdin=input_file) 9149 cmd_line.use_rawinput = False #put it in non interactive mode 9150 cmd_line.cmdloop() 9151 else: 9152 # Interactive mode 9153 MadGraphCmd().cmdloop() 9154