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 proc = subprocess.Popen(['bzr', 'nick'], stdout=subprocess.PIPE,cwd=MG5DIR) 204 bzrname,_ = proc.communicate() 205 proc = subprocess.Popen(['bzr', 'revno'], stdout=subprocess.PIPE,cwd=MG5DIR) 206 bzrversion,_ = proc.communicate() 207 bzrname, bzrversion = bzrname.decode().strip(), bzrversion.decode().strip() 208 len_name = len(bzrname) 209 len_version = len(bzrversion) 210 info_line += "#* BZR %s %s %s *\n" % \ 211 (bzrname, 212 (34 - len_name - len_version) * ' ', 213 bzrversion) 214 215 # Create a header for the history file. 216 # Remember to fill in time at writeout time! 217 self.history_header = banner_module.ProcCard.history_header % {'info_line': info_line} 218 banner_module.ProcCard.history_header = self.history_header 219 220 if info_line: 221 info_line = info_line.replace("#*","*") 222 223 224 logger.info(self.intro_banner % info_line) 225 226 cmd.Cmd.__init__(self, *arg, **opt) 227 228 self.history = banner_module.ProcCard()
229 230
231 - def default(self, line):
232 """Default action if line is not recognized""" 233 234 # Faulty command 235 log=True 236 if line.startswith('p') or line.startswith('e'): 237 logger.warning("Command %s not recognized. Did you mean \'generate %s\'?. Please try again" % 238 (line.split()[0], line)) 239 log=False 240 return super(CmdExtended,self).default(line, log=log)
241
242 - def postcmd(self,stop, line):
243 """ finishing a command 244 This looks if the command add a special post part. 245 This looks if we have to write an additional text for the tutorial.""" 246 247 stop = super(CmdExtended, self).postcmd(stop, line) 248 # Print additional information in case of routines fails 249 if stop == False: 250 return False 251 252 args=line.split() 253 # Return for empty line 254 if len(args)==0: 255 return stop 256 257 # try to print linked to the first word in command 258 #as import_model,... if you don't find then try print with only 259 #the first word. 260 if len(args)==1: 261 command=args[0] 262 else: 263 command = args[0]+'_'+args[1].split('.')[0] 264 265 try: 266 logger_tuto.info(getattr(tutorial_text, command).replace('\n','\n\t')) 267 except Exception: 268 try: 269 logger_tuto.info(getattr(tutorial_text, args[0]).replace('\n','\n\t')) 270 except Exception: 271 pass 272 273 try: 274 logger_tuto_nlo.info(getattr(tutorial_text_nlo, command).replace('\n','\n\t')) 275 except Exception: 276 try: 277 logger_tuto_nlo.info(getattr(tutorial_text_nlo, args[0]).replace('\n','\n\t')) 278 except Exception: 279 pass 280 281 try: 282 logger_tuto_madloop.info(getattr(tutorial_text_madloop, command).replace('\n','\n\t')) 283 except Exception: 284 try: 285 logger_tuto_madloop.info(getattr(tutorial_text_madloop, args[0]).replace('\n','\n\t')) 286 except Exception: 287 pass 288 289 return stop
290 291
292 - def get_history_header(self):
293 """return the history header""" 294 return self.history_header % misc.get_time_info()
295
296 #=============================================================================== 297 # HelpToCmd 298 #=============================================================================== 299 -class HelpToCmd(cmd.HelpCmd):
300 """ The Series of help routine for the MadGraphCmd""" 301
302 - def help_save(self):
303 logger.info("syntax: save %s FILENAME [OPTIONS]" % "|".join(self._save_opts),'$MG:color:BLUE') 304 logger.info("-- save information as file FILENAME",'$MG:BOLD') 305 logger.info(" FILENAME is optional for saving 'options'.") 306 logger.info(' By default it uses ./input/mg5_configuration.txt') 307 logger.info(' If you put "global" for FILENAME it will use ~/.mg5/mg5_configuration.txt') 308 logger.info(' If this files exists, it is uses by all MG5 on the system but continues') 309 logger.info(' to read the local options files.') 310 logger.info(' if additional argument are defined for save options, only those arguments will be saved to the configuration file.')
311
312 - def help_load(self):
313 logger.info("syntax: load %s FILENAME" % "|".join(self._save_opts),'$MG:color:BLUE') 314 logger.info("-- load information from file FILENAME",'$MG:BOLD')
315
316 - def help_import(self):
317 logger.info("syntax: import " + "|".join(self._import_formats) + \ 318 " FILENAME",'$MG:color:BLUE') 319 logger.info("-- imports file(s) in various formats",'$MG:color:GREEN') 320 logger.info("") 321 logger.info(" import model MODEL[-RESTRICTION] [OPTIONS]:",'$MG:BOLD') 322 logger.info(" Import a UFO model.") 323 logger.info(" MODEL should be a valid UFO model name") 324 logger.info(" Model restrictions are specified by MODEL-RESTRICTION") 325 logger.info(" with the file restrict_RESTRICTION.dat in the model dir.") 326 logger.info(" By default, restrict_default.dat is used.") 327 logger.info(" Specify model_name-full to get unrestricted model.") 328 logger.info(" '--modelname' keeps the original particle names for the model") 329 logger.info("") 330 logger.info(" Type 'display modellist' to have the list of all model available.",'$MG:color:GREEN') 331 logger.info("") 332 logger.info(" import model_v4 MODEL [--modelname] :",'$MG:BOLD') 333 logger.info(" Import an MG4 model.") 334 logger.info(" Model should be the name of the model") 335 logger.info(" or the path to theMG4 model directory") 336 logger.info(" '--modelname' keeps the original particle names for the model") 337 logger.info("") 338 logger.info(" import proc_v4 [PATH] :",'$MG:BOLD') 339 logger.info(" Execute MG5 based on a proc_card.dat in MG4 format.") 340 logger.info(" Path to the proc_card is optional if you are in a") 341 logger.info(" madevent directory") 342 logger.info("") 343 logger.info(" import command PATH :",'$MG:BOLD') 344 logger.info(" Execute the list of command in the file at PATH") 345 logger.info("") 346 logger.info(" import banner PATH [--no_launch]:",'$MG:BOLD') 347 logger.info(" Rerun the exact same run define in the valid banner.")
348
349 - def help_install(self):
350 logger.info("syntax: install " + "|".join(self._install_opts),'$MG:color:BLUE') 351 logger.info("-- Download the last version of the program and install it") 352 logger.info(" locally in the current MadGraph5_aMC@NLO version. In order to have") 353 logger.info(" a successful installation, you will need to have an up-to-date") 354 logger.info(" F77 and/or C and Root compiler.") 355 logger.info(" ") 356 logger.info(" When installing any of the following programs:") 357 logger.info(" %s"%(', '.join(self._advanced_install_opts))) 358 logger.info(" The following options are available:") 359 logger.info(" --force Overwrite without asking any existing installation.") 360 logger.info(" --keep_source Keep a local copy of the sources of the tools MG5_aMC installed from.") 361 logger.info(" ") 362 logger.info(" \"install update\"",'$MG:BOLD') 363 logger.info(" check if your MG5 installation is the latest one.") 364 logger.info(" If not it load the difference between your current version and the latest one,") 365 logger.info(" and apply it to the code. Two options are available for this command:") 366 logger.info(" -f: didn't ask for confirmation if it founds an update.") 367 logger.info(" --timeout=: Change the maximum time allowed to reach the server.")
368
369 - def help_display(self):
370 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLUE') 371 logger.info("-- display a the status of various internal state variables") 372 logger.info(" for particles/interactions you can specify the name or id of the") 373 logger.info(" particles/interactions to receive more details information.") 374 logger.info(" Example: display particles e+.",'$MG:color:GREEN') 375 logger.info(" > For \"checks\", can specify only to see failed checks.") 376 logger.info(" > For \"diagrams\", you can specify where the file will be written.") 377 logger.info(" Example: display diagrams ./",'$MG:color:GREEN')
378 379
380 - def help_launch(self):
381 """help for launch command""" 382 # Using the built-in parser help is not convenient when one wants to use 383 # color schemes. 384 #_launch_parser.print_help() 385 logger.info("syntax: launch <dir_path> <options>",'$MG:color:BLUE') 386 logger.info("-- execute the aMC@NLO/madevent/standalone/pythia8 output present in dir_path",'$MG:BOLD') 387 logger.info("By default, dir_path points to the last created directory.") 388 logger.info("(for pythia8, it should be the Pythia 8 main directory)") 389 logger.info("") 390 logger.info("Launch on madevent/pythia8/standalone outputs:",'$MG:BOLD') 391 logger.info(" o Example: launch PROC_sm_1 --name=run2",'$MG:color:GREEN') 392 logger.info(" o Example: launch ../pythia8",'$MG:color:GREEN') 393 logger.info(" > Options:") 394 logger.info(" -h, --help show this help message and exit") 395 logger.info(" -f, --force Use the card present in the directory in order") 396 logger.info(" to launch the different program") 397 logger.info(" -n NAME, --name=NAME Provide a name to the run (for madevent run)") 398 logger.info(" -c, --cluster submit the job on the cluster") 399 logger.info(" -m, --multicore submit the job on multicore core") 400 logger.info(" -i, --interactive Use Interactive Console [if available]") 401 logger.info(" -s LASTSTEP, --laststep=LASTSTEP") 402 logger.info(" last program run in MadEvent run.") 403 logger.info(" [auto|parton|pythia|pgs|delphes]") 404 logger.info("") 405 logger.info("Launch on MadLoop standalone output:",'$MG:BOLD') 406 logger.info(" o Example: launch PROC_loop_sm_1 -f",'$MG:color:GREEN') 407 logger.info(" > Simple check of a single Phase-space points.") 408 logger.info(" > You will be asked whether you want to edit the MadLoop ") 409 logger.info(" and model param card as well as the PS point, unless ") 410 logger.info(" the -f option is specified. All other options are ") 411 logger.info(" irrelevant for this kind of launch.") 412 logger.info("") 413 logger.info("Launch on aMC@NLO output:",'$MG:BOLD') 414 logger.info(" > launch <dir_path> <mode> <options>",'$MG:color:BLUE') 415 logger.info(" o Example: launch MyProc aMC@NLO -f -p",'$MG:color:GREEN')
416
417 - def help_tutorial(self):
418 logger.info("syntax: tutorial [" + "|".join(self._tutorial_opts) + "]",'$MG:color:BLUE') 419 logger.info("-- start/stop the MG5 tutorial mode (or stop any other mode)") 420 logger.info("-- aMCatNLO: start aMC@NLO tutorial mode") 421 logger.info("-- MadLoop: start MadLoop tutorial mode")
422
423 - def help_open(self):
424 logger.info("syntax: open FILE ",'$MG:color:BLUE') 425 logger.info("-- open a file with the appropriate editor.",'$MG:BOLD') 426 logger.info(' If FILE belongs to index.html, param_card.dat, run_card.dat') 427 logger.info(' the path to the last created/used directory is used') 428 logger.info(' The program used to open those files can be chosen in the') 429 logger.info(' configuration file ./input/mg5_configuration.txt')
430
431 - def help_customize_model(self):
432 logger.info("syntax: customize_model --save=NAME",'$MG:color:BLUE') 433 logger.info("-- Open an invite where you options to tweak the model.",'$MG:BOLD') 434 logger.info(" If you specify the option --save=NAME, this tweak will be") 435 logger.info(" available for future import with the command 'import model XXXX-NAME'")
436
437 - def help_output(self):
438 logger.info("syntax: output [" + "|".join(self._export_formats) + \ 439 "] [path|.|auto] [options]",'$MG:color:BLUE') 440 logger.info("-- Output any generated process(es) to file.",'$MG:BOLD') 441 logger.info(" Default mode is madevent. Default path is \'.\' or auto.") 442 logger.info(" mode:",'$MG:BOLD') 443 logger.info(" - For MadLoop and aMC@NLO runs, there is only one mode and") 444 logger.info(" it is set by default.") 445 logger.info(" - If mode is madevent, create a MadEvent process directory.") 446 logger.info(" - If mode is standalone, create a Standalone directory") 447 logger.info(" - If mode is matrix, output the matrix.f files for all") 448 logger.info(" generated processes in directory \"path\".") 449 logger.info(" - If mode is standalone_cpp, create a standalone C++") 450 logger.info(" directory in \"path\".") 451 logger.info(" - If mode is pythia8, output all files needed to generate") 452 logger.info(" the processes using Pythia 8. The files are written in") 453 logger.info(" the Pythia 8 directory (default).") 454 logger.info(" NOTE: The Pythia 8 directory is set in the ./input/mg5_configuration.txt") 455 logger.info(" - If mode is aloha: Special syntax output:") 456 logger.info(" syntax: aloha [ROUTINE] [--options]" ) 457 logger.info(" valid options for aloha output are:") 458 logger.info(" --format=Fortran|Python|Cpp : defining the output language") 459 logger.info(" --output= : defining output directory") 460 logger.info(" path: The path of the process directory.",'$MG:BOLD') 461 logger.info(" If you put '.' as path, your pwd will be used.") 462 logger.info(" If you put 'auto', an automatic directory PROC_XX_n will be created.") 463 logger.info(" options:",'$MG:BOLD') 464 logger.info(" -f: force cleaning of the directory if it already exists") 465 logger.info(" -d: specify other MG/ME directory") 466 logger.info(" -noclean: no cleaning performed in \"path\".") 467 logger.info(" -nojpeg: no jpeg diagrams will be generated.") 468 logger.info(" --noeps=True: no jpeg and eps diagrams will be generated.") 469 logger.info(" -name: the postfix of the main file in pythia8 mode.") 470 logger.info(" --jamp_optim=[True|False]: [madevent(default:True)|standalone(default:False)] allows a more efficient code computing the color-factor.") 471 logger.info(" --t_strategy: [madevent] allows to change ordering strategy for t-channel.") 472 logger.info(" --hel_recycling=False: [madevent] forbids helicity recycling optimization") 473 logger.info(" Examples:",'$MG:color:GREEN') 474 logger.info(" output",'$MG:color:GREEN') 475 logger.info(" output standalone MYRUN -f",'$MG:color:GREEN') 476 logger.info(" output pythia8 ../pythia8/ -name qcdprocs",'$MG:color:GREEN')
477
478 - def help_check(self):
479 logger.info("syntax: check [" + "|".join(self._check_opts) + "] [param_card] process_definition [--energy=] [--split_orders=] [--reduction=]",'$MG:color:BLUE') 480 logger.info("-- check a process or set of processes.",'$MG:BOLD') 481 logger.info("General options:",'$MG:BOLD') 482 logger.info("o full:",'$MG:color:GREEN') 483 logger.info(" Perform all four checks described below:") 484 logger.info(" permutation, brs, gauge and lorentz_invariance.") 485 logger.info("o permutation:",'$MG:color:GREEN') 486 logger.info(" Check that the model and MG5 are working properly") 487 logger.info(" by generating permutations of the process and checking") 488 logger.info(" that the resulting matrix elements give the same value.") 489 logger.info("o gauge:",'$MG:color:GREEN') 490 logger.info(" Check that processes are gauge invariant by ") 491 logger.info(" comparing Feynman and unitary gauges.") 492 logger.info(" This check is, for now, not available for loop processes.") 493 logger.info("o brs:",'$MG:color:GREEN') 494 logger.info(" Check that the Ward identities are satisfied if the ") 495 logger.info(" process has at least one massless gauge boson as an") 496 logger.info(" external particle.") 497 logger.info("o lorentz_invariance:",'$MG:color:GREEN') 498 logger.info(" Check that the amplitude is lorentz invariant by") 499 logger.info(" comparing the amplitiude in different frames") 500 logger.info("o cms:",'$MG:color:GREEN') 501 logger.info(" Check the complex mass scheme consistency by comparing") 502 logger.info(" it to the narrow width approximation in the off-shell") 503 logger.info(" region of detected resonances and by progressively") 504 logger.info(" decreasing the width. Additional options for this check are:") 505 logger.info(" --offshellness=f : f is a positive or negative float specifying ") 506 logger.info(" the distance from the pole as f*particle_mass. Default is 10.0") 507 logger.info(" --seed=i : to force a specific RNG integer seed i (default is fixed to 0)") 508 logger.info(" --cms=order1&order2;...,p1->f(p,lambdaCMS)&p2->f2(p,lambdaCMS);...") 509 logger.info(" 'order_i' specifies the expansion orders considered for the test.") 510 logger.info(" The substitution lists specifies how internal parameter must be modified") 511 logger.info(" with the width scaling 'lambdaCMS'. The default value for this option is:") 512 logger.info(" --cms=QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS ") 513 logger.info(" The number of order and parameters don't have to be the same.") 514 logger.info(" The scaling must be specified so that one occurrence of the coupling order.") 515 logger.info(" brings in exactly one power of lambdaCMS.") 516 logger.info(" --recompute_width= never|first_time|always|auto") 517 logger.info(" Decides when to use MadWidth to automatically recompute the width") 518 logger.info(" 'auto' (default) let MG5 chose the most appropriate behavior.") 519 logger.info(" 'never' uses the default width value for lambdaCMS=1.0.") 520 logger.info(" 'first_time' uses MadWidth to compute the width for lambdaCMS=1.0.") 521 logger.info(" 'first_time' and 'never' assume linear scaling of the widths with lambdaCMS") 522 logger.info(" 'always' uses MadWidth to compute the widths for all values of lambdaCMS") 523 logger.info(" the test relies on linear scaling of the width, so 'always' is ") 524 logger.info(" only for double-checks") 525 logger.info(" --lambdaCMS = <python_list> : specifies the list of lambdaCMS values to ") 526 logger.info(" use for the test. For example: '[(1/2.0)**exp\ for\ exp\ in\ range(0,20)]'") 527 logger.info(" In the list expression, you must escape spaces. Also, this option") 528 logger.info(" *must* appear last in the otpion list. Finally, the default value is '1.0e-6'") 529 logger.info(" for which an optimal list of progressive values is picked up to 1.0e-6") 530 logger.info(" --show_plot = True or False: Whether to show plot during analysis (default is True)") 531 logger.info(" --report = concise or full: Whether return a concise or full report.") 532 logger.info("Comments",'$MG:color:GREEN') 533 logger.info(" > If param_card is given, that param_card is used ") 534 logger.info(" instead of the default values for the model.") 535 logger.info(" If that file is an (LHE) event file. The param_card of the banner") 536 logger.info(" is used and the first event compatible with the requested process") 537 logger.info(" is used for the computation of the square matrix elements") 538 logger.info(" > \"--energy=\" allows to change the default value of sqrt(S).") 539 logger.info(" > Except for the 'gauge' test, all checks above are also") 540 logger.info(" available for loop processes with ML5 ('virt=' mode)") 541 logger.info("Example: check full p p > j j",'$MG:color:GREEN') 542 logger.info("Using leshouches file as input",'$MG:color:GREEN') 543 logger.info(" use the option --events=PATH") 544 logger.info(" zipped file are not supported") 545 logger.info(" to loop over the file use the option --skip_evt=X") 546 logger.info("") 547 logger.info("Options for loop processes only:",'$MG:BOLD') 548 logger.info("o timing:",'$MG:color:GREEN') 549 logger.info(" Generate and output a process and returns detailed") 550 logger.info(" information about the code and a timing benchmark.") 551 logger.info("o stability:",'$MG:color:GREEN') 552 logger.info(" Generate and output a process and returns detailed") 553 logger.info(" statistics about the numerical stability of the code.") 554 logger.info("o profile:",'$MG:color:GREEN') 555 logger.info(" Performs both the timing and stability analysis at once") 556 logger.info(" and outputs the result in a log file without prompting") 557 logger.info(" it to the user.") 558 logger.info("Comments",'$MG:color:GREEN') 559 logger.info(" > These checks are only available for ML5 ('virt=' mode)") 560 logger.info(" > For the 'profile' and 'stability' checks, you can chose") 561 logger.info(" how many PS points should be used for the statistic by") 562 logger.info(" specifying it as an integer just before the [param_card]") 563 logger.info(" optional argument.") 564 logger.info(" > Notice multiparticle labels cannot be used with these checks.") 565 logger.info(" > \"--reduction=\" allows to change what reduction methods should be used.") 566 logger.info(" > \"--split_orders=\" allows to change what specific combination of coupling orders to consider.") 567 logger.info(" > For process syntax, please see help generate.") 568 logger.info(" > In order to save the directory generated or the reuse an existing one") 569 logger.info(" previously generated with the check command, one can add the '-reuse' ") 570 logger.info(" keyword just after the specification of the type of check desired.") 571 logger.info("Example: check profile g g > t t~ [virt=QCD]",'$MG:color:GREEN')
572 573
574 - def help_generate(self):
575 576 logger.info("-- generate diagrams for a given process",'$MG:color:BLUE') 577 logger.info("General leading-order syntax:",'$MG:BOLD') 578 logger.info(" o generate INITIAL STATE > REQ S-CHANNEL > FINAL STATE $ EXCL S-CHANNEL / FORBIDDEN PARTICLES COUP1=ORDER1 COUP2^2=ORDER2 @N") 579 logger.info(" o Example: generate l+ vl > w+ > l+ vl a $ z / a h QED<=3 QCD=0 @1",'$MG:color:GREEN') 580 logger.info(" > Alternative required s-channels can be separated by \"|\":") 581 logger.info(" b b~ > W+ W- | H+ H- > ta+ vt ta- vt~") 582 logger.info(" > If no coupling orders are given, MG5 will try to determine") 583 logger.info(" orders to ensure maximum number of QCD vertices.") 584 logger.info(" > Desired coupling orders combination can be specified directly for") 585 logger.info(" the squared matrix element by appending '^2' to the coupling name.") 586 logger.info(" For example, 'p p > j j QED^2==2 QCD^2==2' selects the QED-QCD") 587 logger.info(" interference terms only. The other two operators '<=' and '>' are") 588 logger.info(" supported. Finally, a negative value COUP^2==-I refers to the") 589 logger.info(" N^(-I+1)LO term in the expansion of the COUP order.") 590 logger.info(" > allowed coupling operator are: \"==\", \"=\", \"<=\" and \">\".") 591 logger.info(" \"==\" request exactly that number of coupling while \"=\" is interpreted as \"<=\".") 592 logger.info(" > To generate a second process use the \"add process\" command") 593 logger.info("Decay chain syntax:",'$MG:BOLD') 594 logger.info(" o core process, decay1, (decay2, (decay2', ...)), ... etc") 595 logger.info(" o Example: generate p p > t~ t QED=0, (t~ > W- b~, W- > l- vl~), t > j j b @2",'$MG:color:GREEN') 596 logger.info(" > Note that identical particles will all be decayed.") 597 logger.info("Loop processes syntax:",'$MG:BOLD') 598 logger.info(" o core process [ <NLO_mode=> LoopOrder1 LoopOrder2 ... ] SQUAREDCOUPi=ORDERi") 599 logger.info(" o Example: generate p p > t~ t QED=0 QCD=2 [ all= QCD ] QCD=6",'$MG:color:GREEN') 600 logger.info(" > Notice that in this format, decay chains are not allowed.") 601 logger.info(" > The LoopOrder(s) defined specify the kind of loops to consider (only QCD for now).") 602 logger.info(" > The coupling restrictions before '[' restrict the orders of born *amplitudes*.") 603 logger.info(" So that in the example above QCD=2 restricts the born amplitude to have at") 604 logger.info(" most QCD=2 and loop amplitudes at most QCD=2+2 (because QCD loops are considered)") 605 logger.info(" > The coupling restrictions after ']' restrict the orders of the matrix element, ") 606 logger.info(" namely the squared amplitudes. In the example above QCD=6 correspond to born") 607 logger.info(" amplitudes with QCD=2 squared against loop amplitudes with QCD=4, adding up to 6.") 608 logger.info(" > The optional <NLO_mode=> can be any of the following ('all=' by default if absent):") 609 logger.info(" all= : Generate all the real-emission and loop diagrams, ready for aMC@NLO runs.") 610 logger.info(" virt= : Generate only the loop diagrams, read for MadLoop standalone checks/runs.") 611 logger.info(" real= : Generate only the real-emission diagrams, for use with alternative OLP. ") 612 logger.info(" > For processes without born amplitudes (i.e. loop-induced like g g > z), please use ") 613 logger.info(" the 'virt=' NLO mode. aMC@NLO cannot integrate these processes, but standalone MadLoop5") 614 logger.info(" can still handle these.")
615
616 - def help_add(self):
617 logger.info("-- generate diagrams for a process and add to existing processes",'$MG:color:BLUE') 618 logger.info(" OR merge two model",'$MG:color:BLUE') 619 logger.info('') 620 logger.info("-- generate diagrams for a process and add to existing processes",'$MG:color:BLUE') 621 logger.info("General leading-order syntax:",'$MG:BOLD') 622 logger.info(" o add process INITIAL STATE > REQ S-CHANNEL > FINAL STATE $ EXCL S-CHANNEL / FORBIDDEN PARTICLES COUP1=ORDER1 COUP2=ORDER2 @N") 623 logger.info(" o Example: add process l+ vl > w+ > l+ vl a $ z / a h QED=3 QCD=0 @1",'$MG:color:GREEN') 624 logger.info(" > Alternative required s-channels can be separated by \"|\":") 625 logger.info(" b b~ > W+ W- | H+ H- > ta+ vt ta- vt~") 626 logger.info(" > If no coupling orders are given, MG5 will try to determine") 627 logger.info(" orders to ensure maximum number of QCD vertices.") 628 logger.info(" > Note that if there are more than one non-QCD coupling type,") 629 logger.info(" coupling orders need to be specified by hand.") 630 logger.info("Decay chain syntax:",'$MG:BOLD') 631 logger.info(" o core process, decay1, (decay2, (decay2', ...)), ... etc") 632 logger.info(" o Example: add process p p > t~ t QED=0, (t~ > W- b~, W- > l- vl~), t > j j b @2",'$MG:color:GREEN') 633 logger.info(" > Note that identical particles will all be decayed.") 634 logger.info("Loop processes syntax:",'$MG:BOLD') 635 logger.info(" o core process [ <NLO_mode=> LoopOrder1 LoopOrder2 ... ] SQUAREDCOUPi=ORDERi") 636 logger.info(" o Example: add process p p > t~ t QED=0 QCD=2 [ all= QCD ] QCD=6",'$MG:color:GREEN') 637 logger.info(" > Notice that in this format, decay chains are not allowed.") 638 logger.info(" > The LoopOrder(s) defined specify the kind of loops to consider (only QCD for now).") 639 logger.info(" > The coupling restrictions before '[' restrict the orders of born *amplitudes*.") 640 logger.info(" So that in the example above QCD=2 restricts the born amplitude to have at") 641 logger.info(" most QCD=2 and loop amplitudes at most QCD=2+2 (because QCD loops are considered)") 642 logger.info(" > The coupling restrictions after ']' restrict the orders of the matrix element, ") 643 logger.info(" namely the squared amplitudes. In the example above QCD=6 correspond to born") 644 logger.info(" amplitudes with QCD=2 squared against loop amplitudes with QCD=4, adding up to 6.") 645 logger.info(" > The optional <NLO_mode=> can be any of the following ('all=' by default if absent):") 646 logger.info(" all= : Generate all the real-emission and loop diagrams, ready for aMC@NLO runs.") 647 logger.info(" virt= : Generate only the loop diagrams, read for MadLoop standalone checks/runs.") 648 logger.info(" real= : Generate only the real-emission diagrams, for use with alternative OLP. ") 649 logger.info(" > For processes without born amplitudes (i.e. loop-induced like g g > z), please use ") 650 logger.info(" the 'virt=' NLO mode. aMC@NLO cannot integrate these processes, but standalone MadLoop5") 651 logger.info(" can still handle these.") 652 653 logger.info("-- merge two model to create a new one", '$MG:color:BLUE') 654 logger.info("syntax:",'$MG:BOLD') 655 logger.info(" o add model MODELNAME [OPTIONS]") 656 logger.info(" o Example: add model taudecay",'$MG:color:GREEN') 657 logger.info(" > Merge the two model in a single one. If that same merge was done before.") 658 logger.info(" > Just reload the previous merge. (WARNING: This doesn't check if those model are modified)") 659 logger.info(" > Options:") 660 logger.info(" --output= : Specify the name of the directory where the merge is done.") 661 logger.info(" This allow to do \"import NAME\" to load that merge.") 662 logger.info(" --recreate : Force to recreated the merge model even if the merge model directory already exists.")
663
664 - def help_convert(self):
665 logger.info("syntax: convert model FULLPATH") 666 logger.info("modify (in place) the UFO model to make it compatible with both python2 and python3")
667
668 - def help_compute_widths(self):
669 logger.info("syntax: calculate_width PART [other particles] [OPTIONS]") 670 logger.info(" Computes the width and partial width for a set of particles") 671 logger.info(" Returns a valid param_card with this information.") 672 logger.info(" ") 673 logger.info(" PART: name of the particle you want to calculate width") 674 logger.info(" you can enter either the name or pdg code.\n") 675 logger.info(" Various options:\n") 676 logger.info(" --body_decay=X: Parameter to control the precision of the computation") 677 logger.info(" if X is an integer, we compute all channels up to X-body decay.") 678 logger.info(" if X <1, then we stop when the estimated error is lower than X.") 679 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer") 680 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.") 681 logger.info(" default: 4.0025") 682 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.") 683 logger.info(" default: precision (decimal part of the body_decay options) divided by four") 684 logger.info(" --precision_channel=X: requested numerical precision for each channel") 685 logger.info(" default: 0.01") 686 logger.info(" --path=X: path for param_card") 687 logger.info(" default: take value from the model") 688 logger.info(" --output=X: path where to write the resulting card. ") 689 logger.info(" default: overwrite input file. If no input file, write it in the model directory") 690 logger.info(" --nlo: Compute NLO width [if the model support it]") 691 logger.info("") 692 logger.info(" example: calculate_width h --body_decay=2 --output=./param_card")
693
694 - def help_decay_diagram(self):
695 logger.info("syntax: decay_diagram PART [other particles] [OPTIONS]") 696 logger.info(" Returns the amplitude required for the computation of the widths") 697 logger.info(" ") 698 logger.info(" PART: name of the particle you want to calculate width") 699 logger.info(" you can enter either the name or pdg code.\n") 700 logger.info(" Various options:\n") 701 logger.info(" --body_decay=X: Parameter to control the precision of the computation") 702 logger.info(" if X is an integer, we compute all channels up to X-body decay.") 703 logger.info(" if X <1, then we stop when the estimated error is lower than X.") 704 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer") 705 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.") 706 logger.info(" default: 4.0025") 707 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.") 708 logger.info(" default: precision (decimal part of the body_decay options) divided by four") 709 logger.info(" --precision_channel=X: requested numerical precision for each channel") 710 logger.info(" default: 0.01") 711 logger.info(" --path=X: path for param_card") 712 logger.info(" default: take value from the model") 713 logger.info(" --output=X: path where to write the resulting card. ") 714 logger.info(" default: overwrite input file. If no input file, write it in the model directory") 715 logger.info("") 716 logger.info(" example: calculate_width h --body_decay=2 --output=./param_card")
717
718 - def help_define(self):
719 logger.info("-- define a multiparticle",'$MG:color:BLUE') 720 logger.info("Syntax: define multipart_name [=] part_name_list") 721 logger.info("Example: define p = g u u~ c c~ d d~ s s~ b b~",'$MG:color:GREEN') 722 logger.info("Special syntax: Use | for OR (used for required s-channels)") 723 logger.info("Special syntax: Use / to remove particles. Example: define q = p / g")
724
725 - def help_set(self):
726 logger.info("-- set options for generation or output.",'$MG:color:BLUE') 727 logger.info("syntax: set <option_name> <option_value>",'$MG:BOLD') 728 logger.info("Possible options are: ") 729 for opts in [self._set_options[i*3:(i+1)*3] for i in \ 730 range((len(self._set_options)//4)+1)]: 731 logger.info("%s"%(','.join(opts)),'$MG:color:GREEN') 732 logger.info("Details of each option:") 733 logger.info("group_subprocesses True/False/Auto: ",'$MG:color:GREEN') 734 logger.info(" > (default Auto) Smart grouping of subprocesses into ") 735 logger.info(" directories, mirroring of initial states, and ") 736 logger.info(" combination of integration channels.") 737 logger.info(" > Example: p p > j j j w+ gives 5 directories and 184 channels",'$MG:BOLD') 738 logger.info(" (cf. 65 directories and 1048 channels for regular output)",'$MG:BOLD') 739 logger.info(" > Auto means False for decay computation and True for collisions.") 740 logger.info("ignore_six_quark_processes multi_part_label",'$MG:color:GREEN') 741 logger.info(" > (default none) ignore processes with at least 6 of any") 742 logger.info(" of the quarks given in multi_part_label.") 743 logger.info(" > These processes give negligible contribution to the") 744 logger.info(" cross section but have subprocesses/channels.") 745 logger.info("stdout_level DEBUG|INFO|WARNING|ERROR|CRITICAL",'$MG:color:GREEN') 746 logger.info(" > change the default level for printed information") 747 logger.info("fortran_compiler NAME",'$MG:color:GREEN') 748 logger.info(" > (default None) Force a specific fortran compiler.") 749 logger.info(" If None, it tries first g77 and if not present gfortran") 750 logger.info(" but loop output use gfortran.") 751 logger.info("loop_optimized_output True|False",'$MG:color:GREEN') 752 logger.info(" > Exploits the open loop thechnique for considerable") 753 logger.info(" improvement.") 754 logger.info(" > CP relations among helicites are detected and the helicity") 755 logger.info(" filter has more potential.") 756 logger.info("loop_color_flows True|False",'$MG:color:GREEN') 757 logger.info(" > Only relevant for the loop optimized output.") 758 logger.info(" > Reduces the loop diagrams at the amplitude level") 759 logger.info(" rendering possible the computation of the loop amplitude") 760 logger.info(" for a fixed color flow or color configuration.") 761 logger.info(" > This option can considerably slow down the loop ME") 762 logger.info(" computation time, especially when summing over all color") 763 logger.info(" and helicity configuration, hence turned off by default.") 764 logger.info("gauge unitary|Feynman|axial",'$MG:color:GREEN') 765 logger.info(" > (default unitary) choose the gauge of the non QCD part.") 766 logger.info(" > For loop processes, only Feynman gauge is employable.") 767 logger.info("complex_mass_scheme True|False",'$MG:color:GREEN') 768 logger.info(" > (default False) Set complex mass scheme.") 769 logger.info(" > Complex mass scheme is not yet supported for loop processes.") 770 logger.info("timeout VALUE",'$MG:color:GREEN') 771 logger.info(" > (default 20) Seconds allowed to answer questions.") 772 logger.info(" > Note that pressing tab always stops the timer.") 773 logger.info("cluster_temp_path PATH",'$MG:color:GREEN') 774 logger.info(" > (default None) [Used in Madevent Output]") 775 logger.info(" > Allow to perform the run in PATH directory") 776 logger.info(" > This allow to not run on the central disk. ") 777 logger.info(" > This is not used by condor cluster (since condor has") 778 logger.info(" its own way to prevent it).") 779 logger.info("mg5amc_py8_interface_path PATH",'$MG:color:GREEN') 780 logger.info(" > Necessary when showering events with Pythia8 from Madevent.") 781 logger.info("OLP ProgramName",'$MG:color:GREEN') 782 logger.info(" > (default 'MadLoop') [Used for virtual generation]") 783 logger.info(" > Chooses what One-Loop Program to use for the virtual") 784 logger.info(" > matrix element generation via the BLAH accord.") 785 logger.info("output_dependencies <mode>",'$MG:color:GREEN') 786 logger.info(" > (default 'external') [Use for NLO outputs]") 787 logger.info(" > Choses how the external dependences (such as CutTools)") 788 logger.info(" > of NLO outputs are handled. Possible values are:") 789 logger.info(" o external: Some of the libraries the output depends") 790 logger.info(" on are links to their installation in MG5 root dir.") 791 logger.info(" o internal: All libraries the output depends on are") 792 logger.info(" copied and compiled locally in the output directory.") 793 logger.info(" o environment_paths: The location of all libraries the ") 794 logger.info(" output depends on should be found in your env. paths.") 795 logger.info("max_npoint_for_channel <value>",'$MG:color:GREEN') 796 logger.info(" > (default '0') [Used ONLY for loop-induced outputs with madevent]") 797 logger.info(" > Sets the maximum 'n' of n-points loops to be used for") 798 logger.info(" > setting up the integration multichannels.") 799 logger.info(" > The default value of zero automatically picks the apparent") 800 logger.info(" > appropriate choice which is to sometimes pick box loops") 801 logger.info(" > but never higher n-points ones.") 802 logger.info("max_t_for_channel <value>",'$MG:color:GREEN') 803 logger.info(" > (default '0') [Used ONLY for tree-level output with madevent]") 804 logger.info(" > Forbids the inclusion of channel of integration with more than X") 805 logger.info(" > T channel propagators. Such channel can sometimes be quite slow to integrate") 806 logger.info("zerowidth_tchannel <value>",'$MG:color:GREEN') 807 logger.info(" > (default: True) [Used ONLY for tree-level output with madevent]") 808 logger.info(" > set the width to zero for all T-channel propagator --no impact on complex-mass scheme mode") 809 logger.info("auto_convert_model <value>",'$MG:color:GREEN') 810 logger.info(" > (default: False) If set on True any python2 UFO model will be automatically converted to pyton3 format")
811 #===============================================================================
812 # CheckValidForCmd 813 #=============================================================================== 814 -class CheckValidForCmd(cmd.CheckCmd):
815 """ The Series of help routine for the MadGraphCmd""" 816
817 - class RWError(MadGraph5Error):
818 """a class for read/write errors"""
819
820 - def check_add(self, args):
821 """check the validity of line 822 syntax: add process PROCESS | add model MODELNAME 823 """ 824 825 if len(args) < 2: 826 self.help_add() 827 raise self.InvalidCmd('\"add\" requires at least two arguments') 828 829 if args[0] not in ['model', 'process']: 830 raise self.InvalidCmd('\"add\" requires the argument \"process\" or \"model\"') 831 832 if args[0] == 'process': 833 return self.check_generate(args) 834 835 if args[0] == 'model': 836 pass
837 838
839 - def check_define(self, args):
840 """check the validity of line 841 syntax: define multipart_name [ part_name_list ] 842 """ 843 844 if len(args) < 2: 845 self.help_define() 846 raise self.InvalidCmd('\"define\" command requires at least two arguments') 847 848 if args[1] == '=': 849 del args[1] 850 if len(args) < 2: 851 self.help_define() 852 raise self.InvalidCmd('\"define\" command requires at least one particles name after \"=\"') 853 854 if '=' in args: 855 self.help_define() 856 raise self.InvalidCmd('\"define\" command requires symbols \"=\" at the second position') 857 858 if not self._curr_model: 859 logger.info('No model currently active. Try with the Standard Model') 860 self.do_import('model sm') 861 862 if self._curr_model['particles'].find_name(args[0]): 863 raise self.InvalidCmd("label %s is a particle name in this model\n\ 864 Please retry with another name." % args[0])
865
866 - def check_display(self, args):
867 """check the validity of line 868 syntax: display XXXXX 869 """ 870 871 if len(args) < 1: 872 self.help_display() 873 raise self.InvalidCmd('display requires an argument specifying what to display') 874 if args[0] not in self._display_opts + ['model_list']: 875 self.help_display() 876 raise self.InvalidCmd('Invalid arguments for display command: %s' % args[0]) 877 878 if not self._curr_model: 879 raise self.InvalidCmd("No model currently active, please import a model!") 880 881 # check that either _curr_amps or _fks_multi_proc exists 882 if (args[0] in ['processes', 'diagrams'] and not self._curr_amps and not self._fks_multi_proc): 883 raise self.InvalidCmd("No process generated, please generate a process!") 884 if args[0] == 'checks' and not self._comparisons and not self._cms_checks: 885 raise self.InvalidCmd("No check results to display.") 886 887 if args[0] == 'variable' and len(args) !=2: 888 raise self.InvalidCmd('variable need a variable name')
889 890
891 - def check_draw(self, args):
892 """check the validity of line 893 syntax: draw DIRPATH [option=value] 894 """ 895 896 if len(args) < 1: 897 args.append('/tmp') 898 899 if not self._curr_amps: 900 raise self.InvalidCmd("No process generated, please generate a process!") 901 902 if not os.path.isdir(args[0]): 903 raise self.InvalidCmd( "%s is not a valid directory for export file" % args[0])
904
905 - def check_check(self, args):
906 """check the validity of args""" 907 908 if not self._curr_model: 909 raise self.InvalidCmd("No model currently active, please import a model!") 910 911 if self._model_v4_path: 912 raise self.InvalidCmd(\ 913 "\"check\" not possible for v4 models") 914 915 if len(args) < 2 and not args[0].lower().endswith('options'): 916 self.help_check() 917 raise self.InvalidCmd("\"check\" requires a process.") 918 919 if args[0] not in self._check_opts and \ 920 not args[0].lower().endswith('options'): 921 args.insert(0, 'full') 922 923 param_card = None 924 if args[0] not in ['stability','profile','timing'] and \ 925 len(args)>1 and os.path.isfile(args[1]): 926 param_card = args.pop(1) 927 928 if len(args)>1: 929 if args[1] != "-reuse": 930 args.insert(1, '-no_reuse') 931 else: 932 args.append('-no_reuse') 933 934 if args[0] in ['timing'] and len(args)>2 and os.path.isfile(args[2]): 935 param_card = args.pop(2) 936 if args[0] in ['stability', 'profile'] and len(args)>1: 937 # If the first argument after 'stability' is not the integer 938 # specifying the desired statistics (i.e. number of points), then 939 # we insert the default value 100 940 try: 941 int(args[2]) 942 except ValueError: 943 args.insert(2, '100') 944 945 if args[0] in ['stability', 'profile'] and os.path.isfile(args[3]): 946 param_card = args.pop(3) 947 if any([',' in elem for elem in args if not elem.startswith('--')]): 948 raise self.InvalidCmd('Decay chains not allowed in check') 949 950 user_options = {'--energy':'1000','--split_orders':'-1', 951 '--reduction':'1|3|5|6','--CTModeRun':'-1', 952 '--helicity':'-1','--seed':'-1','--collier_cache':'-1', 953 '--collier_req_acc':'auto', 954 '--collier_internal_stability_test':'False', 955 '--collier_mode':'1', 956 '--events': None, 957 '--skip_evt':0} 958 959 if args[0] in ['cms'] or args[0].lower()=='cmsoptions': 960 # increase the default energy to 5000 961 user_options['--energy']='5000' 962 # The first argument gives the name of the coupling order in which 963 # the cms expansion is carried, and the expression following the 964 # comma gives the relation of an external parameter with the 965 # CMS expansions parameter called 'lambdaCMS'. 966 parameters = ['aewm1->10.0/lambdaCMS','as->0.1*lambdaCMS'] 967 user_options['--cms']='QED&QCD,'+'&'.join(parameters) 968 # Widths are assumed to scale linearly with lambdaCMS unless 969 # --force_recompute_width='always' or 'first_time' is used. 970 user_options['--recompute_width']='auto' 971 # It can be negative so as to be offshell below the resonant mass 972 user_options['--offshellness']='10.0' 973 # Pick the lambdaCMS values for the test. Instead of a python list 974 # we specify here (low,N) which means that do_check will automatically 975 # pick lambda values up to the value low and with N values uniformly 976 # spread in each interval [1.0e-i,1.0e-(i+1)]. 977 # Some points close to each other will be added at the end for the 978 # stability test. 979 user_options['--lambdaCMS']='(1.0e-6,5)' 980 # Set the RNG seed, -1 is default (random). 981 user_options['--seed']=666 982 # The option below can help the user re-analyze existing pickled check 983 user_options['--analyze']='None' 984 # Decides whether to show plot or not during the analysis 985 user_options['--show_plot']='True' 986 # Decides what kind of report 987 user_options['--report']='concise' 988 # 'secret' option to chose by which lambda power one should divide 989 # the nwa-cms difference. Useful to set to 2 when doing the Born check 990 # to see whether the NLO check will have sensitivity to the CMS 991 # implementation 992 user_options['--diff_lambda_power']='1' 993 # Sets the range of lambda values to plot 994 user_options['--lambda_plot_range']='[-1.0,-1.0]' 995 # Sets a filter to apply at generation. See name of available 996 # filters in loop_diagram_generations.py, function user_filter 997 user_options['--loop_filter']='None' 998 # Apply tweaks to the check like multiplying a certain width by a 999 # certain parameters or changing the analytical continuation of the 1000 # logarithms of the UV counterterms 1001 user_options['--tweak']='default()' 1002 # Give a name to the run for the files to be saved 1003 user_options['--name']='auto' 1004 # Select what resonances must be run 1005 user_options['--resonances']='1' 1006 1007 for arg in args[:]: 1008 if arg.startswith('--') and '=' in arg: 1009 parsed = arg.split('=') 1010 key, value = parsed[0],'='.join(parsed[1:]) 1011 if key not in user_options: 1012 raise self.InvalidCmd("unknown option %s" % key) 1013 user_options[key] = value 1014 args.remove(arg) 1015 1016 # If we are just re-analyzing saved data or displaying options then we 1017 # shouldn't check the process format. 1018 if not (args[0]=='cms' and '--analyze' in user_options and \ 1019 user_options['--analyze']!='None') and not \ 1020 args[0].lower().endswith('options'): 1021 1022 self.check_process_format(" ".join(args[1:])) 1023 1024 for option, value in user_options.items(): 1025 args.append('%s=%s'%(option,value)) 1026 1027 return param_card
1028
1029 - def check_generate(self, args):
1030 """check the validity of args""" 1031 1032 if not self._curr_model: 1033 logger.info("No model currently active, so we import the Standard Model") 1034 self.do_import('model sm') 1035 1036 if args[-1].startswith('--optimize'): 1037 if args[2] != '>': 1038 raise self.InvalidCmd('optimize mode valid only for 1->N processes. (See model restriction for 2->N)') 1039 if '=' in args[-1]: 1040 path = args[-1].split('=',1)[1] 1041 if not os.path.exists(path) or \ 1042 self.detect_file_type(path) != 'param_card': 1043 raise self.InvalidCmd('%s is not a valid param_card') 1044 else: 1045 path=None 1046 # Update the default value of the model here. 1047 if not isinstance(self._curr_model, model_reader.ModelReader): 1048 self._curr_model = model_reader.ModelReader(self._curr_model) 1049 self._curr_model.set_parameters_and_couplings(path) 1050 self.check_process_format(' '.join(args[1:-1])) 1051 else: 1052 self.check_process_format(' '.join(args[1:]))
1053 1054
1055 - def check_process_format(self, process):
1056 """ check the validity of the string given to describe a format """ 1057 1058 #check balance of paranthesis 1059 if process.count('(') != process.count(')'): 1060 raise self.InvalidCmd('Invalid Format, no balance between open and close parenthesis') 1061 #remove parenthesis for fututre introspection 1062 process = process.replace('(',' ').replace(')',' ') 1063 1064 # split following , (for decay chains) 1065 subprocesses = process.split(',') 1066 if len(subprocesses) > 1: 1067 for subprocess in subprocesses: 1068 self.check_process_format(subprocess) 1069 return 1070 1071 # request that we have one or two > in the process 1072 nbsep = len(re.findall('>\D', process)) # not use process.count because of QCD^2>2 1073 if nbsep not in [1,2]: 1074 raise self.InvalidCmd( 1075 'wrong format for \"%s\" this part requires one or two symbols \'>\', %s found' 1076 % (process, nbsep)) 1077 1078 # we need at least one particles in each pieces 1079 particles_parts = re.split('>\D', process) 1080 for particles in particles_parts: 1081 if re.match(r'^\s*$', particles): 1082 raise self.InvalidCmd( 1083 '\"%s\" is a wrong process format. Please try again' % process) 1084 1085 # '/' and '$' sould be used only after the process definition 1086 for particles in particles_parts[:-1]: 1087 if re.search('\D/', particles): 1088 raise self.InvalidCmd( 1089 'wrong process format: restriction should be place after the final states') 1090 if re.search('\D\$', particles): 1091 raise self.InvalidCmd( 1092 'wrong process format: restriction should be place after the final states') 1093 1094 # '{}' should only be used for onshell particle (including initial/final state) 1095 # check first that polarization are not include between > > 1096 if nbsep == 2: 1097 if '{' in particles_parts[1]: 1098 raise self.InvalidCmd('Polarization restriction can not be used as required s-channel') 1099 split = re.split('\D[$|/]',particles_parts[-1],1) 1100 if len(split)==2: 1101 if '{' in split[1]: 1102 raise self.InvalidCmd('Polarization restriction can not be used in forbidding particles') 1103 1104 if '[' in process and '{' in process: 1105 valid = False 1106 if 'noborn' in process or 'sqrvirt' in process: 1107 valid = True 1108 else: 1109 raise self.InvalidCmd('Polarization restriction can not be used for NLO processes') 1110 1111 # below are the check when [QCD] will be valid for computation 1112 order = process.split('[')[1].split(']')[0] 1113 if '=' in order: 1114 order = order.split('=')[1] 1115 if order.strip().lower() != 'qcd': 1116 raise self.InvalidCmd('Polarization restriction can not be used for generic NLO computations') 1117 1118 1119 for p in particles_parts[1].split(): 1120 if '{' in p: 1121 part = p.split('{')[0] 1122 else: 1123 continue 1124 if self._curr_model: 1125 p = self._curr_model.get_particle(part) 1126 if not p: 1127 if part in self._multiparticles: 1128 for part2 in self._multiparticles[part]: 1129 p = self._curr_model.get_particle(part2) 1130 if p.get('color') != 1: 1131 raise self.InvalidCmd('Polarization restriction can not be used for color charged particles') 1132 continue 1133 if p.get('color') != 1: 1134 raise self.InvalidCmd('Polarization restriction can not be used for color charged particles')
1135 1136 1137
1138 - def check_tutorial(self, args):
1139 """check the validity of the line""" 1140 if len(args) == 1: 1141 if not args[0] in self._tutorial_opts: 1142 self.help_tutorial() 1143 raise self.InvalidCmd('Invalid argument for tutorial') 1144 elif len(args) == 0: 1145 #this means mg5 tutorial 1146 args.append('MadGraph5') 1147 else: 1148 self.help_tutorial() 1149 raise self.InvalidCmd('Too many arguments for tutorial')
1150 1151 1152
1153 - def check_import(self, args):
1154 """check the validity of line""" 1155 1156 modelname = False 1157 prefix = True 1158 if '-modelname' in args: 1159 args.remove('-modelname') 1160 modelname = True 1161 elif '--modelname' in args: 1162 args.remove('--modelname') 1163 modelname = True 1164 1165 if '--noprefix' in args: 1166 args.remove('--noprefix') 1167 prefix = False 1168 1169 if args and args[0] == 'model' and '--last' in args: 1170 # finding last created directory 1171 args.remove('--last') 1172 last_change = 0 1173 to_search = [pjoin(MG5DIR,'models')] 1174 if 'PYTHONPATH' in os.environ: 1175 to_search += os.environ['PYTHONPATH'].split(':') 1176 to_search = [d for d in to_search if os.path.exists(d)] 1177 1178 models = [] 1179 for d in to_search: 1180 for p in misc.glob('*/particles.py', path=d ): 1181 if p.endswith(('__REAL/particles.py','__COMPLEX/particles.py')): 1182 continue 1183 models.append(os.path.dirname(p)) 1184 1185 lastmodel = max(models, key=os.path.getmtime) 1186 logger.info('last model found is %s', lastmodel) 1187 args.insert(1, lastmodel) 1188 1189 if not args: 1190 self.help_import() 1191 raise self.InvalidCmd('wrong \"import\" format') 1192 1193 if len(args) >= 2 and args[0] not in self._import_formats: 1194 self.help_import() 1195 raise self.InvalidCmd('wrong \"import\" format') 1196 elif len(args) == 1: 1197 if args[0] in self._import_formats: 1198 if args[0] != "proc_v4": 1199 self.help_import() 1200 raise self.InvalidCmd('wrong \"import\" format') 1201 elif not self._export_dir: 1202 self.help_import() 1203 raise self.InvalidCmd('PATH is mandatory in the current context\n' + \ 1204 'Did you forget to run the \"output\" command') 1205 # The type of the import is not given -> guess it 1206 format = self.find_import_type(args[0]) 1207 logger.info('The import format was not given, so we guess it as %s' % format) 1208 args.insert(0, format) 1209 if self.history[-1].startswith('import'): 1210 self.history[-1] = 'import %s %s' % \ 1211 (format, ' '.join(self.history[-1].split()[1:])) 1212 1213 if not prefix: 1214 args.append('--noprefix') 1215 1216 if modelname: 1217 args.append('-modelname')
1218 1219 1220
1221 - def check_install(self, args):
1222 """check that the install command is valid""" 1223 1224 1225 install_options = {'options_for_HEPToolsInstaller':[], 1226 'update_options':[]} 1227 hidden_prog = ['Delphes2', 'pythia-pgs','SysCalc'] 1228 1229 if len(args) < 1: 1230 self.help_install() 1231 raise self.InvalidCmd('install command require at least one argument') 1232 1233 if len(args) > 1: 1234 for arg in args[1:]: 1235 try: 1236 option, value = arg.split('=') 1237 except ValueError: 1238 option = arg 1239 value = None 1240 # Options related to the MadGraph installer can be treated here, i.e 1241 if args[0]=='update': 1242 if value is None: 1243 install_options['update_options'].append(option) 1244 else: 1245 install_options['update_options'].append('='.join([option,value])) 1246 else: 1247 # Other options will be directly added to the call to HEPToolsInstallers 1248 # in the advanced_install function 1249 install_options['options_for_HEPToolsInstaller'].append(arg) 1250 # Now that the options have been treated keep only the target tool 1251 # to install as argument. 1252 args = args[:1] 1253 1254 if args[0] not in self._install_opts + hidden_prog + self._advanced_install_opts: 1255 if not args[0].startswith('td'): 1256 self.help_install() 1257 raise self.InvalidCmd('Not recognize program %s ' % args[0]) 1258 1259 if args[0] in ["ExRootAnalysis", "Delphes", "Delphes2"]: 1260 if not misc.which('root'): 1261 raise self.InvalidCmd( 1262 '''In order to install ExRootAnalysis, you need to install Root on your computer first. 1263 please follow information on http://root.cern.ch/drupal/content/downloading-root''') 1264 if 'ROOTSYS' not in os.environ: 1265 raise self.InvalidCmd( 1266 '''The environment variable ROOTSYS is not configured. 1267 You can set it by adding the following lines in your .bashrc [.bash_profile for mac]: 1268 export ROOTSYS=%s 1269 export PATH=$PATH:$ROOTSYS/bin 1270 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ROOTSYS/lib 1271 export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$ROOTSYS/lib 1272 This will take effect only in a NEW terminal 1273 ''' % os.path.realpath(pjoin(misc.which('root'), \ 1274 os.path.pardir, os.path.pardir))) 1275 1276 return install_options
1277
1278 - def check_launch(self, args, options):
1279 """check the validity of the line""" 1280 # modify args in order to be MODE DIR 1281 # mode being either standalone or madevent 1282 if not( 0 <= int(options.cluster) <= 2): 1283 return self.InvalidCmd( 'cluster mode should be between 0 and 2') 1284 1285 if not args: 1286 if self._done_export: 1287 mode = self.find_output_type(self._done_export[0]) 1288 if (self._done_export[1] == 'plugin' and mode in self._export_formats): 1289 args.append(mode) 1290 args.append(self._done_export[0]) 1291 elif self._done_export[1].startswith(mode): 1292 args.append(self._done_export[1]) 1293 args.append(self._done_export[0]) 1294 else: 1295 raise self.InvalidCmd('%s not valid directory for launch' % self._done_export[0]) 1296 return 1297 else: 1298 logger.warning('output command missing, run it automatically (with default argument)') 1299 self.do_output('') 1300 logger.warning('output done: running launch') 1301 return self.check_launch(args, options) 1302 1303 if len(args) != 1: 1304 self.help_launch() 1305 return self.InvalidCmd( 'Invalid Syntax: Too many argument') 1306 1307 # search for a valid path 1308 if os.path.isdir(args[0]): 1309 path = os.path.realpath(args[0]) 1310 elif os.path.isdir(pjoin(MG5DIR,args[0])): 1311 path = pjoin(MG5DIR,args[0]) 1312 elif MG4DIR and os.path.isdir(pjoin(MG4DIR,args[0])): 1313 path = pjoin(MG4DIR,args[0]) 1314 else: 1315 raise self.InvalidCmd('%s is not a valid directory' % args[0]) 1316 1317 mode = self.find_output_type(path) 1318 1319 args[0] = mode 1320 args.append(path) 1321 # inform where we are for future command 1322 self._done_export = [path, mode]
1323 1324
1325 - def find_import_type(self, path):
1326 """ identify the import type of a given path 1327 valid output: model/model_v4/proc_v4/command""" 1328 1329 possibility = [pjoin(MG5DIR,'models',path), \ 1330 pjoin(MG5DIR,'models',path+'_v4'), path] 1331 if '-' in path: 1332 name = path.rsplit('-',1)[0] 1333 possibility = [pjoin(MG5DIR,'models',name), name] + possibility 1334 # Check if they are a valid directory 1335 for name in possibility: 1336 if os.path.isdir(name): 1337 if os.path.exists(pjoin(name,'particles.py')): 1338 return 'model' 1339 elif os.path.exists(pjoin(name,'particles.dat')): 1340 return 'model_v4' 1341 1342 # Not valid directory so maybe a file 1343 if os.path.isfile(path): 1344 text = open(path).read() 1345 pat = re.compile('(Begin process|<MGVERSION>)', re.I) 1346 matches = pat.findall(text) 1347 if not matches: 1348 return 'command' 1349 elif len(matches) > 1: 1350 return 'banner' 1351 elif matches[0].lower() == 'begin process': 1352 return 'proc_v4' 1353 else: 1354 return 'banner' 1355 else: 1356 return 'proc_v4'
1357 1358 1359 1360
1361 - def find_output_type(self, path):
1362 """ identify the type of output of a given directory: 1363 valid output: madevent/standalone/standalone_cpp""" 1364 1365 card_path = pjoin(path,'Cards') 1366 bin_path = pjoin(path,'bin') 1367 src_path = pjoin(path,'src') 1368 include_path = pjoin(path,'include') 1369 subproc_path = pjoin(path,'SubProcesses') 1370 mw_path = pjoin(path,'Source','MadWeight') 1371 1372 if os.path.isfile(pjoin(include_path, 'Pythia.h')) or \ 1373 os.path.isfile(pjoin(include_path, 'Pythia8', 'Pythia.h')): 1374 return 'pythia8' 1375 elif not os.path.isdir(os.path.join(path, 'SubProcesses')): 1376 raise self.InvalidCmd('%s : Not a valid directory' % path) 1377 1378 if os.path.isdir(src_path): 1379 return 'standalone_cpp' 1380 elif os.path.isdir(mw_path): 1381 return 'madweight' 1382 elif os.path.isfile(pjoin(bin_path,'madevent')): 1383 return 'madevent' 1384 elif os.path.isfile(pjoin(bin_path,'aMCatNLO')): 1385 return 'aMC@NLO' 1386 elif os.path.isdir(card_path): 1387 return 'standalone' 1388 1389 raise self.InvalidCmd('%s : Not a valid directory' % path)
1390
1391 - def check_load(self, args):
1392 """ check the validity of the line""" 1393 1394 if len(args) != 2 or args[0] not in self._save_opts: 1395 self.help_load() 1396 raise self.InvalidCmd('wrong \"load\" format')
1397
1398 - def check_customize_model(self, args):
1399 """check the validity of the line""" 1400 1401 # Check argument validity 1402 if len(args) >1 : 1403 self.help_customize_model() 1404 raise self.InvalidCmd('No argument expected for this command') 1405 1406 if len(args): 1407 if not args[0].startswith('--save='): 1408 self.help_customize_model() 1409 raise self.InvalidCmd('Wrong argument for this command') 1410 if '-' in args[0][6:]: 1411 raise self.InvalidCmd('The name given in save options can\'t contain \'-\' symbol.') 1412 1413 if self._model_v4_path: 1414 raise self.InvalidCmd('Restriction of Model is not supported by v4 model.')
1415 1416
1417 - def check_save(self, args):
1418 """ check the validity of the line""" 1419 1420 if len(args) == 0: 1421 args.append('options') 1422 1423 if args[0] not in self._save_opts and args[0] != 'global': 1424 self.help_save() 1425 raise self.InvalidCmd('wrong \"save\" format') 1426 elif args[0] == 'global': 1427 args.insert(0, 'options') 1428 1429 if args[0] != 'options' and len(args) != 2: 1430 self.help_save() 1431 raise self.InvalidCmd('wrong \"save\" format') 1432 elif args[0] != 'options' and len(args) == 2: 1433 basename = os.path.dirname(args[1]) 1434 if not os.path.exists(basename): 1435 raise self.InvalidCmd('%s is not a valid path, please retry' % \ 1436 args[1]) 1437 1438 if args[0] == 'options': 1439 has_path = None 1440 for arg in args[1:]: 1441 if arg in ['--auto', '--all'] or arg in self.options: 1442 continue 1443 elif arg.startswith('--'): 1444 raise self.InvalidCmd('unknow command for \'save options\'') 1445 elif arg == 'global': 1446 if 'HOME' in os.environ: 1447 args.remove('global') 1448 args.insert(1,pjoin(os.environ['HOME'],'.mg5','mg5_configuration.txt')) 1449 has_path = True 1450 else: 1451 basename = os.path.dirname(arg) 1452 if not os.path.exists(basename): 1453 raise self.InvalidCmd('%s is not a valid path, please retry' % \ 1454 arg) 1455 elif has_path: 1456 raise self.InvalidCmd('only one path is allowed') 1457 else: 1458 args.remove(arg) 1459 args.insert(1, arg) 1460 has_path = True 1461 if not has_path: 1462 args.insert(1, pjoin(MG5DIR,'input','mg5_configuration.txt'))
1463 1464
1465 - def check_set(self, args, log=True):
1466 """ check the validity of the line""" 1467 1468 if len(args) == 1 and args[0] in ['complex_mass_scheme',\ 1469 'loop_optimized_output',\ 1470 'loop_color_flows',\ 1471 'low_mem_multicore_nlo_generation']: 1472 args.append('True') 1473 1474 if len(args) > 2 and '=' == args[1]: 1475 args.pop(1) 1476 1477 if len(args) < 2: 1478 self.help_set() 1479 raise self.InvalidCmd('set needs an option and an argument') 1480 1481 if args[1] == 'default': 1482 if args[0] in self.options_configuration: 1483 default = self.options_configuration[args[0]] 1484 elif args[0] in self.options_madgraph: 1485 default = self.options_madgraph[args[0]] 1486 elif args[0] in self.options_madevent: 1487 default = self.options_madevent[args[0]] 1488 else: 1489 raise self.InvalidCmd('%s doesn\'t have a valid default value' % args[0]) 1490 if log: 1491 logger.info('Pass parameter %s to it\'s default value: %s' % 1492 (args[0], default)) 1493 args[1] = str(default) 1494 1495 if args[0] not in self._set_options: 1496 if not args[0] in self.options and not args[0] in self.options: 1497 self.help_set() 1498 raise self.InvalidCmd('Possible options for set are %s' % \ 1499 self._set_options) 1500 1501 if args[0] in ['group_subprocesses']: 1502 if args[1].lower() not in ['false', 'true', 'auto']: 1503 raise self.InvalidCmd('%s needs argument False, True or Auto, got %s' % \ 1504 (args[0], args[1])) 1505 if args[0] in ['ignore_six_quark_processes']: 1506 if args[1] not in list(self._multiparticles.keys()) and args[1].lower() != 'false': 1507 raise self.InvalidCmd('ignore_six_quark_processes needs ' + \ 1508 'a multiparticle name as argument') 1509 1510 if args[0] in ['stdout_level']: 1511 if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] and \ 1512 not args[1].isdigit(): 1513 raise self.InvalidCmd('output_level needs ' + \ 1514 'a valid level') 1515 1516 if args[0] in ['timeout', 'max_npoint_for_channel', 'max_t_for_channel']: 1517 if not args[1].isdigit(): 1518 raise self.InvalidCmd('%s values should be a integer' % args[0]) 1519 1520 if args[0] in ['loop_optimized_output', 'loop_color_flows', 'low_mem_multicore_nlo_generation']: 1521 try: 1522 args[1] = banner_module.ConfigFile.format_variable(args[1], bool, args[0]) 1523 except Exception: 1524 raise self.InvalidCmd('%s needs argument True or False'%args[0]) 1525 1526 if args[0] in ['low_mem_multicore_nlo_generation']: 1527 if args[1]: 1528 if sys.version_info[0] == 2: 1529 if sys.version_info[1] == 6: 1530 raise Exception('python2.6 does not support such functionalities please use python2.7') 1531 #else: 1532 # raise Exception('python3.x does not support such functionalities please use python2.7') 1533 1534 1535 1536 1537 if args[0] in ['gauge']: 1538 if args[1] not in ['unitary','Feynman', 'axial']: 1539 raise self.InvalidCmd('gauge needs argument unitary, axial or Feynman.') 1540 1541 if args[0] in ['timeout']: 1542 if not args[1].isdigit(): 1543 raise self.InvalidCmd('timeout values should be a integer') 1544 1545 if args[0] in ['OLP']: 1546 if args[1] not in MadGraphCmd._OLP_supported: 1547 raise self.InvalidCmd('OLP value should be one of %s'\ 1548 %str(MadGraphCmd._OLP_supported)) 1549 1550 if args[0].lower() in ['ewscheme']: 1551 if not self._curr_model: 1552 raise self.InvalidCmd("ewscheme acts on the current model please load one first.") 1553 if args[1] not in ['external']: 1554 raise self.InvalidCmd('Only valid ewscheme is "external". To restore default, please re-import the model.') 1555 1556 if args[0] in ['output_dependencies']: 1557 if args[1] not in MadGraphCmd._output_dependencies_supported: 1558 raise self.InvalidCmd('output_dependencies value should be one of %s'\ 1559 %str(MadGraphCmd._output_dependencies_supported))
1560
1561 - def check_open(self, args):
1562 """ check the validity of the line """ 1563 1564 if len(args) != 1: 1565 self.help_open() 1566 raise self.InvalidCmd('OPEN command requires exactly one argument') 1567 1568 if args[0].startswith('./'): 1569 if not os.path.isfile(args[0]): 1570 raise self.InvalidCmd('%s: not such file' % args[0]) 1571 return True 1572 1573 # if special : create the path. 1574 if not self._done_export: 1575 if not os.path.isfile(args[0]): 1576 self.help_open() 1577 raise self.InvalidCmd('No command \"output\" or \"launch\" used. Impossible to associate this name to a file') 1578 else: 1579 return True 1580 1581 path = self._done_export[0] 1582 if os.path.isfile(pjoin(path,args[0])): 1583 args[0] = pjoin(path,args[0]) 1584 elif os.path.isfile(pjoin(path,'Cards',args[0])): 1585 args[0] = pjoin(path,'Cards',args[0]) 1586 elif os.path.isfile(pjoin(path,'HTML',args[0])): 1587 args[0] = pjoin(path,'HTML',args[0]) 1588 # special for card with _default define: copy the default and open it 1589 elif '_card.dat' in args[0]: 1590 name = args[0].replace('_card.dat','_card_default.dat') 1591 if os.path.isfile(pjoin(path,'Cards', name)): 1592 files.cp(path + '/Cards/' + name, path + '/Cards/'+ args[0]) 1593 args[0] = pjoin(path,'Cards', args[0]) 1594 else: 1595 raise self.InvalidCmd('No default path for this file') 1596 elif not os.path.isfile(args[0]): 1597 raise self.InvalidCmd('No default path for this file')
1598 1599
1600 - def check_output(self, args, default='madevent'):
1601 """ check the validity of the line""" 1602 1603 if args and args[0] in self._export_formats: 1604 self._export_format = args.pop(0) 1605 elif args: 1606 # check for PLUGIN format 1607 output_cls = misc.from_plugin_import(self.plugin_path, 'new_output', 1608 args[0], warning=True, 1609 info='Output will be done with PLUGIN: %(plug)s') 1610 if output_cls: 1611 self._export_format = 'plugin' 1612 self._export_plugin = output_cls 1613 args.pop(0) 1614 else: 1615 self._export_format = default 1616 else: 1617 self._export_format = default 1618 1619 if not self._curr_model: 1620 text = 'No model found. Please import a model first and then retry.' 1621 raise self.InvalidCmd(text) 1622 1623 if self._model_v4_path and \ 1624 (self._export_format not in self._v4_export_formats): 1625 text = " The Model imported (MG4 format) does not contain enough\n " 1626 text += " information for this type of output. In order to create\n" 1627 text += " output for " + args[0] + ", you have to use a UFO model.\n" 1628 text += " Those model can be imported with MG5> import model NAME." 1629 logger.warning(text) 1630 raise self.InvalidCmd('') 1631 1632 if self._export_format == 'aloha': 1633 return 1634 1635 1636 if not self._curr_amps: 1637 text = 'No processes generated. Please generate a process first.' 1638 raise self.InvalidCmd(text) 1639 1640 if args and args[0][0] != '-': 1641 # This is a path 1642 path = args.pop(0) 1643 forbiden_chars = ['>','<',';','&'] 1644 for char in forbiden_chars: 1645 if char in path: 1646 raise self.InvalidCmd('%s is not allowed in the output path' % char) 1647 # Check for special directory treatment 1648 if path == 'auto' and self._export_format in \ 1649 ['madevent', 'standalone', 'standalone_cpp', 'matchbox_cpp', 'madweight', 1650 'matchbox', 'plugin']: 1651 self.get_default_path() 1652 if '-noclean' not in args and os.path.exists(self._export_dir): 1653 args.append('-noclean') 1654 elif path != 'auto': 1655 if path in ['HELAS', 'tests', 'MadSpin', 'madgraph', 'mg5decay', 'vendor']: 1656 if os.getcwd() == MG5DIR: 1657 raise self.InvalidCmd("This name correspond to a buildin MG5 directory. Please choose another name") 1658 self._export_dir = path 1659 elif path == 'auto': 1660 if self.options['pythia8_path']: 1661 self._export_dir = self.options['pythia8_path'] 1662 else: 1663 self._export_dir = '.' 1664 else: 1665 if self._export_format != 'pythia8': 1666 # No valid path 1667 self.get_default_path() 1668 if '-noclean' not in args and os.path.exists(self._export_dir): 1669 args.append('-noclean') 1670 1671 else: 1672 if self.options['pythia8_path']: 1673 self._export_dir = self.options['pythia8_path'] 1674 else: 1675 self._export_dir = '.' 1676 1677 self._export_dir = os.path.realpath(self._export_dir)
1678 1679
1680 - def check_compute_widths(self, args):
1681 """ check and format calculate decay width: 1682 Expected format: NAME [other names] [--options] 1683 # fill the options if not present. 1684 # NAME can be either (anti-)particle name, multiparticle, pid 1685 """ 1686 1687 if len(args)<1: 1688 self.help_compute_widths() 1689 raise self.InvalidCmd('''compute_widths requires at least the name of one particle. 1690 If you want to compute the width of all particles, type \'compute_widths all\'''') 1691 1692 particles = set() 1693 options = {'path':None, 'output':None, 1694 'min_br':None, 'body_decay':4.0025, 'precision_channel':0.01, 1695 'nlo':False} 1696 # check that the firsts argument is valid 1697 1698 for i,arg in enumerate(args): 1699 if arg.startswith('--'): 1700 if arg.startswith('--nlo'): 1701 options['nlo'] =True 1702 continue 1703 elif not '=' in arg: 1704 raise self.InvalidCmd('Options required an equal (and then the value)') 1705 arg, value = arg.split('=',1) 1706 if arg[2:] not in options: 1707 raise self.InvalidCmd('%s not valid options' % arg) 1708 options[arg[2:]] = value 1709 continue 1710 # check for pid 1711 if arg.isdigit(): 1712 p = self._curr_model.get_particle(int(arg)) 1713 if not p: 1714 raise self.InvalidCmd('Model doesn\'t have pid %s for any particle' % arg) 1715 particles.add(abs(int(arg))) 1716 elif arg in self._multiparticles: 1717 particles.update([abs(id) for id in self._multiparticles[args[0]]]) 1718 else: 1719 if not self._curr_model['case_sensitive']: 1720 arg = arg.lower() 1721 for p in self._curr_model['particles']: 1722 if p['name'] == arg or p['antiname'] == arg: 1723 particles.add(abs(p.get_pdg_code())) 1724 break 1725 else: 1726 if arg == 'all': 1727 #sometimes the multiparticle all is not define 1728 particles.update([abs(p.get_pdg_code()) 1729 for p in self._curr_model['particles']]) 1730 else: 1731 raise self.InvalidCmd('%s invalid particle name' % arg) 1732 1733 if options['path'] and not os.path.isfile(options['path']): 1734 1735 if os.path.exists(pjoin(MG5DIR, options['path'])): 1736 options['path'] = pjoin(MG5DIR, options['path']) 1737 elif self._model_v4_path and os.path.exists(pjoin(self._model_v4_path, options['path'])): 1738 options['path'] = pjoin(self._curr_model_v4_path, options['path']) 1739 elif os.path.exists(pjoin(self._curr_model.path, options['path'])): 1740 options['path'] = pjoin(self._curr_model.path, options['path']) 1741 1742 if os.path.isdir(options['path']) and os.path.isfile(pjoin(options['path'], 'param_card.dat')): 1743 options['path'] = pjoin(options['path'], 'param_card.dat') 1744 elif not os.path.isfile(options['path']): 1745 raise self.InvalidCmd('%s is not a valid path' % args[2]) 1746 # check that the path is indeed a param_card: 1747 if madevent_interface.MadEventCmd.detect_card_type(options['path']) != 'param_card.dat': 1748 raise self.InvalidCmd('%s should be a path to a param_card' % options['path']) 1749 1750 if not options['path']: 1751 param_card_text = self._curr_model.write_param_card() 1752 if not options['output']: 1753 dirpath = self._curr_model.get('modelpath') 1754 options['path'] = pjoin(dirpath, 'param_card.dat') 1755 else: 1756 options['path'] = options['output'] 1757 ff = open(options['path'],'w') 1758 ff.write(param_card_text) 1759 ff.close() 1760 if not options['output']: 1761 options['output'] = options['path'] 1762 1763 if not options['min_br']: 1764 options['min_br'] = (float(options['body_decay']) % 1) / 5 1765 return particles, options
1766 1767 1768 check_decay_diagram = check_compute_widths 1769
1770 - def get_default_path(self):
1771 """Set self._export_dir to the default (\'auto\') path""" 1772 1773 if self._export_format in ['madevent', 'standalone']: 1774 # Detect if this script is launched from a valid copy of the Template, 1775 # if so store this position as standard output directory 1776 if 'TemplateVersion.txt' in os.listdir('.'): 1777 #Check for ./ 1778 self._export_dir = os.path.realpath('.') 1779 return 1780 elif 'TemplateVersion.txt' in os.listdir('..'): 1781 #Check for ../ 1782 self._export_dir = os.path.realpath('..') 1783 return 1784 elif self.stdin != sys.stdin: 1785 #Check for position defined by the input files 1786 input_path = os.path.realpath(self.stdin.name).split(os.path.sep) 1787 print("Not standard stdin, use input path") 1788 if input_path[-2] == 'Cards': 1789 self._export_dir = os.path.sep.join(input_path[:-2]) 1790 if 'TemplateVersion.txt' in self._export_dir: 1791 return 1792 1793 1794 if self._export_format == 'NLO': 1795 name_dir = lambda i: 'PROCNLO_%s_%s' % \ 1796 (self._curr_model['name'], i) 1797 auto_path = lambda i: pjoin(self.writing_dir, 1798 name_dir(i)) 1799 elif self._export_format.startswith('madevent'): 1800 name_dir = lambda i: 'PROC_%s_%s' % \ 1801 (self._curr_model['name'], i) 1802 auto_path = lambda i: pjoin(self.writing_dir, 1803 name_dir(i)) 1804 elif self._export_format.startswith('standalone'): 1805 name_dir = lambda i: 'PROC_SA_%s_%s' % \ 1806 (self._curr_model['name'], i) 1807 auto_path = lambda i: pjoin(self.writing_dir, 1808 name_dir(i)) 1809 elif self._export_format == 'madweight': 1810 name_dir = lambda i: 'PROC_MW_%s_%s' % \ 1811 (self._curr_model['name'], i) 1812 auto_path = lambda i: pjoin(self.writing_dir, 1813 name_dir(i)) 1814 elif self._export_format == 'standalone_cpp': 1815 name_dir = lambda i: 'PROC_SA_CPP_%s_%s' % \ 1816 (self._curr_model['name'], i) 1817 auto_path = lambda i: pjoin(self.writing_dir, 1818 name_dir(i)) 1819 elif self._export_format in ['matchbox_cpp', 'matchbox']: 1820 name_dir = lambda i: 'PROC_MATCHBOX_%s_%s' % \ 1821 (self._curr_model['name'], i) 1822 auto_path = lambda i: pjoin(self.writing_dir, 1823 name_dir(i)) 1824 elif self._export_format in ['plugin']: 1825 name_dir = lambda i: 'PROC_PLUGIN_%s_%s' % \ 1826 (self._curr_model['name'], i) 1827 auto_path = lambda i: pjoin(self.writing_dir, 1828 name_dir(i)) 1829 elif self._export_format == 'pythia8': 1830 if self.options['pythia8_path']: 1831 self._export_dir = self.options['pythia8_path'] 1832 else: 1833 self._export_dir = '.' 1834 return 1835 else: 1836 self._export_dir = '.' 1837 return 1838 for i in range(500): 1839 if os.path.isdir(auto_path(i)): 1840 continue 1841 else: 1842 self._export_dir = auto_path(i) 1843 break 1844 if not self._export_dir: 1845 raise self.InvalidCmd('Can\'t use auto path,' + \ 1846 'more than 500 dirs already')
1847
1848 1849 #=============================================================================== 1850 # CheckValidForCmdWeb 1851 #=============================================================================== 1852 -class CheckValidForCmdWeb(CheckValidForCmd):
1853 """ Check the validity of input line for web entry 1854 (no explicit path authorized)""" 1855
1856 - class WebRestriction(MadGraph5Error):
1857 """class for WebRestriction"""
1858
1859 - def check_draw(self, args):
1860 """check the validity of line 1861 syntax: draw FILEPATH [option=value] 1862 """ 1863 raise self.WebRestriction('direct call to draw is forbidden on the web')
1864
1865 - def check_display(self, args):
1866 """ check the validity of line in web mode """ 1867 1868 if args[0] == 'mg5_variable': 1869 raise self.WebRestriction('Display internal variable is forbidden on the web') 1870 1871 CheckValidForCmd.check_history(self, args)
1872
1873 - def check_check(self, args):
1874 """ Not authorize for the Web""" 1875 1876 raise self.WebRestriction('Check call is forbidden on the web')
1877
1878 - def check_history(self, args):
1879 """check the validity of line 1880 No Path authorize for the Web""" 1881 1882 CheckValidForCmd.check_history(self, args) 1883 1884 if len(args) == 2 and args[1] not in ['.', 'clean']: 1885 raise self.WebRestriction('Path can\'t be specify on the web.')
1886 1887
1888 - def check_import(self, args):
1889 """check the validity of line 1890 No Path authorize for the Web""" 1891 1892 if not args: 1893 raise self.WebRestriction('import requires at least one option') 1894 1895 if args[0] not in self._import_formats: 1896 args[:] = ['command', './proc_card_mg5.dat'] 1897 elif args[0] == 'proc_v4': 1898 args[:] = [args[0], './proc_card.dat'] 1899 elif args[0] == 'command': 1900 args[:] = [args[0], './proc_card_mg5.dat'] 1901 1902 CheckValidForCmd.check_import(self, args)
1903
1904 - def check_install(self, args):
1905 """ No possibility to install new software on the web """ 1906 if args == ['update','--mode=mg5_start']: 1907 return 1908 1909 raise self.WebRestriction('Impossible to install program on the cluster')
1910
1911 - def check_load(self, args):
1912 """ check the validity of the line 1913 No Path authorize for the Web""" 1914 1915 CheckValidForCmd.check_load(self, args) 1916 1917 if len(args) == 2: 1918 if args[0] != 'model': 1919 raise self.WebRestriction('only model can be loaded online') 1920 if 'model.pkl' not in args[1]: 1921 raise self.WebRestriction('not valid pkl file: wrong name') 1922 if not os.path.realpath(args[1]).startswith(pjoin(MG4DIR, \ 1923 'Models')): 1924 raise self.WebRestriction('Wrong path to load model')
1925
1926 - def check_save(self, args):
1927 """ not authorize on web""" 1928 raise self.WebRestriction('\"save\" command not authorize online')
1929
1930 - def check_open(self, args):
1931 """ not authorize on web""" 1932 raise self.WebRestriction('\"open\" command not authorize online')
1933
1934 - def check_output(self, args, default='madevent'):
1935 """ check the validity of the line""" 1936 1937 # first pass to the default 1938 CheckValidForCmd.check_output(self, args, default=default) 1939 args[:] = ['.', '-f'] 1940 1941 self._export_dir = os.path.realpath(os.getcwd()) 1942 # Check that we output madevent 1943 if 'madevent' != self._export_format: 1944 raise self.WebRestriction('only available output format is madevent (at current stage)')
1945
1946 #=============================================================================== 1947 # CompleteForCmd 1948 #=============================================================================== 1949 -class CompleteForCmd(cmd.CompleteCmd):
1950 """ The Series of help routine for the MadGraphCmd""" 1951 1952
1953 - def nlo_completion(self,args,text,line,allowed_loop_mode=None):
1954 """ complete the nlo settings within square brackets. It uses the 1955 allowed_loop_mode for the proposed mode if specified, otherwise, it 1956 uses self._nlo_modes_for_completion""" 1957 1958 # We are now editing the loop related options 1959 # Automatically allow for QCD perturbation if in the sm because the 1960 # loop_sm would then automatically be loaded 1961 nlo_modes = allowed_loop_mode if not allowed_loop_mode is None else \ 1962 self._nlo_modes_for_completion 1963 if isinstance(self._curr_model,loop_base_objects.LoopModel): 1964 pert_couplings_allowed = ['all']+self._curr_model['perturbation_couplings'] 1965 else: 1966 pert_couplings_allowed = [] 1967 if self._curr_model.get('name').startswith('sm'): 1968 pert_couplings_allowed = pert_couplings_allowed + ['QCD'] 1969 # Find wether the loop mode is already set or not 1970 loop_specs = line[line.index('[')+1:] 1971 try: 1972 loop_orders = loop_specs[loop_specs.index('=')+1:] 1973 except ValueError: 1974 loop_orders = loop_specs 1975 possibilities = [] 1976 possible_orders = [order for order in pert_couplings_allowed if \ 1977 order not in loop_orders] 1978 1979 # Simplify obvious loop completion 1980 single_completion = '' 1981 if len(nlo_modes)==1: 1982 single_completion = '%s= '%nlo_modes[0] 1983 if len(possible_orders)==1: 1984 single_completion = single_completion + possible_orders[0] + ' ] ' 1985 # Automatically add a space if not present after [ or = 1986 if text.endswith('['): 1987 if single_completion != '': 1988 return self.list_completion(text, ['[ '+single_completion]) 1989 else: 1990 return self.list_completion(text,['[ ']) 1991 1992 if text.endswith('='): 1993 return self.list_completion(text,[' ']) 1994 1995 if args[-1]=='[': 1996 possibilities = possibilities + ['%s= '%mode for mode in nlo_modes] 1997 if single_completion != '': 1998 return self.list_completion(text, [single_completion]) 1999 else: 2000 if len(possible_orders)==1: 2001 return self.list_completion(text, [poss+' %s ] '%\ 2002 possible_orders[0] for poss in possibilities]) 2003 return self.list_completion(text, possibilities) 2004 2005 if len(possible_orders)==1: 2006 possibilities.append(possible_orders[0]+' ] ') 2007 else: 2008 possibilities.extend(possible_orders) 2009 if any([(order in loop_orders) for order in pert_couplings_allowed]): 2010 possibilities.append(']') 2011 return self.list_completion(text, possibilities)
2012
2013 - def model_completion(self, text, process, line, categories = True, \ 2014 allowed_loop_mode = None, 2015 formatting=True):
2016 """ complete the line with model information. If categories is True, 2017 it will use completion with categories. If allowed_loop_mode is 2018 specified, it will only complete with these loop modes.""" 2019 2020 # First check if we are within squared brackets so that specific 2021 # input for NLO settings must be completed 2022 args = self.split_arg(process) 2023 if len(args) > 2 and '>' in line and '[' in line and not ']' in line: 2024 return self.nlo_completion(args,text,line, allowed_loop_mode = \ 2025 allowed_loop_mode) 2026 2027 while ',' in process: 2028 process = process[process.index(',')+1:] 2029 args = self.split_arg(process) 2030 couplings = [] 2031 2032 # Do no complete the @ for the process number. 2033 if len(args) > 1 and args[-1]=='@': 2034 return 2035 2036 # Automatically allow for QCD perturbation if in the sm because the 2037 # loop_sm would then automatically be loaded 2038 if isinstance(self._curr_model,loop_base_objects.LoopModel): 2039 pert_couplings_allowed = ['all'] + self._curr_model['perturbation_couplings'] 2040 else: 2041 pert_couplings_allowed = [] 2042 if self._curr_model.get('name').startswith('sm'): 2043 pert_couplings_allowed = pert_couplings_allowed + ['QCD'] 2044 2045 # Remove possible identical names 2046 particles = list(set(self._particle_names + list(self._multiparticles.keys()))) 2047 n_part_entered = len([1 for a in args if a in particles]) 2048 2049 # Force '>' if two initial particles. 2050 if n_part_entered == 2 and args[-1] != '>': 2051 return self.list_completion(text, '>') 2052 2053 # Add non-particle names 2054 syntax = [] 2055 couplings = [] 2056 if len(args) > 0 and args[-1] != '>' and n_part_entered > 0: 2057 syntax.append('>') 2058 if '>' in args and args.index('>') < len(args) - 1: 2059 couplings.extend(sum([[c+"<=", c+"==", c+">",c+'^2<=',c+'^2==',c+'^2>' ] for c in \ 2060 self._couplings+['WEIGHTED']],[])) 2061 syntax.extend(['@','$','/','>',',']) 2062 if '[' not in line and ',' not in line and len(pert_couplings_allowed)>0: 2063 syntax.append('[') 2064 2065 # If information for the virtuals has been specified already, do not 2066 # propose syntax or particles input anymore 2067 if '[' in line: 2068 syntax = [] 2069 particles = [] 2070 # But still allow for defining the process id 2071 couplings.append('@') 2072 2073 if not categories: 2074 # The direct completion (might be needed for some completion using 2075 # this function but adding some other completions (like in check)). 2076 # For those, it looks ok in the categorie mode on my mac, but if 2077 # someone sees wierd result on Linux systems, then use the 2078 # default completion for these features. 2079 return self.list_completion(text, particles+syntax+couplings) 2080 else: 2081 # A more elaborate one with categories 2082 poss_particles = self.list_completion(text, particles) 2083 poss_syntax = self.list_completion(text, syntax) 2084 poss_couplings = self.list_completion(text, couplings) 2085 possibilities = {} 2086 if poss_particles != []: possibilities['Particles']=poss_particles 2087 if poss_syntax != []: possibilities['Syntax']=poss_syntax 2088 if poss_couplings != []: possibilities['Coupling orders']=poss_couplings 2089 if len(list(possibilities.keys()))==1: 2090 return self.list_completion(text, list(possibilities.values())[0]) 2091 else: 2092 return self.deal_multiple_categories(possibilities, formatting)
2093
2094 - def complete_generate(self, text, line, begidx, endidx, formatting=True):
2095 "Complete the generate command" 2096 2097 # Return list of particle names and multiparticle names, as well as 2098 # coupling orders and allowed symbols 2099 args = self.split_arg(line[0:begidx]) 2100 2101 valid_sqso_operators=['==','<=','>'] 2102 2103 if any(line.endswith('^2 %s '%op) for op in valid_sqso_operators): 2104 return 2105 if args[-1].endswith('^2'): 2106 return self.list_completion(text,valid_sqso_operators) 2107 match_op = [o for o in valid_sqso_operators if o.startswith(args[-1])] 2108 if len(args)>2 and args[-2].endswith('^2') and len(match_op)>0: 2109 if args[-1] in valid_sqso_operators: 2110 return self.list_completion(text,' ') 2111 if len(match_op)==1: 2112 return self.list_completion(text,[match_op[0][len(args[-1]):]]) 2113 else: 2114 return self.list_completion(text,match_op) 2115 if len(args) > 2 and args[-1] == '@' or ( args[-1].endswith('=') and \ 2116 (not '[' in line or ('[' in line and ']' in line))): 2117 return 2118 2119 try: 2120 return self.model_completion(text, ' '.join(args[1:]),line, formatting) 2121 except Exception as error: 2122 print(error)
2123 2124 #if len(args) > 1 and args[-1] != '>': 2125 # couplings = ['>'] 2126 #if '>' in args and args.index('>') < len(args) - 1: 2127 # couplings = [c + "=" for c in self._couplings] + ['@','$','/','>'] 2128 #return self.list_completion(text, self._particle_names + \ 2129 # self._multiparticles.keys() + couplings) 2130
2131 - def complete_convert(self, text, line, begidx, endidx,formatting=True):
2132 "Complete the compute_widths command" 2133 2134 args = self.split_arg(line[0:begidx]) 2135 2136 # Format 2137 if len(args) == 1: 2138 return self.list_completion(text, ['model']) 2139 elif line[begidx-1] == os.path.sep: 2140 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)]) 2141 return self.path_completion(text, current_dir) 2142 else: 2143 return self.path_completion(text)
2144 2145
2146 - def complete_compute_widths(self, text, line, begidx, endidx,formatting=True):
2147 "Complete the compute_widths command" 2148 2149 args = self.split_arg(line[0:begidx]) 2150 2151 if args[-1] in ['--path=', '--output=']: 2152 completion = {'path': self.path_completion(text)} 2153 elif line[begidx-1] == os.path.sep: 2154 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)]) 2155 if current_dir.startswith('--path='): 2156 current_dir = current_dir[7:] 2157 if current_dir.startswith('--output='): 2158 current_dir = current_dir[9:] 2159 completion = {'path': self.path_completion(text, current_dir)} 2160 else: 2161 completion = {} 2162 completion['options'] = self.list_completion(text, 2163 ['--path=', '--output=', '--min_br=0.\$', 2164 '--precision_channel=0.\$', '--body_decay=', '--nlo']) 2165 completion['particles'] = self.model_completion(text, '', line) 2166 2167 return self.deal_multiple_categories(completion,formatting)
2168 2169 complete_decay_diagram = complete_compute_widths 2170
2171 - def complete_add(self, text, line, begidx, endidx, formatting):
2172 "Complete the add command" 2173 2174 args = self.split_arg(line[0:begidx]) 2175 2176 # Format 2177 if len(args) == 1: 2178 return self.list_completion(text, self._add_opts) 2179 2180 if args[1] == 'process': 2181 return self.complete_generate(text, " ".join(args[1:]), begidx, endidx) 2182 2183 elif args[1] == 'model': 2184 completion_categories = self.complete_import(text, line, begidx, endidx, 2185 allow_restrict=False, formatting=False) 2186 completion_categories['options'] = self.list_completion(text,['--modelname=','--recreate']) 2187 return self.deal_multiple_categories(completion_categories, formatting)
2188
2189 - def complete_customize_model(self, text, line, begidx, endidx):
2190 "Complete the customize_model command" 2191 2192 args = self.split_arg(line[0:begidx]) 2193 2194 # Format 2195 if len(args) == 1: 2196 return self.list_completion(text, ['--save='])
2197 2198
2199 - def complete_check(self, text, line, begidx, endidx, formatting=True):
2200 "Complete the check command" 2201 2202 out = {} 2203 args = self.split_arg(line[0:begidx]) 2204 2205 # Format 2206 if len(args) == 1: 2207 return self.list_completion(text, self._check_opts) 2208 2209 2210 cms_check_mode = len(args) >= 2 and args[1]=='cms' 2211 2212 cms_options = ['--name=','--tweak=','--seed=','--offshellness=', 2213 '--lambdaCMS=','--show_plot=','--report=','--lambda_plot_range=','--recompute_width=', 2214 '--CTModeRun=','--helicity=','--reduction=','--cms=','--diff_lambda_power=', 2215 '--loop_filter=','--resonances='] 2216 2217 options = ['--energy='] 2218 if cms_options: 2219 options.extend(cms_options) 2220 2221 # Directory continuation 2222 if args[-1].endswith(os.path.sep): 2223 return self.path_completion(text, pjoin(*[a for a in args \ 2224 if a.endswith(os.path.sep)])) 2225 # autocompletion for particles/couplings 2226 model_comp = self.model_completion(text, ' '.join(args[2:]),line, 2227 categories = True, allowed_loop_mode=['virt']) 2228 2229 model_comp_and_path = self.deal_multiple_categories(\ 2230 {'Process completion': self.model_completion(text, ' '.join(args[2:]), 2231 line, categories = False, allowed_loop_mode=['virt']), 2232 'Param_card.dat path completion:':self.path_completion(text), 2233 'options': self.list_completion(text,options)}, formatting) 2234 2235 #Special rules for check cms completion 2236 if cms_check_mode: 2237 # A couple of useful value completions 2238 if line[-1]!=' ' and line[-2]!='\\' and not '--' in line[begidx:endidx] \ 2239 and args[-1].startswith('--') and '=' in args[-1]: 2240 examples = { 2241 '--tweak=': 2242 ['default','alltweaks',"['default','allwidths->1.1*all_withds&seed333(Increased_widths_and_seed_333)','logp->logm&logm->logp(inverted_logs)']"], 2243 '--lambdaCMS=': 2244 ['(1.0e-2,5)',"[float('1.0e-%d'%exp)\\ for\\ exp\\ in\\ range(8)]","[1.0,0.5,0.001]"], 2245 '--lambda_plot_range=': 2246 [' [1e-05,1e-02]','[0.01,1.0]'], 2247 '--reduction=': 2248 ['1','1|2|3|4','1|2','3'], 2249 '--cms=': 2250 ['QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS', 2251 'NP&QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS&newExpansionParameter->newExpansionParameter*lambdaCMS'], 2252 '--loop_filter=': 2253 ['None','n>3','n<4 and 6 in loop_pdgs and 3<=id<=7'], 2254 '--resonances=': 2255 ['1','all','(24,(3,4))','[(24,(3,4)),(24,(4,5))]'], 2256 '--analyze=': 2257 ['my_default_run.pkl', 2258 'default_run.pkl,increased_widths.pkl(Increased_widths),logs_modified.pkl(Inverted_logs),seed_668.pkl(Different_seed)'] 2259 } 2260 for name, example in examples.items(): 2261 if args[-1].startswith(name): 2262 return self.deal_multiple_categories( 2263 {"Examples of completion for option '%s'"%args[-1].split('=')[0]: 2264 # ['%d: %s'%(i+1,ex) for i, ex in enumerate(example)]}, 2265 ['%s'%ex for i, ex in enumerate(example)]},formatting, 2266 forceCategory=True) 2267 if args[-1]=='--recompute_width=': 2268 return self.list_completion(text, 2269 ['never','first_time','always','auto']) 2270 elif args[-1]=='--show_plot=': 2271 return self.list_completion(text,['True','False']) 2272 elif args[-1]=='--report=': 2273 return self.list_completion(text,['concise','full']) 2274 elif args[-1]=='--CTModeRun=': 2275 return self.list_completion(text,['-1','1','2','3','4']) 2276 else: 2277 return text 2278 if len(args)==2 or len(args)==3 and args[-1]=='-reuse': 2279 return self.deal_multiple_categories( 2280 {'Process completion': self.model_completion(text, ' '.join(args[2:]), 2281 line, categories = False, allowed_loop_mode=['virt']), 2282 'Param_card.dat path completion:': self.path_completion(text), 2283 'reanalyze result on disk / save output:':self.list_completion( 2284 text,['-reuse','--analyze='])}, 2285 formatting) 2286 elif not any(arg.startswith('--') for arg in args): 2287 if '>' in args: 2288 return self.deal_multiple_categories({'Process completion': 2289 self.model_completion(text, ' '.join(args[2:]), 2290 line, categories = False, allowed_loop_mode=['virt']), 2291 'options': self.list_completion(text,options)}, 2292 formatting) 2293 else: 2294 return self.deal_multiple_categories({'Process completion': 2295 self.model_completion(text, ' '.join(args[2:]), 2296 line, categories = False, allowed_loop_mode=['virt'])}, 2297 formatting) 2298 else: 2299 return self.list_completion(text,options) 2300 2301 if len(args) == 2: 2302 return model_comp_and_path 2303 elif len(args) == 3: 2304 try: 2305 int(args[2]) 2306 except ValueError: 2307 return model_comp 2308 else: 2309 return model_comp_and_path 2310 elif len(args) > 3: 2311 return model_comp
2312 2313
2314 - def complete_tutorial(self, text, line, begidx, endidx):
2315 "Complete the tutorial command" 2316 2317 # Format 2318 if len(self.split_arg(line[0:begidx])) == 1: 2319 return self.list_completion(text, self._tutorial_opts)
2320
2321 - def complete_define(self, text, line, begidx, endidx):
2322 """Complete particle information""" 2323 return self.model_completion(text, line[6:],line)
2324
2325 - def complete_display(self, text, line, begidx, endidx):
2326 "Complete the display command" 2327 2328 args = self.split_arg(line[0:begidx]) 2329 # Format 2330 if len(args) == 1: 2331 return self.list_completion(text, self._display_opts) 2332 2333 if len(args) == 2 and args[1] == 'checks': 2334 return self.list_completion(text, ['failed']) 2335 2336 if len(args) == 2 and args[1] == 'particles': 2337 return self.model_completion(text, line[begidx:],line)
2338
2339 - def complete_draw(self, text, line, begidx, endidx):
2340 "Complete the draw command" 2341 2342 args = self.split_arg(line[0:begidx]) 2343 2344 # Directory continuation 2345 if args[-1].endswith(os.path.sep): 2346 return self.path_completion(text, 2347 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2348 only_dirs = True) 2349 # Format 2350 if len(args) == 1: 2351 return self.path_completion(text, '.', only_dirs = True) 2352 2353 2354 #option 2355 if len(args) >= 2: 2356 opt = ['horizontal', 'external=', 'max_size=', 'add_gap=', 2357 'non_propagating', '--'] 2358 return self.list_completion(text, opt)
2359
2360 - def complete_launch(self, text, line, begidx, endidx,formatting=True):
2361 """ complete the launch command""" 2362 args = self.split_arg(line[0:begidx]) 2363 2364 # Directory continuation 2365 if args[-1].endswith(os.path.sep): 2366 return self.path_completion(text, 2367 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2368 only_dirs = True) 2369 # Format 2370 if len(args) == 1: 2371 out = {'Path from ./': self.path_completion(text, '.', only_dirs = True)} 2372 if MG5DIR != os.path.realpath('.'): 2373 out['Path from %s' % MG5DIR] = self.path_completion(text, 2374 MG5DIR, only_dirs = True, relative=False) 2375 if MG4DIR and MG4DIR != os.path.realpath('.') and MG4DIR != MG5DIR: 2376 out['Path from %s' % MG4DIR] = self.path_completion(text, 2377 MG4DIR, only_dirs = True, relative=False) 2378 2379 2380 #option 2381 if len(args) >= 2: 2382 out={} 2383 2384 if line[0:begidx].endswith('--laststep='): 2385 opt = ['parton', 'pythia', 'pgs','delphes','auto'] 2386 out['Options'] = self.list_completion(text, opt, line) 2387 else: 2388 opt = ['--cluster', '--multicore', '-i', '--name=', '-f','-m', '-n', 2389 '-p','--parton','--interactive', '--laststep=parton', '--laststep=pythia', 2390 '--laststep=pgs', '--laststep=delphes','--laststep=auto'] 2391 out['Options'] = self.list_completion(text, opt, line) 2392 2393 2394 return self.deal_multiple_categories(out,formatting)
2395
2396 - def complete_load(self, text, line, begidx, endidx):
2397 "Complete the load command" 2398 2399 args = self.split_arg(line[0:begidx]) 2400 2401 # Format 2402 if len(args) == 1: 2403 return self.list_completion(text, self._save_opts) 2404 2405 # Directory continuation 2406 if args[-1].endswith(os.path.sep): 2407 return self.path_completion(text, 2408 pjoin(*[a for a in args if \ 2409 a.endswith(os.path.sep)])) 2410 2411 # Filename if directory is not given 2412 if len(args) == 2: 2413 return self.path_completion(text)
2414
2415 - def complete_save(self, text, line, begidx, endidx):
2416 "Complete the save command" 2417 2418 args = self.split_arg(line[0:begidx]) 2419 2420 # Format 2421 if len(args) == 1: 2422 return self.list_completion(text, self._save_opts) 2423 2424 # Directory continuation 2425 if args[-1].endswith(os.path.sep): 2426 return self.path_completion(text, 2427 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2428 only_dirs = True) 2429 2430 # Filename if directory is not given 2431 if len(args) == 2: 2432 return self.path_completion(text) + self.list_completion(text, ['global'])
2433 2434 @cmd.debug()
2435 - def complete_open(self, text, line, begidx, endidx):
2436 """ complete the open command """ 2437 2438 args = self.split_arg(line[0:begidx]) 2439 2440 # Directory continuation 2441 if os.path.sep in args[-1] + text: 2442 return self.path_completion(text, 2443 pjoin(*[a for a in args if \ 2444 a.endswith(os.path.sep)])) 2445 2446 possibility = [] 2447 if self._done_export: 2448 path = self._done_export[0] 2449 possibility = ['index.html'] 2450 if os.path.isfile(pjoin(path,'README')): 2451 possibility.append('README') 2452 if os.path.isdir(pjoin(path,'Cards')): 2453 possibility += [f for f in os.listdir(pjoin(path,'Cards')) 2454 if f.endswith('.dat')] 2455 if os.path.isdir(pjoin(path,'HTML')): 2456 possibility += [f for f in os.listdir(pjoin(path,'HTML')) 2457 if f.endswith('.html') and 'default' not in f] 2458 else: 2459 possibility.extend(['./','../']) 2460 if os.path.exists('MG5_debug'): 2461 possibility.append('MG5_debug') 2462 if os.path.exists('ME5_debug'): 2463 possibility.append('ME5_debug') 2464 2465 return self.list_completion(text, possibility)
2466 2467 @cmd.debug()
2468 - def complete_output(self, text, line, begidx, endidx, 2469 possible_options = ['f', 'noclean', 'nojpeg'], 2470 possible_options_full = ['-f', '-noclean', '-nojpeg', '--noeps=True','--hel_recycling=False', 2471 '--jamp_optim=', '--t_strategy=']):
2472 "Complete the output command" 2473 2474 possible_format = self._export_formats 2475 #don't propose directory use by MG_ME 2476 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS', 2477 'Calculators', 'MadAnalysis', 'SimpleAnalysis', 2478 'mg5', 'DECAY', 'EventConverter', 'Models', 2479 'ExRootAnalysis', 'HELAS', 'Transfer_Fct', 'aloha', 2480 'matchbox', 'matchbox_cpp', 'tests', 'launch'] 2481 2482 #name of the run =>proposes old run name 2483 args = self.split_arg(line[0:begidx]) 2484 if len(args) >= 1: 2485 2486 if len(args) > 1 and args[1] == 'pythia8': 2487 possible_options_full = list(possible_options_full) + ['--version=8.1','--version=8.2'] 2488 2489 if len(args) > 1 and args[1] == 'aloha': 2490 try: 2491 return self.aloha_complete_output(text, line, begidx, endidx) 2492 except Exception as error: 2493 print(error) 2494 # Directory continuation 2495 if args[-1].endswith(os.path.sep): 2496 return [name for name in self.path_completion(text, 2497 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2498 only_dirs = True) if name not in forbidden_names] 2499 # options 2500 if args[-1][0] == '-' or len(args) > 1 and args[-2] == '-': 2501 return self.list_completion(text, possible_options) 2502 2503 if len(args) > 2: 2504 return self.list_completion(text, possible_options_full) 2505 # Formats 2506 if len(args) == 1: 2507 format = possible_format + ['.' + os.path.sep, '..' + os.path.sep, 'auto'] 2508 return self.list_completion(text, format) 2509 2510 # directory names 2511 content = [name for name in self.path_completion(text, '.', only_dirs = True) \ 2512 if name not in forbidden_names] 2513 content += ['auto'] 2514 content += possible_options_full 2515 return self.list_completion(text, content)
2516
2517 - def aloha_complete_output(self, text, line, begidx, endidx,formatting=True):
2518 "Complete the output aloha command" 2519 args = self.split_arg(line[0:begidx]) 2520 completion_categories = {} 2521 2522 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS', 2523 'Calculators', 'MadAnalysis', 'SimpleAnalysis', 2524 'mg5', 'DECAY', 'EventConverter', 'Models', 2525 'ExRootAnalysis', 'Transfer_Fct', 'aloha', 2526 'apidoc','vendor'] 2527 2528 2529 # options 2530 options = ['--format=Fortran', '--format=Python','--format=gpu','--format=CPP','--output='] 2531 options = self.list_completion(text, options) 2532 if options: 2533 completion_categories['options'] = options 2534 2535 if args[-1] == '--output=' or args[-1].endswith(os.path.sep): 2536 # Directory continuation 2537 completion_categories['path'] = [name for name in self.path_completion(text, 2538 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2539 only_dirs = True) if name not in forbidden_names] 2540 2541 else: 2542 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 2543 wf_opt = [] 2544 amp_opt = [] 2545 opt_conjg = [] 2546 for lor in ufomodel.all_lorentz: 2547 amp_opt.append('%s_0' % lor.name) 2548 for i in range(len(lor.spins)): 2549 wf_opt.append('%s_%i' % (lor.name,i+1)) 2550 if i % 2 == 0 and lor.spins[i] == 2: 2551 opt_conjg.append('%sC%i_%i' % (lor.name,i //2 +1,i+1)) 2552 completion_categories['amplitude routines'] = self.list_completion(text, amp_opt) 2553 completion_categories['Wavefunctions routines'] = self.list_completion(text, wf_opt) 2554 completion_categories['conjugate_routines'] = self.list_completion(text, opt_conjg) 2555 2556 return self.deal_multiple_categories(completion_categories,formatting)
2557
2558 - def complete_set(self, text, line, begidx, endidx):
2559 "Complete the set command" 2560 #misc.sprint([text,line,begidx, endidx]) 2561 args = self.split_arg(line[0:begidx]) 2562 2563 # Format 2564 if len(args) == 1: 2565 opts = list(set(list(self.options.keys()) + self._set_options)) 2566 return self.list_completion(text, opts) 2567 2568 if len(args) == 2: 2569 if args[1] in ['group_subprocesses', 'complex_mass_scheme',\ 2570 'loop_optimized_output', 'loop_color_flows',\ 2571 'low_mem_multicore_nlo_generation']: 2572 return self.list_completion(text, ['False', 'True', 'default']) 2573 elif args[1] in ['ignore_six_quark_processes']: 2574 return self.list_completion(text, list(self._multiparticles.keys())) 2575 elif args[1].lower() == 'ewscheme': 2576 return self.list_completion(text, ["external"]) 2577 elif args[1] == 'gauge': 2578 return self.list_completion(text, ['unitary', 'Feynman','default', 'axial']) 2579 elif args[1] == 'OLP': 2580 return self.list_completion(text, MadGraphCmd._OLP_supported) 2581 elif args[1] == 'output_dependencies': 2582 return self.list_completion(text, 2583 MadGraphCmd._output_dependencies_supported) 2584 elif args[1] == 'stdout_level': 2585 return self.list_completion(text, ['DEBUG','INFO','WARNING','ERROR', 2586 'CRITICAL','default']) 2587 elif args[1] == 'fortran_compiler': 2588 return self.list_completion(text, ['f77','g77','gfortran','default']) 2589 elif args[1] == 'cpp_compiler': 2590 return self.list_completion(text, ['g++', 'c++', 'clang', 'default']) 2591 elif args[1] == 'nb_core': 2592 return self.list_completion(text, [str(i) for i in range(100)] + ['default'] ) 2593 elif args[1] == 'run_mode': 2594 return self.list_completion(text, [str(i) for i in range(3)] + ['default']) 2595 elif args[1] == 'cluster_type': 2596 return self.list_completion(text, list(cluster.from_name.keys()) + ['default']) 2597 elif args[1] == 'cluster_queue': 2598 return [] 2599 elif args[1] == 'automatic_html_opening': 2600 return self.list_completion(text, ['False', 'True', 'default']) 2601 else: 2602 # directory names 2603 second_set = [name for name in self.path_completion(text, '.', only_dirs = True)] 2604 return self.list_completion(text, second_set + ['default']) 2605 elif len(args) >2 and args[-1].endswith(os.path.sep): 2606 return self.path_completion(text, 2607 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2608 only_dirs = True)
2609
2610 - def complete_import(self, text, line, begidx, endidx, allow_restrict=True, 2611 formatting=True):
2612 "Complete the import command" 2613 2614 args=self.split_arg(line[0:begidx]) 2615 2616 # Format 2617 if len(args) == 1: 2618 opt = self.list_completion(text, self._import_formats) 2619 if opt: 2620 return opt 2621 mode = 'all' 2622 elif args[1] in self._import_formats: 2623 mode = args[1] 2624 else: 2625 args.insert(1, 'all') 2626 mode = 'all' 2627 2628 completion_categories = {} 2629 # restriction continuation (for UFO) 2630 if mode in ['model', 'all'] and '-' in text: 2631 # deal with - in readline splitting (different on some computer) 2632 path = '-'.join([part for part in text.split('-')[:-1]]) 2633 # remove the final - for the model name 2634 # find the different possibilities 2635 all_name = self.find_restrict_card(path, no_restrict=False) 2636 all_name += self.find_restrict_card(path, no_restrict=False, 2637 base_dir=pjoin(MG5DIR,'models')) 2638 2639 if os.environ['PYTHONPATH']: 2640 for modeldir in os.environ['PYTHONPATH'].split(':'): 2641 if not modeldir: 2642 continue 2643 all_name += self.find_restrict_card(path, no_restrict=False, 2644 base_dir=modeldir) 2645 all_name = list(set(all_name)) 2646 # select the possibility according to the current line 2647 all_name = [name+' ' for name in all_name if name.startswith(text) 2648 and name.strip() != text] 2649 2650 2651 if all_name: 2652 completion_categories['Restricted model'] = all_name 2653 2654 # Path continuation 2655 if os.path.sep in args[-1]: 2656 if mode.startswith('model') or mode == 'all': 2657 # Directory continuation 2658 try: 2659 cur_path = pjoin(*[a for a in args \ 2660 if a.endswith(os.path.sep)]) 2661 except Exception as error: 2662 pass 2663 else: 2664 all_dir = self.path_completion(text, cur_path, only_dirs = True) 2665 if mode in ['model_v4','all']: 2666 completion_categories['Path Completion'] = all_dir 2667 # Only UFO model here 2668 new = [] 2669 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path, online=False)) 2670 for name in all_dir] 2671 if data: 2672 completion_categories['Path Completion'] = all_dir + new 2673 else: 2674 try: 2675 cur_path = pjoin(*[a for a in args \ 2676 if a.endswith(os.path.sep)]) 2677 except Exception: 2678 pass 2679 else: 2680 all_path = self.path_completion(text, cur_path) 2681 if mode == 'all': 2682 new = [] 2683 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path, online=False)) 2684 for name in all_path] 2685 if data: 2686 completion_categories['Path Completion'] = data[0] 2687 else: 2688 completion_categories['Path Completion'] = all_path 2689 2690 # Model directory name if directory is not given 2691 if (len(args) == 2): 2692 is_model = True 2693 if mode == 'model': 2694 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) 2695 mod_name = lambda name: name 2696 elif mode == 'model_v4': 2697 file_cond = lambda p : (os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) 2698 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat'))) 2699 mod_name = lambda name :(name[-3:] != '_v4' and name or name[:-3]) 2700 elif mode == 'all': 2701 mod_name = lambda name: name 2702 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) \ 2703 or os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) \ 2704 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat')) 2705 else: 2706 cur_path = pjoin(*[a for a in args \ 2707 if a.endswith(os.path.sep)]) 2708 all_path = self.path_completion(text, cur_path) 2709 completion_categories['model name'] = all_path 2710 is_model = False 2711 2712 if is_model and os.path.sep not in text: 2713 model_list = [mod_name(name) for name in \ 2714 self.path_completion(text, 2715 pjoin(MG5DIR,'models'), 2716 only_dirs = True) \ 2717 if file_cond(name)] 2718 if mode == 'model' and 'PYTHONPATH' in os.environ: 2719 for modeldir in os.environ['PYTHONPATH'].split(':'): 2720 if not modeldir or not os.path.exists(modeldir): 2721 continue 2722 model_list += [name for name in self.path_completion(text, 2723 modeldir, only_dirs=True) 2724 if os.path.exists(pjoin(modeldir,name, 'particles.py'))] 2725 if mode == 'model': 2726 model_list += [name for name in list(self._online_model.keys())+self._online_model2 2727 if name.startswith(text)] 2728 2729 if mode == 'model_v4': 2730 completion_categories['model name'] = model_list 2731 elif allow_restrict: 2732 # need to update the list with the possible restriction 2733 all_name = [] 2734 for model_name in model_list: 2735 all_name += self.find_restrict_card(model_name, 2736 base_dir=pjoin(MG5DIR,'models')) 2737 else: 2738 all_name = model_list 2739 2740 #avoid duplication 2741 all_name = list(set(all_name)) 2742 2743 if mode == 'all': 2744 cur_path = pjoin(*[a for a in args \ 2745 if a.endswith(os.path.sep)]) 2746 all_path = self.path_completion(text, cur_path) 2747 completion_categories['model name'] = all_path + all_name 2748 elif mode == 'model': 2749 completion_categories['model name'] = all_name 2750 elif os.path.sep in text: 2751 try: 2752 cur_path = pjoin(*[a for a in args \ 2753 if a.endswith(os.path.sep)]) 2754 except Exception: 2755 cur_path = os.getcwd() 2756 all_path = self.path_completion(text, cur_path) 2757 completion_categories['model name'] = all_path 2758 2759 # Options 2760 if mode == 'all' and len(args)>1: 2761 mode = self.find_import_type(args[2]) 2762 2763 if len(args) >= 3 and mode.startswith('model') and not '-modelname' in line: 2764 if not text and not completion_categories: 2765 return ['--modelname'] 2766 elif not (os.path.sep in args[-1] and line[-1] != ' '): 2767 completion_categories['options'] = self.list_completion(text, ['--modelname','-modelname','--noprefix']) 2768 if len(args) >= 3 and mode.startswith('banner') and not '--no_launch' in line: 2769 completion_categories['options'] = self.list_completion(text, ['--no_launch']) 2770 2771 return self.deal_multiple_categories(completion_categories,formatting)
2772 2773 _online_model = {'2HDM':[], 2774 'loop_qcd_qed_sm':['full','no_widths','with_b_mass ', 'with_b_mass_no_widths'], 2775 'loop_qcd_qed_sm_Gmu':['ckm', 'full', 'no_widths'], 2776 '4Gen':[], 2777 'DY_SM':[], 2778 'EWdim6':['full'], 2779 'heft':['ckm','full', 'no_b_mass','no_masses','no_tau_mass','zeromass_ckm'], 2780 'nmssm':['full'], 2781 'SMScalars':['full'], 2782 'RS':[''], 2783 'sextet_diquarks':[''], 2784 'TopEffTh':[''], 2785 'triplet_diquarks':[''], 2786 'uutt_sch_4fermion':[''], 2787 'uutt_tch_scalar':[''] 2788 } 2789 _online_model2 = [] # fill by model on the db if user do "display modellist" 2790
2791 - def find_restrict_card(self, model_name, base_dir='./', no_restrict=True, 2792 online=True):
2793 """find the restriction file associate to a given model""" 2794 2795 # check if the model_name should be keeped as a possibility 2796 if no_restrict: 2797 output = [model_name] 2798 else: 2799 output = [] 2800 2801 local_model = os.path.exists(pjoin(base_dir, model_name, 'couplings.py')) 2802 # check that the model is a valid model 2803 if online and not local_model and model_name in self._online_model: 2804 output += ['%s-%s' % (model_name, tag) for tag in self._online_model[model_name]] 2805 return output 2806 2807 if not local_model: 2808 # not valid UFO model 2809 return output 2810 2811 if model_name.endswith(os.path.sep): 2812 model_name = model_name[:-1] 2813 2814 # look for _default and treat this case 2815 if os.path.exists(pjoin(base_dir, model_name, 'restrict_default.dat')): 2816 output.append('%s-full' % model_name) 2817 2818 # look for other restrict_file 2819 for name in os.listdir(pjoin(base_dir, model_name)): 2820 if name.startswith('restrict_') and not name.endswith('default.dat') \ 2821 and name.endswith('.dat'): 2822 tag = name[9:-4] #remove restrict and .dat 2823 while model_name.endswith(os.path.sep): 2824 model_name = model_name[:-1] 2825 output.append('%s-%s' % (model_name, tag)) 2826 2827 # return 2828 return output
2829
2830 - def complete_install(self, text, line, begidx, endidx):
2831 "Complete the import command" 2832 2833 args = self.split_arg(line[0:begidx]) 2834 # Format 2835 if len(args) == 1: 2836 return self.list_completion(text, self._install_opts + self._advanced_install_opts) 2837 elif len(args) and args[0] == 'update': 2838 return self.list_completion(text, ['-f','--timeout=']) 2839 elif len(args)>=2 and args[1] in self._advanced_install_opts: 2840 options = ['--keep_source','--logging='] 2841 if args[1]=='pythia8': 2842 options.append('--pythia8_tarball=') 2843 elif args[1]=='mg5amc_py8_interface': 2844 options.append('--mg5amc_py8_interface_tarball=') 2845 elif args[1] in ['MadAnalysis5','MadAnalysis']: 2846 #options.append('--no_MA5_further_install') 2847 options.append('--no_root_in_MA5') 2848 options.append('--update') 2849 options.append('--madanalysis5_tarball=') 2850 for prefix in ['--with', '--veto']: 2851 for prog in ['fastjet', 'delphes', 'delphesMA5tune']: 2852 options.append('%s_%s' % (prefix, prog)) 2853 2854 for opt in options[:]: 2855 if any(a.startswith(opt) for a in args): 2856 options.remove(opt) 2857 return self.list_completion(text, options) 2858 else: 2859 return self.list_completion(text, [])
2860
2861 #=============================================================================== 2862 # MadGraphCmd 2863 #=============================================================================== 2864 -class MadGraphCmd(HelpToCmd, CheckValidForCmd, CompleteForCmd, CmdExtended):
2865 """The command line processor of MadGraph""" 2866 2867 writing_dir = '.' 2868 2869 # Options and formats available 2870 _display_opts = ['particles', 'interactions', 'processes', 'diagrams', 2871 'diagrams_text', 'multiparticles', 'couplings', 'lorentz', 2872 'checks', 'parameters', 'options', 'coupling_order','variable', 2873 'modellist'] 2874 _add_opts = ['process', 'model'] 2875 _save_opts = ['model', 'processes', 'options'] 2876 _tutorial_opts = ['aMCatNLO', 'stop', 'MadLoop', 'MadGraph5'] 2877 _switch_opts = ['mg5','aMC@NLO','ML5'] 2878 _check_opts = ['full', 'timing', 'stability', 'profile', 'permutation', 2879 'gauge','lorentz', 'brs', 'cms'] 2880 _import_formats = ['model_v4', 'model', 'proc_v4', 'command', 'banner'] 2881 _install_opts = ['Delphes', 'MadAnalysis4', 'ExRootAnalysis', 2882 'update', 'Golem95', 'QCDLoop', 'maddm', 'maddump', 2883 'looptools', 'MadSTR'] 2884 2885 # The targets below are installed using the HEPToolsInstaller.py script 2886 _advanced_install_opts = ['pythia8','zlib','boost','lhapdf6','lhapdf5','collier', 2887 'hepmc','mg5amc_py8_interface','ninja','oneloop','MadAnalysis5'] 2888 2889 _install_opts.extend(_advanced_install_opts) 2890 2891 _v4_export_formats = ['madevent', 'standalone', 'standalone_msP','standalone_msF', 2892 'matrix', 'standalone_rw', 'madweight'] 2893 _export_formats = _v4_export_formats + ['standalone_cpp', 'pythia8', 'aloha', 2894 'matchbox_cpp', 'matchbox'] 2895 _set_options = ['group_subprocesses', 2896 'ignore_six_quark_processes', 2897 'stdout_level', 2898 'fortran_compiler', 2899 'cpp_compiler', 2900 'loop_optimized_output', 2901 'complex_mass_scheme', 2902 'gauge', 2903 'EWscheme', 2904 'max_npoint_for_channel', 2905 'max_t_for_channel', 2906 'zerowidth_tchannel', 2907 'default_unset_couplings', 2908 ] 2909 _valid_nlo_modes = ['all','real','virt','sqrvirt','tree','noborn','LOonly'] 2910 _valid_sqso_types = ['==','<=','=','>'] 2911 _valid_amp_so_types = ['=','<=', '==', '>'] 2912 _OLP_supported = ['MadLoop', 'GoSam'] 2913 _output_dependencies_supported = ['external', 'internal','environment_paths'] 2914 2915 # The three options categories are treated on a different footage when a 2916 # set/save configuration occur. current value are kept in self.options 2917 options_configuration = {'pythia8_path': './HEPTools/pythia8', 2918 'hwpp_path': './herwigPP', 2919 'thepeg_path': './thepeg', 2920 'hepmc_path': './hepmc', 2921 'madanalysis_path': './MadAnalysis', 2922 'madanalysis5_path':'./HEPTools/madanalysis5/madanalysis5', 2923 'pythia-pgs_path':'./pythia-pgs', 2924 'td_path':'./td', 2925 'delphes_path':'./Delphes', 2926 'exrootanalysis_path':'./ExRootAnalysis', 2927 'syscalc_path': './SysCalc', 2928 'timeout': 60, 2929 'web_browser':None, 2930 'eps_viewer':None, 2931 'text_editor':None, 2932 'fortran_compiler':None, 2933 'f2py_compiler':None, 2934 'f2py_compiler_py2':None, 2935 'f2py_compiler_py3':None, 2936 'cpp_compiler':None, 2937 'auto_update':7, 2938 'cluster_type': 'condor', 2939 'cluster_queue': None, 2940 'cluster_status_update': (600, 30), 2941 'fastjet':'fastjet-config', 2942 'golem':'auto', 2943 'samurai':None, 2944 'ninja':'./HEPTools/lib', 2945 'collier':'./HEPTools/lib', 2946 'lhapdf':'lhapdf-config', 2947 'lhapdf_py2': None, 2948 'lhapdf_py3': None, 2949 'applgrid':'applgrid-config', 2950 'amcfast':'amcfast-config', 2951 'cluster_temp_path':None, 2952 'mg5amc_py8_interface_path': './HEPTools/MG5aMC_PY8_interface', 2953 'cluster_local_path': None, 2954 'OLP': 'MadLoop', 2955 'cluster_nb_retry':1, 2956 'cluster_retry_wait':300, 2957 'cluster_size':100, 2958 'output_dependencies':'external', 2959 'crash_on_error':False, 2960 'auto_convert_model': False, 2961 } 2962 2963 options_madgraph= {'group_subprocesses': 'Auto', 2964 'ignore_six_quark_processes': False, 2965 'low_mem_multicore_nlo_generation': False, 2966 'complex_mass_scheme': False, 2967 'gauge':'unitary', 2968 'stdout_level':None, 2969 'loop_optimized_output':True, 2970 'loop_color_flows':False, 2971 'max_npoint_for_channel': 0, # 0 means automaticly adapted 2972 'default_unset_couplings': 99, # 99 means infinity 2973 'max_t_for_channel': 99, # means no restrictions 2974 'zerowidth_tchannel': True, 2975 } 2976 2977 options_madevent = {'automatic_html_opening':True, 2978 'run_mode':2, 2979 'nb_core': None, 2980 'notification_center': True 2981 } 2982 2983 2984 # Variables to store object information 2985 _curr_model = None #base_objects.Model() 2986 _curr_amps = diagram_generation.AmplitudeList() 2987 _curr_proc_defs = base_objects.ProcessDefinitionList() 2988 _curr_matrix_elements = helas_objects.HelasMultiProcess() 2989 _curr_helas_model = None 2990 _curr_exporter = None 2991 _done_export = False 2992 _curr_decaymodel = None 2993 2994 helporder = ['Main commands', 'Documented commands'] 2995 2996
2997 - def preloop(self):
2998 """Initializing before starting the main loop""" 2999 3000 self.prompt = 'MG5_aMC>' 3001 if madgraph.ReadWrite: # prevent on read-only disk 3002 self.do_install('update --mode=mg5_start') 3003 3004 # By default, load the UFO Standard Model 3005 logger.info("Loading default model: sm") 3006 self.exec_cmd('import model sm', printcmd=False, precmd=True) 3007 3008 # preloop mother 3009 CmdExtended.preloop(self)
3010 3011
3012 - def __init__(self, mgme_dir = '', *completekey, **stdin):
3013 """ add a tracker of the history """ 3014 3015 CmdExtended.__init__(self, *completekey, **stdin) 3016 3017 # Set MG/ME directory path 3018 if mgme_dir: 3019 if os.path.isdir(pjoin(mgme_dir, 'Template')): 3020 self._mgme_dir = mgme_dir 3021 logger.info('Setting MG/ME directory to %s' % mgme_dir) 3022 else: 3023 logger.warning('Warning: Directory %s not valid MG/ME directory' % \ 3024 mgme_dir) 3025 self._mgme_dir = MG4DIR 3026 3027 # check that make_opts exists 3028 make_opts = pjoin(MG5DIR, 'Template','LO','Source','make_opts') 3029 make_opts_source = pjoin(MG5DIR, 'Template','LO','Source','.make_opts') 3030 if not os.path.exists(make_opts): 3031 shutil.copy(make_opts_source, make_opts) 3032 elif os.path.getmtime(make_opts) < os.path.getmtime(make_opts_source): 3033 shutil.copy(make_opts_source, make_opts) 3034 3035 # Variables to store state information 3036 self._multiparticles = {} 3037 self.options = {} 3038 self._generate_info = "" # store the first generated process 3039 self._model_v4_path = None 3040 self._export_dir = None 3041 self._export_format = 'madevent' 3042 self._mgme_dir = MG4DIR 3043 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools')) 3044 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src')) 3045 self._comparisons = None 3046 self._cms_checks = [] 3047 self._nlo_modes_for_completion = ['all','virt','real','LOonly'] 3048 3049 # Load the configuration file,i.e.mg5_configuration.txt 3050 self.set_configuration()
3051
3052 - def setup(self):
3053 """ Actions to carry when switching to this interface """ 3054 3055 # Refresh all the interface stored value as things like generated 3056 # processes and amplitudes are not to be reused in between different 3057 # interfaces 3058 # Clear history, amplitudes and matrix elements when a model is imported 3059 # Remove previous imports, generations and outputs from history 3060 self.history.clean(remove_bef_last='import',keep_switch=True) 3061 # Reset amplitudes and matrix elements 3062 self._done_export=False 3063 self._curr_amps = diagram_generation.AmplitudeList() 3064 self._curr_proc_defs = base_objects.ProcessDefinitionList() 3065 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 3066 3067 self._v4_export_formats = ['madevent', 'standalone','standalone_msP','standalone_msF', 3068 'matrix', 'standalone_rw'] 3069 self._export_formats = self._v4_export_formats + ['standalone_cpp', 'pythia8'] 3070 self._nlo_modes_for_completion = ['all','virt','real']
3071
3072 - def do_quit(self, line):
3073 """Not in help: Do quit""" 3074 3075 if self._done_export and \ 3076 os.path.exists(pjoin(self._done_export[0],'RunWeb')): 3077 os.remove(pjoin(self._done_export[0],'RunWeb')) 3078 3079 value = super(MadGraphCmd, self).do_quit(line) 3080 if madgraph.ReadWrite: #prevent to run on Read Only disk 3081 self.do_install('update --mode=mg5_end') 3082 misc.EasterEgg('quit') 3083 3084 3085 return value
3086 3087 # Add a process to the existing multiprocess definition 3088 # Generate a new amplitude
3089 - def do_add(self, line):
3090 """Generate an amplitude for a given process and add to 3091 existing amplitudes 3092 or merge two model 3093 """ 3094 3095 args = self.split_arg(line) 3096 3097 3098 warning_duplicate = True 3099 if '--no_warning=duplicate' in args: 3100 warning_duplicate = False 3101 args.remove('--no_warning=duplicate') 3102 3103 diagram_filter = False 3104 if '--diagram_filter' in args: 3105 diagram_filter = True 3106 args.remove('--diagram_filter') 3107 3108 standalone_only = False 3109 if '--standalone' in args: 3110 standalone_only = True 3111 args.remove('--standalone') 3112 3113 # Check the validity of the arguments 3114 self.check_add(args) 3115 3116 if args[0] == 'model': 3117 return self.add_model(args[1:]) 3118 3119 # special option for 1->N to avoid generation of kinematically forbidden 3120 #decay. 3121 if args[-1].startswith('--optimize'): 3122 optimize = True 3123 args.pop() 3124 else: 3125 optimize = False 3126 3127 if args[0] == 'process': 3128 # Rejoin line 3129 line = ' '.join(args[1:]) 3130 3131 # store the first process (for the perl script) 3132 if not self._generate_info: 3133 self._generate_info = line 3134 3135 # Reset Helas matrix elements 3136 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 3137 3138 # Extract process from process definition 3139 if ',' in line: 3140 if ']' in line or '[' in line: 3141 error_msg=\ 3142 """The '[' and ']' syntax cannot be used in cunjunction with decay chains. 3143 This implies that with decay chains: 3144 > Squared coupling order limitations are not available. 3145 > Loop corrections cannot be considered.""" 3146 raise MadGraph5Error(error_msg) 3147 else: 3148 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 3149 myprocdef, line = self.extract_decay_chain_process(line, proc_number=nb_proc) 3150 # Redundant with above, but not completely as in the future 3151 # one might think of allowing the core process to be 3152 # corrected by loops. 3153 if myprocdef.are_decays_perturbed(): 3154 raise MadGraph5Error("Decay processes cannot be perturbed.") 3155 # The two limitations below have some redundancy, but once 3156 # again, they might be relieved (one at a time or together) 3157 # int he future. 3158 if myprocdef.decays_have_squared_orders() or \ 3159 myprocdef['squared_orders']!={}: 3160 raise MadGraph5Error("Decay processes cannot specify "+\ 3161 "squared orders constraints.") 3162 if myprocdef.are_negative_orders_present(): 3163 raise MadGraph5Error("Decay processes cannot include negative"+\ 3164 " coupling orders constraints.") 3165 else: 3166 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 3167 myprocdef = self.extract_process(line, proc_number=nb_proc) 3168 3169 3170 3171 # Check that we have something 3172 if not myprocdef: 3173 raise self.InvalidCmd("Empty or wrong format process, please try again.") 3174 # Check that we have the same number of initial states as 3175 # existing processes 3176 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 3177 myprocdef.get_ninitial() and not standalone_only: 3178 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 3179 3180 #Check that we do not have situation like z{T} z 3181 if not myprocdef.check_polarization(): 3182 logger.critical("Not Supported syntax:\n"+ \ 3183 " Syntax like p p > Z{T} Z are ambiguious" +\ 3184 " Behavior is not guarantee to be stable within future version of the code." + \ 3185 " Furthemore, you can have issue with symmetry factor (we do not guarantee [differential] cross-section."+\ 3186 " We suggest you to abort this computation") 3187 ans = self.ask('Do you want to continue', 'no',['yes','no']) 3188 if ans == 'no': 3189 raise self.InvalidCmd("Not supported syntax of type p p > Z{T} Z") 3190 3191 3192 3193 3194 self._curr_proc_defs.append(myprocdef) 3195 3196 try: 3197 # Negative coupling order contraints can be given on at most one 3198 # coupling order (and either in squared orders or orders, not both) 3199 if len([1 for val in list(myprocdef.get('orders').values())+\ 3200 list(myprocdef.get('squared_orders').values()) if val<0])>1: 3201 raise MadGraph5Error("Negative coupling order constraints"+\ 3202 " can only be given on one type of coupling and either on"+\ 3203 " squared orders or amplitude orders, not both.") 3204 3205 if myprocdef.get_ninitial() ==1 and myprocdef.get('squared_orders'): 3206 logger.warning('''Computation of interference term with decay is not 100% validated. 3207 Please check carefully your result. 3208 One suggestion is also to compare the generation of your process with and without 3209 set group_subprocesses True 3210 (to write Before the generate command) 3211 ''') 3212 3213 cpu_time1 = time.time() 3214 3215 # Generate processes 3216 if self.options['group_subprocesses'] == 'Auto': 3217 collect_mirror_procs = True 3218 else: 3219 collect_mirror_procs = self.options['group_subprocesses'] 3220 ignore_six_quark_processes = \ 3221 self.options['ignore_six_quark_processes'] if \ 3222 "ignore_six_quark_processes" in self.options \ 3223 else [] 3224 3225 myproc = diagram_generation.MultiProcess(myprocdef, 3226 collect_mirror_procs = collect_mirror_procs, 3227 ignore_six_quark_processes = ignore_six_quark_processes, 3228 optimize=optimize, diagram_filter=diagram_filter) 3229 3230 3231 for amp in myproc.get('amplitudes'): 3232 if amp not in self._curr_amps: 3233 self._curr_amps.append(amp) 3234 elif warning_duplicate: 3235 raise self.InvalidCmd( "Duplicate process %s found. Please check your processes." % \ 3236 amp.nice_string_processes()) 3237 except Exception: 3238 self._curr_proc_defs.pop(-1) 3239 raise 3240 3241 # Reset _done_export, since we have new process 3242 self._done_export = False 3243 3244 cpu_time2 = time.time() 3245 3246 nprocs = len(myproc.get('amplitudes')) 3247 ndiags = sum([amp.get_number_of_diagrams() for \ 3248 amp in myproc.get('amplitudes')]) 3249 3250 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 3251 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 3252 ndiags = sum([amp.get_number_of_diagrams() for \ 3253 amp in self._curr_amps]) 3254 logger.info("Total: %i processes with %i diagrams" % \ 3255 (len(self._curr_amps), ndiags))
3256
3257 - def add_model(self, args):
3258 """merge two model""" 3259 3260 model_path = args[0] 3261 recreate = ('--recreate' in args) 3262 if recreate: 3263 args.remove('--recreate') 3264 keep_decay = ('--keep_decay' in args) 3265 if keep_decay: 3266 args.remove('--keep_decay') 3267 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')] 3268 if output_dir: 3269 output_dir = output_dir[0] 3270 recreate = True 3271 restrict_name = '' 3272 args.remove('--output=%s' % output_dir) 3273 else: 3274 name = os.path.basename(self._curr_model.get('modelpath')) 3275 restrict_name = self._curr_model.get('restrict_name') 3276 output_dir = pjoin(MG5DIR, 'models', '%s__%s' % (name, 3277 os.path.basename(model_path))) 3278 3279 if os.path.exists(output_dir): 3280 if recreate: 3281 shutil.rmtree(output_dir) 3282 else: 3283 logger.info('Model already created! Loading it from %s' % output_dir) 3284 oldmodel = self._curr_model.get('modelpath') 3285 new_model_name = output_dir 3286 if restrict_name: 3287 new_model_name = '%s-%s' % (output_dir, restrict_name) 3288 try: 3289 self.exec_cmd('import model %s' % new_model_name, errorhandling=False, 3290 printcmd=False, precmd=True, postcmd=True) 3291 except Exception as error: 3292 logger.debug('fail to load model %s with error:\n %s' % (output_dir, error)) 3293 logger.warning('Fail to load the model. Restore previous model') 3294 self.exec_cmd('import model %s' % oldmodel, errorhandling=False, 3295 printcmd=False, precmd=True, postcmd=True) 3296 raise Exception('Invalid Model! Please retry with the option \'--recreate\'.') 3297 else: 3298 return 3299 3300 #Need to do the work!!! 3301 import models.usermod as usermod 3302 base_model = copy.deepcopy(usermod.UFOModel(self._curr_model.get('modelpath'))) 3303 3304 identify = dict(tuple(a.split('=')) for a in args if '=' in a) 3305 base_model.add_model(path=model_path, identify_particles=identify) 3306 base_model.write(output_dir) 3307 3308 if keep_decay and os.path.exists(pjoin(self._curr_model.get('modelpath'), 'decays.py')): 3309 base_model.mod_file(pjoin(pjoin(self._curr_model.get('modelpath'), 'decays.py')), 3310 pjoin(pjoin(output_dir, 'decays.py'))) 3311 3312 new_model_name = output_dir 3313 if restrict_name: 3314 new_model_name = '%s-%s' % (output_dir, restrict_name) 3315 3316 if 'modelname' in self.history.get('full_model_line'): 3317 opts = '--modelname' 3318 else: 3319 opts='' 3320 self.exec_cmd('import model %s %s' % (new_model_name, opts), errorhandling=False, 3321 printcmd=False, precmd=True, postcmd=True)
3322 3323
3324 - def do_convert(self, line):
3325 """convert model FULLPATH 3326 modify (in place) the UFO model to make it compatible with both python2 and python3 3327 """ 3328 3329 args = self.split_arg(line) 3330 if hasattr(self, 'do_convert_%s' % args[0]): 3331 getattr(self, 'do_convert_%s' % args[0])(args[1:])
3332
3333 - def do_convert_model(self, args):
3334 "Not in help: shortcut for convert model" 3335 3336 if not os.path.isdir(args[0]): 3337 raise Exception( 'model to convert need to provide a full path') 3338 model_dir = args[0] 3339 3340 3341 if not ('-f' not in args or self.options['auto_convert_model']): 3342 answer = self.ask('model conversion to support both py2 and py3 are done in place.\n They are NO guarantee of success.\n It can make the model to stop working under PY2 as well.\n Do you want to proceed?', 3343 'y', ['y','n']) 3344 if answer != 'y': 3345 return 3346 3347 #Object_library 3348 text = open(pjoin(model_dir, 'object_library.py')).read() 3349 #(.iteritems() -> .items()) 3350 text = text.replace('.iteritems()', '.items()') 3351 # raise UFOError, "" -> raise UFOError() 3352 text = re.sub('raise (\w+)\s*,\s*["\']([^"]+)["\']', 3353 'raise \g<1>("\g<2>")', text) 3354 text = open(pjoin(model_dir, 'object_library.py'),'w').write(text) 3355 3356 # write_param_card.dat -> copy the one of the sm model 3357 files.cp(pjoin(MG5DIR, 'models','sm','write_param_card.py'), 3358 pjoin(model_dir, 'write_param_card.py')) 3359 3360 # __init__.py check that function_library and object_library are imported 3361 text = open(pjoin(model_dir, '__init__.py')).read() 3362 mod = False 3363 to_check = ['object_library', 'function_library'] 3364 for lib in to_check: 3365 if 'import %s' % lib in text: 3366 continue 3367 mod = True 3368 text = "import %s \n" % lib + text 3369 if mod: 3370 open(pjoin(model_dir, '__init__.py'),'w').write(text)
3371 3372 3373 3374 3375 3376 # Define a multiparticle label
3377 - def do_define(self, line, log=True):
3378 """Define a multiparticle""" 3379 3380 self.avoid_history_duplicate('define %s' % line, ['define']) 3381 if not self._curr_model: 3382 self.do_import('model sm') 3383 self.history.append('define %s' % line) 3384 if not self._curr_model['case_sensitive']: 3385 # Particle names lowercase 3386 line = line.lower() 3387 # Make sure there are spaces around =, | and / 3388 line = line.replace("=", " = ") 3389 line = line.replace("|", " | ") 3390 line = line.replace("/", " / ") 3391 args = self.split_arg(line) 3392 # check the validity of the arguments 3393 self.check_define(args) 3394 3395 label = args[0] 3396 remove_ids = [] 3397 try: 3398 remove_index = args.index("/") 3399 except ValueError: 3400 pass 3401 else: 3402 remove_ids = args[remove_index + 1:] 3403 args = args[:remove_index] 3404 3405 pdg_list = self.extract_particle_ids(args[1:]) 3406 remove_list = self.extract_particle_ids(remove_ids) 3407 pdg_list = [p for p in pdg_list if p not in remove_list] 3408 3409 self.optimize_order(pdg_list) 3410 self._multiparticles[label] = pdg_list 3411 if log: 3412 logger.info("Defined multiparticle %s" % \ 3413 self.multiparticle_string(label))
3414 3415 # Display
3416 - def do_display(self, line, output=sys.stdout):
3417 """Display current internal status""" 3418 3419 args = self.split_arg(line) 3420 #check the validity of the arguments 3421 self.check_display(args) 3422 3423 if args[0] == 'diagrams': 3424 self.draw(' '.join(args[1:])) 3425 3426 if args[0] == 'particles' and len(args) == 1: 3427 propagating_particle = [] 3428 nb_unpropagating = 0 3429 for particle in self._curr_model['particles']: 3430 if particle.get('propagating'): 3431 propagating_particle.append(particle) 3432 else: 3433 nb_unpropagating += 1 3434 3435 print("Current model contains %i particles:" % \ 3436 len(propagating_particle)) 3437 part_antipart = [part for part in propagating_particle \ 3438 if not part['self_antipart']] 3439 part_self = [part for part in propagating_particle \ 3440 if part['self_antipart']] 3441 for part in part_antipart: 3442 print(part['name'] + '/' + part['antiname'], end=' ') 3443 print('') 3444 for part in part_self: 3445 print(part['name'], end=' ') 3446 print('') 3447 if nb_unpropagating: 3448 print('In addition of %s un-physical particle mediating new interactions.' \ 3449 % nb_unpropagating) 3450 3451 elif args[0] == 'particles': 3452 for arg in args[1:]: 3453 if arg.isdigit() or (arg[0] == '-' and arg[1:].isdigit()): 3454 particle = self._curr_model.get_particle(abs(int(arg))) 3455 else: 3456 particle = self._curr_model['particles'].find_name(arg) 3457 if not particle: 3458 raise self.InvalidCmd('no particle %s in current model' % arg) 3459 3460 print("Particle %s has the following properties:" % particle.get_name()) 3461 print(str(particle)) 3462 3463 elif args[0] == 'interactions' and len(args) == 1: 3464 text = "Current model contains %i interactions\n" % \ 3465 len(self._curr_model['interactions']) 3466 for i, inter in enumerate(self._curr_model['interactions']): 3467 text += str(i+1) + ':' 3468 for part in inter['particles']: 3469 if part['is_part']: 3470 text += part['name'] 3471 else: 3472 text += part['antiname'] 3473 text += " " 3474 text += " ".join(order + '=' + str(inter['orders'][order]) \ 3475 for order in inter['orders']) 3476 text += '\n' 3477 pydoc.pager(text) 3478 3479 elif args[0] == 'interactions' and len(args)==2 and args[1].isdigit(): 3480 for arg in args[1:]: 3481 if int(arg) > len(self._curr_model['interactions']): 3482 raise self.InvalidCmd('no interaction %s in current model' % arg) 3483 if int(arg) == 0: 3484 print('Special interactions which identify two particles') 3485 else: 3486 print("Interactions %s has the following property:" % arg) 3487 print(self._curr_model['interactions'][int(arg)-1]) 3488 3489 elif args[0] == 'interactions': 3490 request_part = args[1:] 3491 text = '' 3492 for i, inter in enumerate(self._curr_model['interactions']): 3493 present_part = [part['is_part'] and part['name'] or part['antiname'] 3494 for part in inter['particles'] 3495 if (part['is_part'] and part['name'] in request_part) or 3496 (not part['is_part'] and part['antiname'] in request_part)] 3497 if len(present_part) < len(request_part): 3498 continue 3499 # check that all particles are selected at least once 3500 if set(present_part) != set(request_part): 3501 continue 3502 # check if a particle is asked more than once 3503 if len(request_part) > len(set(request_part)): 3504 for p in request_part: 3505 if request_part.count(p) > present_part.count(p): 3506 continue 3507 3508 name = str(i+1) + ' : ' 3509 for part in inter['particles']: 3510 if part['is_part']: 3511 name += part['name'] 3512 else: 3513 name += part['antiname'] 3514 name += " " 3515 text += "\nInteractions %s has the following property:\n" % name 3516 text += str(self._curr_model['interactions'][i]) 3517 3518 text += '\n' 3519 print(name) 3520 if text =='': 3521 text += 'No matching for any interactions' 3522 pydoc.pager(text) 3523 3524 3525 elif args[0] == 'parameters' and len(args) == 1: 3526 text = "Current model contains %i parameters\n" % \ 3527 sum([len(part) for part in 3528 self._curr_model['parameters'].values()]) 3529 keys = list(self._curr_model['parameters'].keys()) 3530 def key_sort(x): 3531 if ('external',) == x: 3532 return -1 3533 else: 3534 return len(x)
3535 keys.sort(key=key_sort) 3536 for key in keys: 3537 item = self._curr_model['parameters'][key] 3538 text += '\nparameter type: %s\n' % str(key) 3539 for value in item: 3540 if hasattr(value, 'expr'): 3541 if value.value is not None: 3542 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3543 else: 3544 text+= ' %s = %s\n' % (value.name, value.expr) 3545 else: 3546 if value.value is not None: 3547 text+= ' %s = %s\n' % (value.name, value.value) 3548 else: 3549 text+= ' %s \n' % (value.name) 3550 pydoc.pager(text) 3551 3552 elif args[0] == 'processes': 3553 for amp in self._curr_amps: 3554 print(amp.nice_string_processes()) 3555 3556 elif args[0] == 'diagrams_text': 3557 text = "\n".join([amp.nice_string() for amp in self._curr_amps]) 3558 pydoc.pager(text) 3559 3560 elif args[0] == 'multiparticles': 3561 print('Multiparticle labels:') 3562 for key in self._multiparticles: 3563 print(self.multiparticle_string(key)) 3564 3565 elif args[0] == 'coupling_order': 3566 hierarchy = list(self._curr_model['order_hierarchy'].items()) 3567 #self._curr_model.get_order_hierarchy().items() 3568 def order(first, second): 3569 if first[1] < second[1]: 3570 return -1 3571 else: 3572 return 1
3573 hierarchy.sort(order) 3574 for order in hierarchy: 3575 print(' %s : weight = %s' % order) 3576 3577 elif args[0] == 'couplings' and len(args) == 1: 3578 if self._model_v4_path: 3579 print('No couplings information available in V4 model') 3580 return 3581 text = '' 3582 text = "Current model contains %i couplings\n" % \ 3583 sum([len(part) for part in 3584 self._curr_model['couplings'].values()]) 3585 keys = list(self._curr_model['couplings'].keys()) 3586 def key_sort(x, y): 3587 if ('external',) == x: 3588 return -1 3589 elif ('external',) == y: 3590 return +1 3591 elif len(x) < len(y): 3592 return -1 3593 else: 3594 return 1 3595 keys.sort(key_sort) 3596 for key in keys: 3597 item = self._curr_model['couplings'][key] 3598 text += '\ncouplings type: %s\n' % str(key) 3599 for value in item: 3600 if value.value is not None: 3601 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3602 else: 3603 text+= ' %s = %s\n' % (value.name, value.expr) 3604 3605 pydoc.pager(text) 3606 3607 elif args[0] == 'couplings': 3608 if self._model_v4_path: 3609 print('No couplings information available in V4 model') 3610 return 3611 3612 try: 3613 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3614 print('Note that this is the UFO informations.') 3615 print(' "display couplings" present the actual definition') 3616 print('prints the current states of mode') 3617 print(eval('ufomodel.couplings.%s.nice_string()'%args[1])) 3618 except Exception: 3619 raise self.InvalidCmd('no couplings %s in current model' % args[1]) 3620 3621 elif args[0] == 'lorentz': 3622 print('in lorentz') 3623 if self._model_v4_path: 3624 print('No lorentz information available in V4 model') 3625 return 3626 elif len(args) == 1: 3627 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3628 print(dir(ufomodel.lorentz)) 3629 return 3630 try: 3631 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3632 print(getattr(ufomodel.lorentz, args[1]).nice_string()) 3633 except Exception as error: 3634 raise 3635 logger.info(str(error)) 3636 raise self.InvalidCmd('no lorentz %s in current model' % args[1]) 3637 3638 elif args[0] == 'checks': 3639 outstr = '' 3640 if self._comparisons: 3641 comparisons = self._comparisons[0] 3642 if len(args) > 1 and args[1] == 'failed': 3643 comparisons = [c for c in comparisons if not c['passed']] 3644 outstr += "Process check results:" 3645 for comp in comparisons: 3646 outstr += "\n%s:" % comp['process'].nice_string() 3647 outstr += "\n Phase space point: (px py pz E)" 3648 for i, p in enumerate(comp['momenta']): 3649 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p) 3650 outstr += "\n Permutation values:" 3651 outstr += "\n " + str(comp['values']) 3652 if comp['passed']: 3653 outstr += "\n Process passed (rel. difference %.9e)" % \ 3654 comp['difference'] 3655 else: 3656 outstr += "\n Process failed (rel. difference %.9e)" % \ 3657 comp['difference'] 3658 3659 used_aloha = sorted(self._comparisons[1]) 3660 if used_aloha: 3661 outstr += "\nChecked ALOHA routines:" 3662 for aloha in used_aloha: 3663 aloha_str = aloha[0] 3664 if aloha[1]: 3665 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]]) 3666 aloha_str += "_%d" % aloha[2] 3667 outstr += "\n" + aloha_str 3668 3669 outstr += '\n' 3670 for cms_check in self._cms_checks: 3671 outstr += '*'*102+'\n' 3672 outstr += 'Complex Mass Scheme check:\n' 3673 outstr += ' -> check %s\n'%cms_check['line'] 3674 outstr += '*'*102+'\n' 3675 tmp_options = copy.copy(cms_check['options']) 3676 tmp_options['show_plot']=False 3677 outstr += process_checks.output_complex_mass_scheme( 3678 cms_check['cms_result'], cms_check['output_path'], 3679 tmp_options, self._curr_model) + '\n' 3680 outstr += '*'*102+'\n\n' 3681 pydoc.pager(outstr) 3682 3683 elif args[0] == 'options': 3684 if len(args) == 1: 3685 to_print = lambda name: True 3686 else: 3687 to_print = lambda name: any(poss in name for poss in args[1:]) 3688 3689 outstr = " MadGraph5_aMC@NLO Options \n" 3690 outstr += " ---------------- \n" 3691 keys = list(self.options_madgraph.keys()) 3692 keys.sort() 3693 for key in keys: 3694 if not to_print(key): 3695 continue 3696 default = self.options_madgraph[key] 3697 value = self.options[key] 3698 if value == default: 3699 outstr += " %25s \t:\t%s\n" % (key,value) 3700 else: 3701 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3702 outstr += "\n" 3703 outstr += " MadEvent Options \n" 3704 outstr += " ---------------- \n" 3705 keys = list(self.options_madevent.keys()) 3706 keys.sort() 3707 for key in keys: 3708 if not to_print(key): 3709 continue 3710 default = self.options_madevent[key] 3711 value = self.options[key] 3712 if value == default: 3713 outstr += " %25s \t:\t%s\n" % (key,value) 3714 else: 3715 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3716 outstr += "\n" 3717 outstr += " Configuration Options \n" 3718 outstr += " --------------------- \n" 3719 keys = list(self.options_configuration.keys()) 3720 keys.sort() 3721 for key in keys: 3722 if not to_print(key): 3723 continue 3724 default = self.options_configuration[key] 3725 value = self.options[key] 3726 if value == default: 3727 outstr += " %25s \t:\t%s\n" % (key,value) 3728 else: 3729 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3730 3731 output.write(outstr) 3732 elif args[0] in ["variable"]: 3733 super(MadGraphCmd, self).do_display(line, output) 3734 3735 elif args[0] in ["modellist", "model_list"]: 3736 outstr = [] 3737 template = """%-30s | %-60s | %-25s """ 3738 outstr.append(template % ('name', 'restriction', 'comment')) 3739 outstr.append('*'*150) 3740 already_done = [] 3741 #local model #use 3742 3743 if 'PYTHONPATH' in os.environ: 3744 pythonpath = os.environ['PYTHONPATH'].split(':') 3745 else: 3746 pythonpath = [] 3747 3748 for base in [pjoin(MG5DIR,'models')] + pythonpath: 3749 if not os.path.exists(base): 3750 continue 3751 file_cond = lambda p : os.path.exists(pjoin(base,p,'particles.py')) 3752 mod_name = lambda name: name 3753 3754 model_list = [mod_name(name) for name in \ 3755 self.path_completion('', 3756 base, 3757 only_dirs = True) \ 3758 if file_cond(name)] 3759 3760 for model_name in model_list: 3761 if model_name in already_done: 3762 continue 3763 all_name = self.find_restrict_card(model_name, 3764 base_dir=base, 3765 online=False) 3766 already_done.append(model_name) 3767 restrict = [name[len(model_name):] for name in all_name 3768 if len(name)>len(model_name)] 3769 3770 comment = 'from models directory' 3771 if base != pjoin(MG5DIR,'models'): 3772 comment = 'from PYTHONPATH: %s' % base 3773 lrestrict = ', '.join(restrict) 3774 if len(lrestrict) > 50: 3775 for i in range(-1,-len(restrict), -1): 3776 lrestrict = ', '.join(restrict[:i]) 3777 if len(lrestrict)<50: 3778 break 3779 outstr.append(template % (model_name, lrestrict, comment)) 3780 outstr.append(template % ('', ', '.join(restrict[i:]), '')) 3781 else: 3782 outstr.append(template % (model_name, ', '.join(restrict), comment)) 3783 outstr.append('*'*150) 3784 3785 # Still have to add the one with internal information 3786 for model_name in self._online_model: 3787 if model_name in already_done: 3788 continue 3789 restrict = [tag for tag in self._online_model[model_name]] 3790 comment = 'automatic download from MG5aMC server' 3791 outstr.append(template % (model_name, ','.join(restrict), comment)) 3792 already_done.append(model_name) 3793 3794 outstr.append('*'*150) 3795 # other downloadable model 3796 data = import_ufo.get_model_db() 3797 self._online_model2 = [] 3798 for line in data: 3799 model_name, path = line.decode().split() 3800 if model_name in already_done: 3801 continue 3802 if model_name.endswith('_v4'): 3803 continue 3804 3805 if 'feynrules' in path: 3806 comment = 'automatic download from FeynRules website' 3807 elif 'madgraph.phys' in path: 3808 comment = 'automatic download from MG5aMC server' 3809 else: 3810 comment = 'automatic download.' 3811 restrict = 'unknown' 3812 outstr.append(template % (model_name, restrict, comment)) 3813 self._online_model2.append(model_name) 3814 pydoc.pager('\n'.join(outstr)) 3815 3816
3817 - def multiparticle_string(self, key):
3818 """Returns a nicely formatted string for the multiparticle""" 3819 3820 if self._multiparticles[key] and \ 3821 isinstance(self._multiparticles[key][0], list): 3822 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\ 3823 get('particle_dict')[part_id].get_name() \ 3824 for part_id in id_list]) \ 3825 for id_list in self._multiparticles[key]])) 3826 else: 3827 return "%s = %s" % (key, " ".join([self._curr_model.\ 3828 get('particle_dict')[part_id].get_name() \ 3829 for part_id in self._multiparticles[key]]))
3830
3831 - def do_tutorial(self, line):
3832 """Activate/deactivate the tutorial mode.""" 3833 3834 args = self.split_arg(line) 3835 self.check_tutorial(args) 3836 tutorials = {'MadGraph5': logger_tuto, 3837 'aMCatNLO': logger_tuto_nlo, 3838 'MadLoop': logger_tuto_madloop} 3839 try: 3840 tutorials[args[0]].setLevel(logging.INFO) 3841 for mode in [m for m in tutorials.keys() if m != args[0]]: 3842 tutorials[mode].setLevel(logging.ERROR) 3843 except KeyError: 3844 logger_tuto.info("\n\tThanks for using the tutorial!") 3845 logger_tuto.setLevel(logging.ERROR) 3846 logger_tuto_nlo.info("\n\tThanks for using the aMC@NLO tutorial!") 3847 logger_tuto_nlo.setLevel(logging.ERROR) 3848 logger_tuto_madloop.info("\n\tThanks for using MadLoop tutorial!") 3849 logger_tuto_madloop.setLevel(logging.ERROR) 3850 3851 if not self._mgme_dir: 3852 logger_tuto.info(\ 3853 "\n\tWarning: To use all features in this tutorial, " + \ 3854 "please run from a" + \ 3855 "\n\t valid MG_ME directory.")
3856 3857 3858
3859 - def draw(self, line,selection='all',Dtype=''):
3860 """ draw the Feynman diagram for the given process. 3861 Dtype refers to born, real or loop""" 3862 3863 args = self.split_arg(line) 3864 # Check the validity of the arguments 3865 self.check_draw(args) 3866 3867 # Check if we plot a decay chain 3868 if any([isinstance(a, diagram_generation.DecayChainAmplitude) for \ 3869 a in self._curr_amps]) and not self._done_export: 3870 warn = 'WARNING: You try to draw decay chain diagrams without first running output.\n' 3871 warn += '\t The decay processes will be drawn separately' 3872 logger.warning(warn) 3873 3874 (options, args) = _draw_parser.parse_args(args) 3875 if madgraph.iolibs.drawing_eps.EpsDiagramDrawer.april_fool: 3876 options.horizontal = True 3877 options.external = True 3878 options.max_size = 0.3 3879 options.add_gap = 0.5 3880 options = draw_lib.DrawOption(options) 3881 start = time.time() 3882 3883 3884 3885 3886 # Collect amplitudes 3887 amplitudes = diagram_generation.AmplitudeList() 3888 3889 for amp in self._curr_amps: 3890 amplitudes.extend(amp.get_amplitudes()) 3891 3892 for amp in amplitudes: 3893 filename = pjoin(args[0], 'diagrams_' + \ 3894 amp.get('process').shell_string() + ".eps") 3895 3896 if selection=='all' and Dtype != 'loop': 3897 diags=amp.get('diagrams') 3898 elif selection=='born': 3899 diags=amp.get('born_diagrams') 3900 elif selection=='loop' or Dtype == 'loop': 3901 diags=base_objects.DiagramList([d for d in 3902 amp.get('loop_diagrams') if d.get('type')>0]) 3903 if len(diags) > 5000: 3904 logger.warning('Displaying only the first 5000 diagrams') 3905 diags = base_objects.DiagramList(diags[:5000]) 3906 3907 plot = draw.MultiEpsDiagramDrawer(diags, 3908 filename, 3909 model=self._curr_model, 3910 amplitude=amp, 3911 legend=amp.get('process').input_string(), 3912 diagram_type=Dtype) 3913 3914 3915 logger.info("Drawing " + \ 3916 amp.get('process').nice_string()) 3917 plot.draw(opt=options) 3918 logger.info("Wrote file " + filename) 3919 self.exec_cmd('open %s' % filename) 3920 3921 stop = time.time() 3922 logger.info('time to draw %s' % (stop - start))
3923 3924 # Perform checks
3925 - def do_check(self, line):
3926 """Check a given process or set of processes""" 3927 3928 def create_lambda_values_list(lower_bound, N): 3929 """ Returns a list of values spanning the range [1.0, lower_bound] with 3930 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered 3931 by N values uniformly distributed. For example, lower_bound=1e-2 3932 and N=5 returns: 3933 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]""" 3934 3935 lCMS_values = [1] 3936 exp = 0 3937 n = 0 3938 while lCMS_values[-1]>=lower_bound: 3939 n = (n+1) 3940 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N))) 3941 if lCMS_values[-1]==lCMS_values[-2]: 3942 lCMS_values.pop() 3943 exp = (n+1)//N 3944 3945 lCMS_values = lCMS_values[:-1] 3946 if lCMS_values[-1]!=lower_bound: 3947 lCMS_values.append(lower_bound) 3948 3949 return lCMS_values
3950 3951 ###### BEGIN do_check 3952 3953 args = self.split_arg(line) 3954 # Check args validity 3955 param_card = self.check_check(args) 3956 3957 options= {'events':None} # If the momentum needs to be picked from a event file 3958 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card): 3959 logger_check.info("Will use the param_card contained in the banner and the events associated") 3960 import madgraph.various.banner as banner 3961 options['events'] = param_card 3962 mybanner = banner.Banner(param_card) 3963 param_card = mybanner.charge_card('param_card') 3964 3965 aloha_lib.KERNEL.clean() 3966 # Back up the gauge for later 3967 gauge = str(self.options['gauge']) 3968 options['reuse'] = args[1]=="-reuse" 3969 args = args[:1]+args[2:] 3970 # For the stability check the user can specify the statistics (i.e 3971 # number of trial PS points) as a second argument 3972 if args[0] in ['stability', 'profile']: 3973 options['npoints'] = int(args[1]) 3974 args = args[:1]+args[2:] 3975 MLoptions={} 3976 i=-1 3977 CMS_options = {} 3978 while args[i].startswith('--'): 3979 option = args[i].split('=') 3980 if option[0] =='--energy': 3981 options['energy']=float(option[1]) 3982 elif option[0] == '--events' and option[1]: 3983 if option[1] == 'None': 3984 options['events'] = None 3985 elif not os.path.exists(option[1]): 3986 raise Exception('path %s does not exists' % option[1]) 3987 else: 3988 options['events'] = option[1] 3989 elif option[0] == '--skip_evt': 3990 options['skip_evt']=int(option[1]) 3991 elif option[0]=='--split_orders': 3992 options['split_orders']=int(option[1]) 3993 elif option[0]=='--helicity': 3994 try: 3995 options['helicity']=int(option[1]) 3996 except ValueError: 3997 raise self.InvalidCmd("The value of the 'helicity' option"+\ 3998 " must be an integer, not %s."%option[1]) 3999 elif option[0]=='--reduction': 4000 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')] 4001 elif option[0]=='--collier_mode': 4002 MLoptions['COLLIERMode']=int(option[1]) 4003 elif option[0]=='--collier_cache': 4004 MLoptions['COLLIERGlobalCache']=int(option[1]) 4005 elif option[0]=='--collier_req_acc': 4006 if option[1]!='auto': 4007 MLoptions['COLLIERRequiredAccuracy']=float(option[1]) 4008 elif option[0]=='--collier_internal_stability_test': 4009 MLoptions['COLLIERUseInternalStabilityTest']=eval(option[1]) 4010 elif option[0]=='--CTModeRun': 4011 try: 4012 MLoptions['CTModeRun']=int(option[1]) 4013 except ValueError: 4014 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\ 4015 " must be an integer, not %s."%option[1]) 4016 elif option[0]=='--offshellness': 4017 CMS_options['offshellness'] = float(option[1]) 4018 if CMS_options['offshellness']<=-1.0: 4019 raise self.InvalidCmd('Offshellness must be number larger or'+ 4020 ' equal to -1.0, not %f'%CMS_options['offshellness']) 4021 elif option[0]=='--analyze': 4022 options['analyze'] = option[1] 4023 elif option[0]=='--show_plot': 4024 options['show_plot'] = 'true' in option[1].lower() 4025 elif option[0]=='--report': 4026 options['report'] = option[1].lower() 4027 elif option[0]=='--seed': 4028 options['seed'] = int(option[1]) 4029 elif option[0]=='--name': 4030 if '.' in option[1]: 4031 raise self.InvalidCmd("Do not specify the extension in the"+ 4032 " name of the run") 4033 CMS_options['name'] = option[1] 4034 elif option[0]=='--resonances': 4035 if option[1]=='all': 4036 CMS_options['resonances'] = 'all' 4037 else: 4038 try: 4039 resonances=eval(option[1]) 4040 except: 4041 raise self.InvalidCmd("Could not evaluate 'resonances'"+ 4042 " option '%s'"%option[1]) 4043 if isinstance(resonances,int) and resonances>0: 4044 CMS_options['resonances'] = resonances 4045 elif isinstance(resonances,list) and all(len(res)==2 and 4046 isinstance(res[0],int) and all(isinstance(i, int) for i in 4047 res[1]) for res in resonances): 4048 CMS_options['resonances'] = resonances 4049 else: 4050 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+ 4051 " or and integer or a list of tuples of the form "+ 4052 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1]) 4053 elif option[0]=='--tweak': 4054 # Lists the sets of custom and widths modifications to apply 4055 value = option[1] 4056 # Set a shortcuts for applying all relevant tweaks 4057 if value=='alltweaks': 4058 value=str(['default','seed667(seed667)','seed668(seed668)', 4059 'allwidths->0.9*allwidths(widths_x_0.9)', 4060 'allwidths->0.99*allwidths(widths_x_0.99)', 4061 'allwidths->1.01*allwidths(widths_x_1.01)', 4062 'allwidths->1.1*allwidths(widths_x_1.1)', 4063 'logp->logm(logp2logm)','logm->logp(logm2logp)']) 4064 try: 4065 tweaks = eval(value) 4066 if isinstance(tweaks, str): 4067 tweaks = [value] 4068 elif not isinstance(tweaks,list): 4069 tweaks = [value] 4070 except: 4071 tweaks = [value] 4072 if not all(isinstance(t,str) for t in tweaks): 4073 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value) 4074 CMS_options['tweak'] = [] 4075 for tweakID, tweakset in enumerate(tweaks): 4076 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset) 4077 if specs: 4078 tweakset = specs.group('tweakset') 4079 name = specs.group('name') 4080 else: 4081 if tweakset!='default': 4082 name = 'tweak_%d'%(tweakID+1) 4083 else: 4084 name = '' 4085 new_tweak_set = {'custom':[],'params':{},'name':name} 4086 for tweak in tweakset.split('&'): 4087 if tweak=='default': 4088 continue 4089 if tweak.startswith('seed'): 4090 new_tweak_set['custom'].append(tweak) 4091 continue 4092 try: 4093 param, replacement = tweak.split('->') 4094 except ValueError: 4095 raise self.InvalidCmd("Tweak specification '%s'"%\ 4096 tweak+" is incorrect. It should be of"+\ 4097 " the form a->_any_function_of_(a,lambdaCMS).") 4098 if param in ['logp','logm','log'] and \ 4099 replacement in ['logp','logm','log']: 4100 new_tweak_set['custom'].append(tweak) 4101 continue 4102 try: 4103 # for safety prefix parameters, because 'as' for alphas 4104 # is a python reserved name for example 4105 orig_param, orig_replacement = param, replacement 4106 replacement = replacement.replace(param, 4107 '__tmpprefix__%s'%param) 4108 param = '__tmpprefix__%s'%param 4109 res = float(eval(replacement.lower(), 4110 {'lambdacms':1.0,param.lower():98.85})) 4111 except: 4112 raise self.InvalidCmd("The substitution expression "+ 4113 "'%s' for the tweaked parameter"%orig_replacement+ 4114 " '%s' could not be evaluated. It must be an "%orig_param+ 4115 "expression of the parameter and 'lambdaCMS'.") 4116 new_tweak_set['params'][param.lower()] = replacement.lower() 4117 CMS_options['tweak'].append(new_tweak_set) 4118 4119 elif option[0]=='--recompute_width': 4120 if option[1].lower() not in ['never','always','first_time','auto']: 4121 raise self.InvalidCmd("The option 'recompute_width' can "+\ 4122 "only be 'never','always', 'first_time' or 'auto' (default).") 4123 CMS_options['recompute_width'] = option[1] 4124 elif option[0]=='--loop_filter': 4125 # Specify a loop, filter. See functions get_loop_filter and 4126 # user_filter in loop_diagram_generation.LoopAmplitude for 4127 # information on usage. 4128 CMS_options['loop_filter'] = '='.join(option[1:]) 4129 elif option[0]=='--diff_lambda_power': 4130 #'secret' option to chose by which lambda power one should divide 4131 # the nwa-cms difference. Useful to set to 2 when doing the Born check 4132 # to see whether the NLO check will have sensitivity to the CMS 4133 # implementation 4134 try: 4135 CMS_options['diff_lambda_power']=float(option[1]) 4136 except ValueError: 4137 raise self.InvalidCmd("the '--diff_lambda_power' option"+\ 4138 " must be an integer or float, not '%s'."%option[1]) 4139 elif option[0]=='--lambda_plot_range': 4140 try: 4141 plot_range=eval(option[1]) 4142 except Exception as e: 4143 raise self.InvalidCmd("The plot range specified %s"%option[1]+\ 4144 " is not a valid syntax. Error:\n%s"%str(e)) 4145 if not isinstance(plot_range,(list,tuple)) or \ 4146 len(plot_range)!=2 or any(not isinstance(p,(float,int)) 4147 for p in plot_range): 4148 raise self.InvalidCmd("The plot range specified %s"\ 4149 %option[1]+" is invalid") 4150 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range]) 4151 elif option[0]=='--lambdaCMS': 4152 try: 4153 lambda_values = eval(option[1]) 4154 except SyntaxError: 4155 raise self.InvalidCmd("'%s' is not a correct"%option[1]+ 4156 " python expression for lambdaCMS values.") 4157 if isinstance(lambda_values,list): 4158 if lambda_values[0]!=1.0: 4159 raise self.InvalidCmd("The first value of the lambdaCMS values"+ 4160 " specified must be 1.0, not %s"%str(lambda_values)) 4161 for l in lambda_values: 4162 if not isinstance(l,float): 4163 raise self.InvalidCmd("All lambda CMS values must be"+ 4164 " float, not '%s'"%str(l)) 4165 elif isinstance(lambda_values,(tuple,float)): 4166 # Format here is then (lower_bound, N) were lower_bound is 4167 # the minimum lambdaCMS value that must be probed and the 4168 # integer N is the number of such values that must be 4169 # uniformly distributed in each intervale [1.0e-i,1.0e-(i+1)] 4170 if isinstance(lambda_values, float): 4171 # Use default of 10 for the number of lambda values 4172 lower_bound = lambda_values 4173 N = 10 4174 else: 4175 if isinstance(lambda_values[0],float) and \ 4176 isinstance(lambda_values[1],int): 4177 lower_bound = lambda_values[0] 4178 N = lambda_values[1] 4179 else: 4180 raise self.InvalidCmd("'%s' must be a "%option[1]+ 4181 "tuple with types (float, int).") 4182 lambda_values = create_lambda_values_list(lower_bound,N) 4183 else: 4184 raise self.InvalidCmd("'%s' must be an expression"%option[1]+ 4185 " for either a float, tuple or list.") 4186 lower_bound = lambda_values[-1] 4187 # and finally add 5 points for stability test on the last values 4188 # Depending on how the stab test will behave at NLO, we can 4189 # consider automatically adding the values below 4190 # for stab in range(1,6): 4191 # lambda_values.append((1.0+(stab/100.0))*lower_bound) 4192 4193 CMS_options['lambdaCMS'] = lambda_values 4194 elif option[0]=='--cms': 4195 try: 4196 CMS_expansion_orders, CMS_expansion_parameters = \ 4197 option[1].split(',') 4198 except ValueError: 4199 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 4200 args[i]+" is incorrect.") 4201 CMS_options['expansion_orders'] = [expansion_order for 4202 expansion_order in CMS_expansion_orders.split('&')] 4203 CMS_options['expansion_parameters'] = {} 4204 for expansion_parameter in CMS_expansion_parameters.split('&'): 4205 try: 4206 param, replacement = expansion_parameter.split('->') 4207 except ValueError: 4208 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 4209 expansion_parameter+" is incorrect. It should be of"+\ 4210 " the form a->_any_function_of_(a,lambdaCMS).") 4211 try: 4212 # for safety prefix parameters, because 'as' for alphas 4213 # is a python reserved name for example 4214 orig_param, orig_replacement = param, replacement 4215 replacement = replacement.replace(param, 4216 '__tmpprefix__%s'%param) 4217 param = '__tmpprefix__%s'%param 4218 res = float(eval(replacement.lower(), 4219 {'lambdacms':1.0,param.lower():98.85})) 4220 except: 4221 raise self.InvalidCmd("The substitution expression "+ 4222 "'%s' for CMS expansion parameter"%orig_replacement+ 4223 " '%s' could not be evaluated. It must be an "%orig_param+ 4224 "expression of the parameter and 'lambdaCMS'.") 4225 # Put everything lower case as it will be done when 4226 # accessing model variables 4227 CMS_options['expansion_parameters'][param.lower()]=\ 4228 replacement.lower() 4229 else: 4230 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0]) 4231 4232 i=i-1 4233 args = args[:i+1] 4234 4235 if args[0]=='options': 4236 # Simple printout of the check command options 4237 logger_check.info("Options for the command 'check' are:") 4238 logger_check.info("{:<20} {}".format(' name','default value')) 4239 logger_check.info("-"*40) 4240 for key, value in options.items(): 4241 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 4242 return 4243 4244 if args[0].lower()=='cmsoptions': 4245 # Simple printout of the special check cms options 4246 logger_check.info("Special options for the command 'check cms' are:") 4247 logger_check.info("{:<20} {}".format(' name','default value')) 4248 logger_check.info("-"*40) 4249 for key, value in CMS_options.items(): 4250 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 4251 return 4252 4253 # Set the seed here if not in cms check and if specified 4254 if args[0]!='cms' and options['seed']!=-1: 4255 # Not necessarily optimal as there could be additional call to 4256 # random() as the code develops, but at least it will encompass 4257 # everything in this way. 4258 logger_check.info('Setting random seed to %d.'%options['seed']) 4259 random.seed(options['seed']) 4260 4261 proc_line = " ".join(args[1:]) 4262 # Don't try to extract the process if just re-analyzing a saved run 4263 if not (args[0]=='cms' and options['analyze']!='None'): 4264 myprocdef = self.extract_process(proc_line) 4265 4266 # Check that we have something 4267 if not myprocdef: 4268 raise self.InvalidCmd("Empty or wrong format process, please try again.") 4269 # For the check command, only the mode 'virt' make sense. 4270 if myprocdef.get('NLO_mode')=='all': 4271 myprocdef.set('NLO_mode','virt') 4272 else: 4273 myprocdef = None 4274 4275 # If the test has to write out on disk, it should do so at the location 4276 # specified below where the user must be sure to have writing access. 4277 output_path = os.getcwd() 4278 4279 if args[0] in ['timing','stability', 'profile'] and not \ 4280 myprocdef.get('perturbation_couplings'): 4281 raise self.InvalidCmd("Only loop processes can have their "+ 4282 " timings or stability checked.") 4283 4284 if args[0]=='gauge' and \ 4285 not myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4286 raise self.InvalidCmd( 4287 """Feynman vs unitary gauge comparisons can only be done if there are no loop 4288 propagators affected by this gauge. Typically, either processes at tree level 4289 or including only QCD perturbations can be considered here.""") 4290 4291 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2: 4292 raise self.InvalidCmd("The current model does not allow for both "+\ 4293 "Feynman and unitary gauge.") 4294 4295 # Disable some loggers 4296 loggers = [logging.getLogger('madgraph.diagram_generation'), 4297 logging.getLogger('madgraph.loop_diagram_generation'), 4298 logging.getLogger('ALOHA'), 4299 logging.getLogger('madgraph.helas_objects'), 4300 logging.getLogger('madgraph.loop_exporter'), 4301 logging.getLogger('madgraph.export_v4'), 4302 logging.getLogger('cmdprint'), 4303 logging.getLogger('madgraph.model'), 4304 logging.getLogger('madgraph.base_objects')] 4305 old_levels = [log.level for log in loggers] 4306 for log in loggers: 4307 log.setLevel(logging.WARNING) 4308 4309 # run the check 4310 cpu_time1 = time.time() 4311 # Run matrix element generation check on processes 4312 4313 # The aloha python output has trouble when doing (tree level of course) 4314 # python output and that loop_mode is True at the beginning. 4315 # So as a temporary fix for the problem that after doing a check at NLO 4316 # then a check at LO will fail, I make sure I set it to False if the 4317 # process is a tree-level one 4318 if myprocdef: 4319 if myprocdef.get('perturbation_couplings')==[]: 4320 aloha.loop_mode = False 4321 4322 comparisons = [] 4323 gauge_result = [] 4324 gauge_result_no_brs = [] 4325 lorentz_result =[] 4326 nb_processes = 0 4327 timings = [] 4328 stability = [] 4329 profile_time = [] 4330 profile_stab = [] 4331 cms_results = [] 4332 4333 if "_cuttools_dir" in dir(self): 4334 CT_dir = self._cuttools_dir 4335 else: 4336 CT_dir ="" 4337 if "MLReductionLib" in MLoptions: 4338 if 1 in MLoptions["MLReductionLib"]: 4339 MLoptions["MLReductionLib"].remove(1) 4340 # directories for TIR 4341 TIR_dir={} 4342 if "_iregi_dir" in dir(self): 4343 TIR_dir['iregi_dir']=self._iregi_dir 4344 else: 4345 if "MLReductionLib" in MLoptions: 4346 if 3 in MLoptions["MLReductionLib"]: 4347 logger_check.warning('IREGI not available on your system; it will be skipped.') 4348 MLoptions["MLReductionLib"].remove(3) 4349 4350 4351 if "MLReductionLib" in MLoptions: 4352 if 2 in MLoptions["MLReductionLib"]: 4353 logger_check.warning('PJFRY not supported anymore; it will be skipped.') 4354 MLoptions["MLReductionLib"].remove(2) 4355 4356 if 'golem' in self.options and isinstance(self.options['golem'],str): 4357 TIR_dir['golem_dir']=self.options['golem'] 4358 else: 4359 if "MLReductionLib" in MLoptions: 4360 if 4 in MLoptions["MLReductionLib"]: 4361 logger_check.warning('GOLEM not available on your system; it will be skipped.') 4362 MLoptions["MLReductionLib"].remove(4) 4363 4364 if 'samurai' in self.options and isinstance(self.options['samurai'],str): 4365 TIR_dir['samurai_dir']=self.options['samurai'] 4366 else: 4367 if "MLReductionLib" in MLoptions: 4368 if 5 in MLoptions["MLReductionLib"]: 4369 logger_check.warning('Samurai not available on your system; it will be skipped.') 4370 MLoptions["MLReductionLib"].remove(5) 4371 4372 if 'collier' in self.options and isinstance(self.options['collier'],str): 4373 TIR_dir['collier_dir']=self.options['collier'] 4374 else: 4375 if "MLReductionLib" in MLoptions: 4376 if 7 in MLoptions["MLReductionLib"]: 4377 logger_check.warning('Collier not available on your system; it will be skipped.') 4378 MLoptions["MLReductionLib"].remove(7) 4379 4380 if 'ninja' in self.options and isinstance(self.options['ninja'],str): 4381 TIR_dir['ninja_dir']=self.options['ninja'] 4382 else: 4383 if "MLReductionLib" in MLoptions: 4384 if 6 in MLoptions["MLReductionLib"]: 4385 logger_check.warning('Ninja not available on your system; it will be skipped.') 4386 MLoptions["MLReductionLib"].remove(6) 4387 4388 if args[0] in ['timing']: 4389 timings = process_checks.check_timing(myprocdef, 4390 param_card = param_card, 4391 cuttools=CT_dir, 4392 tir=TIR_dir, 4393 options = options, 4394 cmd = self, 4395 output_path = output_path, 4396 MLOptions = MLoptions 4397 ) 4398 4399 if args[0] in ['stability']: 4400 stability=process_checks.check_stability(myprocdef, 4401 param_card = param_card, 4402 cuttools=CT_dir, 4403 tir=TIR_dir, 4404 options = options, 4405 output_path = output_path, 4406 cmd = self, 4407 MLOptions = MLoptions) 4408 4409 if args[0] in ['profile']: 4410 # In this case timing and stability will be checked one after the 4411 # other without re-generating the process. 4412 profile_time, profile_stab = process_checks.check_profile(myprocdef, 4413 param_card = param_card, 4414 cuttools=CT_dir, 4415 tir=TIR_dir, 4416 options = options, 4417 MLOptions = MLoptions, 4418 output_path = output_path, 4419 cmd = self) 4420 4421 if args[0] in ['gauge', 'full'] and \ 4422 len(self._curr_model.get('gauge')) == 2 and\ 4423 myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4424 4425 line = " ".join(args[1:]) 4426 myprocdef = self.extract_process(line) 4427 if gauge == 'unitary': 4428 myprocdef_unit = myprocdef 4429 self.do_set('gauge Feynman', log=False) 4430 myprocdef_feyn = self.extract_process(line) 4431 else: 4432 myprocdef_feyn = myprocdef 4433 self.do_set('gauge unitary', log=False) 4434 myprocdef_unit = self.extract_process(line) 4435 4436 nb_part_unit = len(myprocdef_unit.get('model').get('particles')) 4437 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles')) 4438 if nb_part_feyn == nb_part_unit: 4439 logger_check.error('No Goldstone present for this check!!') 4440 gauge_result_no_brs = process_checks.check_unitary_feynman( 4441 myprocdef_unit, myprocdef_feyn, 4442 param_card = param_card, 4443 options=options, 4444 cuttools=CT_dir, 4445 tir=TIR_dir, 4446 reuse = options['reuse'], 4447 output_path = output_path, 4448 cmd = self) 4449 4450 # restore previous settings 4451 self.do_set('gauge %s' % gauge, log=False) 4452 nb_processes += len(gauge_result_no_brs) 4453 4454 if args[0] in ['permutation', 'full']: 4455 comparisons = process_checks.check_processes(myprocdef, 4456 param_card = param_card, 4457 quick = True, 4458 cuttools=CT_dir, 4459 tir=TIR_dir, 4460 reuse = options['reuse'], 4461 cmd = self, 4462 output_path = output_path, 4463 options=options) 4464 nb_processes += len(comparisons[0]) 4465 4466 if args[0] in ['lorentz', 'full']: 4467 myprocdeff = copy.copy(myprocdef) 4468 lorentz_result = process_checks.check_lorentz(myprocdeff, 4469 param_card = param_card, 4470 cuttools=CT_dir, 4471 tir=TIR_dir, 4472 reuse = options['reuse'], 4473 cmd = self, 4474 output_path = output_path, 4475 options=options) 4476 nb_processes += len(lorentz_result) 4477 4478 if args[0] in ['brs', 'full']: 4479 gauge_result = process_checks.check_gauge(myprocdef, 4480 param_card = param_card, 4481 cuttools=CT_dir, 4482 tir=TIR_dir, 4483 reuse = options['reuse'], 4484 cmd = self, 4485 output_path = output_path, 4486 options=options) 4487 nb_processes += len(gauge_result) 4488 4489 # The CMS check is typically more complicated and slower than others 4490 # so we don't run it automatically with 'full'. 4491 if args[0] in ['cms']: 4492 4493 cms_original_setup = self.options['complex_mass_scheme'] 4494 process_line = " ".join(args[1:]) 4495 # Merge in the CMS_options to the options 4496 for key, value in CMS_options.items(): 4497 if key=='tweak': 4498 continue 4499 if key not in options: 4500 options[key] = value 4501 else: 4502 raise MadGraph5Error("Option '%s' is both in the option"%key+\ 4503 " and CMS_option dictionary.") 4504 4505 if options['analyze']=='None': 4506 cms_results = [] 4507 for tweak in CMS_options['tweak']: 4508 options['tweak']=tweak 4509 # Try to guess the save path and try to load it before running 4510 guessed_proc = myprocdef.get_process( 4511 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4512 if not leg.get('state')], 4513 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4514 if leg.get('state')]) 4515 save_path = process_checks.CMS_save_path('pkl', 4516 {'ordered_processes':[guessed_proc.base_string()], 4517 'perturbation_orders':guessed_proc.get('perturbation_couplings')}, 4518 self._curr_model, options, output_path=output_path) 4519 if os.path.isfile(save_path) and options['reuse']: 4520 cms_result = save_load_object.load_from_file(save_path) 4521 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"% 4522 (tweak['name'],save_path)) 4523 if cms_result is None: 4524 raise self.InvalidCmd('The complex mass scheme check result'+ 4525 " file below could not be read.\n %s"%save_path) 4526 else: 4527 cms_result = process_checks.check_complex_mass_scheme( 4528 process_line, 4529 param_card = param_card, 4530 cuttools=CT_dir, 4531 tir=TIR_dir, 4532 cmd = self, 4533 output_path = output_path, 4534 MLOptions = MLoptions, 4535 options=options) 4536 # Now set the correct save path 4537 save_path = process_checks.CMS_save_path('pkl', cms_result, 4538 self._curr_model, options, output_path=output_path) 4539 cms_results.append((cms_result,save_path,tweak['name'])) 4540 else: 4541 cms_result = save_load_object.load_from_file( 4542 options['analyze'].split(',')[0]) 4543 cms_results.append((cms_result,options['analyze'].split(',')[0], 4544 CMS_options['tweak'][0]['name'])) 4545 if cms_result is None: 4546 raise self.InvalidCmd('The complex mass scheme check result'+ 4547 " file below could not be read.\n %s" 4548 %options['analyze'].split(',')[0]) 4549 4550 # restore previous settings 4551 self.do_set('complex_mass_scheme %s'%str(cms_original_setup), 4552 log=False) 4553 # Use here additional key 'ordered_processes' 4554 nb_processes += len(cms_result['ordered_processes']) 4555 4556 cpu_time2 = time.time() 4557 logger_check.info("%i check performed in %s"% (nb_processes, 4558 misc.format_time(int(cpu_time2 - cpu_time1)))) 4559 4560 if args[0] in ['cms']: 4561 text = "Note that the complex mass scheme test in principle only\n" 4562 text+= "works for stable particles in final states.\n\ns" 4563 if args[0] not in ['timing','stability', 'profile', 'cms']: 4564 if self.options['complex_mass_scheme']: 4565 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n" 4566 text+= "results only for stable particles in final states.\n\ns" 4567 elif not myprocdef.get('perturbation_couplings'): 4568 text = "Note That all width have been set to zero for those checks\n\n" 4569 else: 4570 text = "\n" 4571 else: 4572 text ="\n" 4573 4574 if timings: 4575 text += 'Timing result for the '+('optimized' if \ 4576 self.options['loop_optimized_output'] else 'default')+' output:\n' 4577 4578 text += process_checks.output_timings(myprocdef, timings) 4579 if stability: 4580 text += 'Stability result for the '+('optimized' if \ 4581 self.options['loop_optimized_output'] else 'default')+' output:\n' 4582 text += process_checks.output_stability(stability,output_path) 4583 4584 if profile_time and profile_stab: 4585 text += 'Timing result '+('optimized' if \ 4586 self.options['loop_optimized_output'] else 'default')+':\n' 4587 text += process_checks.output_profile(myprocdef, profile_stab, 4588 profile_time, output_path, options['reuse']) + '\n' 4589 if lorentz_result: 4590 text += 'Lorentz invariance results:\n' 4591 text += process_checks.output_lorentz_inv(lorentz_result) + '\n' 4592 if gauge_result: 4593 text += 'Gauge results:\n' 4594 text += process_checks.output_gauge(gauge_result) + '\n' 4595 if gauge_result_no_brs: 4596 text += 'Gauge results (switching between Unitary/Feynman/axial gauge):\n' 4597 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n' 4598 if cms_results: 4599 text += 'Complex mass scheme results (varying width in the off-shell regions):\n' 4600 cms_result = cms_results[0][0] 4601 if len(cms_results)>1: 4602 analyze = [] 4603 for i, (cms_res, save_path, tweakname) in enumerate(cms_results): 4604 save_load_object.save_to_file(save_path, cms_res) 4605 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"% 4606 (tweakname,save_path)) 4607 if i==0: 4608 analyze.append(save_path) 4609 else: 4610 analyze.append('%s(%s)'%(save_path,tweakname)) 4611 options['analyze']=','.join(analyze) 4612 options['tweak'] = CMS_options['tweak'][0] 4613 4614 self._cms_checks.append({'line':line, 'cms_result':cms_result, 4615 'options':options, 'output_path':output_path}) 4616 text += process_checks.output_complex_mass_scheme(cms_result, 4617 output_path, options, self._curr_model, 4618 output='concise_text' if options['report']=='concise' else 'text')+'\n' 4619 4620 if comparisons and len(comparisons[0])>0: 4621 text += 'Process permutation results:\n' 4622 text += process_checks.output_comparisons(comparisons[0]) + '\n' 4623 self._comparisons = comparisons 4624 4625 # We use the reuse tag for an alternative way of skipping the pager. 4626 if len(text.split('\n'))>20 and not '-reuse' in line and text!='': 4627 if 'test_manager' not in sys.argv[0]: 4628 pydoc.pager(text) 4629 4630 # Restore diagram logger 4631 for i, log in enumerate(loggers): 4632 log.setLevel(old_levels[i]) 4633 4634 # Output the result to the interface directly if short enough or if it 4635 # was anyway not output to the pager 4636 if len(text.split('\n'))<=20 or options['reuse']: 4637 # Useful to really specify what logger is used for ML acceptance tests 4638 logging.getLogger('madgraph.check_cmd').info(text) 4639 else: 4640 logging.getLogger('madgraph.check_cmd').debug(text) 4641 4642 # clean the globals created. 4643 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL) 4644 if not options['reuse']: 4645 process_checks.clean_up(self._mgme_dir) 4646 4647
4648 - def clean_process(self):
4649 """ensure that all processes are cleaned from memory. 4650 typically called from import model and generate XXX command 4651 """ 4652 4653 aloha_lib.KERNEL.clean() 4654 # Reset amplitudes 4655 self._curr_amps = diagram_generation.AmplitudeList() 4656 # Reset Process definition 4657 self._curr_proc_defs = base_objects.ProcessDefinitionList() 4658 # Reset Helas matrix elements 4659 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4660 self._generate_info = "" 4661 # Reset _done_export, since we have new process 4662 self._done_export = False 4663 # Also reset _export_format and _export_dir 4664 self._export_format = None
4665 4666 4667 # Generate a new amplitude
4668 - def do_generate(self, line):
4669 """Main commands: Generate an amplitude for a given process""" 4670 4671 self.clean_process() 4672 self._generate_info = line 4673 4674 # Call add process 4675 args = self.split_arg(line) 4676 args.insert(0, 'process') 4677 self.do_add(" ".join(args))
4678
4679 - def extract_process(self, line, proc_number = 0, overall_orders = {}):
4680 """Extract a process definition from a string. Returns 4681 a ProcessDefinition.""" 4682 4683 orig_line = line 4684 # Check basic validity of the line 4685 if not len(re.findall('>\D', line)) in [1,2]: 4686 self.do_help('generate') 4687 raise self.InvalidCmd('Wrong use of \">\" special character.') 4688 4689 4690 # Perform sanity modifications on the lines: 4691 # Add a space before and after any > , $ / | [ ] 4692 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)") 4693 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line) 4694 4695 # Use regular expressions to extract s-channel propagators, 4696 # forbidden s-channel propagators/particles, coupling orders 4697 # and process number, starting from the back 4698 4699 # Start with process number (identified by "@") 4700 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4701 proc_number_re = proc_number_pattern.match(line) 4702 if proc_number_re: 4703 proc_number = int(proc_number_re.group(2)) 4704 line = proc_number_re.group(1)+ proc_number_re.group(3) 4705 #overall_order are already handle but it is better to pass the info to each group 4706 4707 # Now check for perturbation orders, specified in between squared brackets 4708 perturbation_couplings_pattern = \ 4709 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\ 4710 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 4711 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 4712 perturbation_couplings = "" 4713 LoopOption= 'tree' 4714 HasBorn= True 4715 if perturbation_couplings_re: 4716 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 4717 option=perturbation_couplings_re.group("option") 4718 if option: 4719 if option in self._valid_nlo_modes: 4720 LoopOption=option 4721 if option=='sqrvirt': 4722 LoopOption='virt' 4723 HasBorn=False 4724 elif option=='noborn': 4725 HasBorn=False 4726 else: 4727 raise self.InvalidCmd("NLO mode %s is not valid. "%option+\ 4728 "Valid modes are %s. "%str(self._valid_nlo_modes)) 4729 else: 4730 LoopOption='all' 4731 4732 line = perturbation_couplings_re.group("proc")+\ 4733 perturbation_couplings_re.group("rest") 4734 4735 ## Now check for orders/squared orders/constrained orders 4736 order_pattern = re.compile(\ 4737 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\ 4738 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*?(?P<after>.*)") 4739 order_re = order_pattern.match(line) 4740 squared_orders = {} 4741 orders = {} 4742 constrained_orders = {} 4743 ## The 'split_orders' (i.e. those for which individual matrix element 4744 ## evalutations must be provided for each corresponding order value) are 4745 ## defined from the orders specified in between [] and any order for 4746 ## which there are squared order constraints. 4747 split_orders = [] 4748 while order_re: 4749 type = order_re.group('type') 4750 if order_re.group('name').endswith('^2'): 4751 if type not in self._valid_sqso_types: 4752 raise self.InvalidCmd("Type of squared order "+\ 4753 "constraint '%s'"% type+" is not supported.") 4754 if type == '=': 4755 name = order_re.group('name') 4756 value = order_re.group('value') 4757 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4758 {'n':name, 'v': value}) 4759 type = "<=" 4760 squared_orders[order_re.group('name')[:-2]] = \ 4761 (int(order_re.group('value')),type) 4762 else: 4763 if type not in self._valid_amp_so_types: 4764 raise self.InvalidCmd("Amplitude order constraints can only be of type %s"%\ 4765 (', '.join(self._valid_amp_so_types))+", not '%s'."%type) 4766 name = order_re.group('name') 4767 value = int(order_re.group('value')) 4768 if type in ['=', '<=']: 4769 if type == '=' and value != 0: 4770 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4771 {'n':name, 'v': value}) 4772 orders[name] = value 4773 elif type == "==": 4774 constrained_orders[name] = (value, type) 4775 if name not in squared_orders: 4776 squared_orders[name] = (2 * value,'==') 4777 if True:#name not in orders: 4778 orders[name] = value 4779 4780 elif type == ">": 4781 constrained_orders[name] = (value, type) 4782 if name not in squared_orders: 4783 squared_orders[name] = (2 * value,'>') 4784 4785 line = '%s %s' % (order_re.group('before'),order_re.group('after')) 4786 order_re = order_pattern.match(line) 4787 4788 # handle the case where default is not 99 and some coupling defined 4789 if self.options['default_unset_couplings'] != 99 and \ 4790 (orders or squared_orders): 4791 4792 to_set = [name for name in self._curr_model.get('coupling_orders') 4793 if name not in orders and name not in squared_orders] 4794 if to_set: 4795 logger.info('the following coupling will be allowed up to the maximal value of %s: %s' % 4796 (self.options['default_unset_couplings'], ', '.join(to_set)), '$MG:BOLD') 4797 for name in to_set: 4798 orders[name] = int(self.options['default_unset_couplings']) 4799 4800 #only allow amplitue restrctions >/ == for LO/tree level 4801 if constrained_orders and LoopOption != 'tree': 4802 raise self.InvalidCmd("Amplitude order constraints (for not LO processes) can only be of type %s"%\ 4803 (', '.join(['<=']))+", not '%s'."%type) 4804 4805 # If the squared orders are defined but not the orders, assume 4806 # orders=sq_orders. In case the squared order has a negative value or is 4807 # defined with the '>' operato, then this order correspondingly set to 4808 # be maximal (99) since there is no way to know, during generation, if 4809 # the amplitude being contstructed will be leading or not. 4810 if orders=={} and squared_orders!={}: 4811 for order in squared_orders.keys(): 4812 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>': 4813 orders[order]=squared_orders[order][0] 4814 else: 4815 orders[order]=99 4816 4817 4818 if not self._curr_model['case_sensitive']: 4819 # Particle names lowercase 4820 line = line.lower() 4821 4822 # Now check for forbidden particles, specified using "/" 4823 slash = line.find("/") 4824 dollar = line.find("$") 4825 forbidden_particles = "" 4826 if slash > 0: 4827 if dollar > slash: 4828 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line) 4829 else: 4830 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line) 4831 if forbidden_particles_re: 4832 forbidden_particles = forbidden_particles_re.group(2) 4833 line = forbidden_particles_re.group(1) 4834 if len(forbidden_particles_re.groups()) > 2: 4835 line = line + forbidden_particles_re.group(3) 4836 4837 # Now check for forbidden schannels, specified using "$$" 4838 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line) 4839 forbidden_schannels = "" 4840 if forbidden_schannels_re: 4841 forbidden_schannels = forbidden_schannels_re.group(2) 4842 line = forbidden_schannels_re.group(1) 4843 4844 # Now check for forbidden onshell schannels, specified using "$" 4845 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line) 4846 forbidden_onsh_schannels = "" 4847 if forbidden_onsh_schannels_re: 4848 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2) 4849 line = forbidden_onsh_schannels_re.group(1) 4850 4851 # Now check for required schannels, specified using "> >" 4852 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line) 4853 required_schannels = "" 4854 if required_schannels_re: 4855 required_schannels = required_schannels_re.group(2) 4856 line = required_schannels_re.group(1) + ">" + \ 4857 required_schannels_re.group(3) 4858 4859 args = self.split_arg(line) 4860 4861 myleglist = base_objects.MultiLegList() 4862 state = False 4863 4864 # Extract process 4865 for part_name in args: 4866 if part_name == '>': 4867 if not myleglist: 4868 raise self.InvalidCmd("No final state particles") 4869 state = True 4870 continue 4871 4872 mylegids = [] 4873 polarization = [] 4874 if '{' in part_name: 4875 part_name, pol = part_name.split('{',1) 4876 pol, rest = pol.split('}',1) 4877 4878 no_dup_name = part_name 4879 while True: 4880 try: 4881 spin = self._curr_model.get_particle(no_dup_name).get('spin') 4882 break 4883 except AttributeError: 4884 if no_dup_name in self._multiparticles: 4885 spins = set([self._curr_model.get_particle(p).get('spin') for p in self._multiparticles[no_dup_name]]) 4886 if len(spins) > 1: 4887 raise self.InvalidCmd('Can not use polarised on multi-particles for multi-particles with various spin') 4888 else: 4889 spin = spins.pop() 4890 break 4891 elif no_dup_name[0].isdigit(): 4892 no_dup_name = no_dup_name[1:] 4893 else: 4894 raise 4895 if rest: 4896 raise self.InvalidCmd('A space is required after the "}" symbol to separate particles') 4897 ignore =False 4898 for i,p in enumerate(pol): 4899 if ignore or p==',': 4900 ignore= False 4901 continue 4902 if p in ['t','T']: 4903 if spin == 3: 4904 polarization += [1,-1] 4905 else: 4906 raise self.InvalidCmd('"T" (transverse) polarization are only supported for spin one particle.') 4907 elif p in ['l', 'L']: 4908 if spin == 3: 4909 logger.warning('"L" polarization is interpreted as Left for Longitudinal please use "0".') 4910 polarization += [-1] 4911 elif p in ['R','r']: 4912 polarization += [1] 4913 elif p in ["A",'a']: 4914 if spin == 3: 4915 polarization += [99] 4916 else: 4917 raise self.InvalidCmd('"A" (auxiliary) polarization are only supported for spin one particle.') 4918 elif p in ['+']: 4919 if i +1 < len(pol) and pol[i+1].isdigit(): 4920 p = int(pol[i+1]) 4921 if abs(p) > 3: 4922 raise self.InvalidCmd("polarization are between -3 and 3") 4923 polarization.append(p) 4924 ignore = True 4925 else: 4926 polarization += [1] 4927 elif p in ['-']: 4928 if i+1 < len(pol) and pol[i+1].isdigit(): 4929 p = int(pol[i+1]) 4930 if abs(p) > 3: 4931 raise self.InvalidCmd("polarization are between -3 and 3") 4932 polarization.append(-p) 4933 ignore = True 4934 else: 4935 polarization += [-1] 4936 elif p in [0,'0']: 4937 if spin in [1,2]: 4938 raise self.InvalidCmd('"0" (longitudinal) polarization are not supported for scalar/fermion.') 4939 else: 4940 polarization += [0] 4941 elif p.isdigit(): 4942 p = int(p) 4943 if abs(p) > 3: 4944 raise self.InvalidCmd("polarization are between -3 and 3") 4945 polarization.append(p) 4946 else: 4947 raise self.InvalidCmd('Invalid Polarization') 4948 4949 duplicate =1 4950 if part_name in self._multiparticles: 4951 if isinstance(self._multiparticles[part_name][0], list): 4952 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 4953 " which can be used only for required s-channels") 4954 mylegids.extend(self._multiparticles[part_name]) 4955 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit(): 4956 if int(part_name) in self._curr_model.get('particle_dict'): 4957 mylegids.append(int(part_name)) 4958 else: 4959 raise self.InvalidCmd("No pdg_code %s in model" % part_name) 4960 else: 4961 mypart = self._curr_model['particles'].get_copy(part_name) 4962 4963 if mypart: 4964 mylegids.append(mypart.get_pdg_code()) 4965 else: 4966 # check for duplication flag! 4967 if part_name[0].isdigit(): 4968 duplicate, part_name = int(part_name[0]), part_name[1:] 4969 if part_name in self._multiparticles: 4970 if isinstance(self._multiparticles[part_name][0], list): 4971 raise self.InvalidCmd(\ 4972 "Multiparticle %s is or-multiparticle" % part_name + \ 4973 " which can be used only for required s-channels") 4974 mylegids.extend(self._multiparticles[part_name]) 4975 else: 4976 mypart = self._curr_model['particles'].get_copy(part_name) 4977 mylegids.append(mypart.get_pdg_code()) 4978 4979 if mylegids: 4980 for _ in range(duplicate): 4981 myleglist.append(base_objects.MultiLeg({'ids':mylegids, 4982 'state':state, 4983 'polarization': polarization})) 4984 else: 4985 raise self.InvalidCmd("No particle %s in model" % part_name) 4986 4987 # Apply the keyword 'all' for perturbed coupling orders. 4988 if perturbation_couplings.lower() in ['all', 'loonly']: 4989 if perturbation_couplings.lower() in ['loonly']: 4990 LoopOption = 'LOonly' 4991 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings']) 4992 4993 4994 if [leg for leg in myleglist if leg.get('state') == True]: 4995 # We have a valid process 4996 # Extract perturbation orders 4997 perturbation_couplings_list = perturbation_couplings.split() 4998 if perturbation_couplings_list==['']: 4999 perturbation_couplings_list=[] 5000 # Correspondingly set 'split_order' from the squared orders and the 5001 # perturbation couplings list 5002 split_orders=list(set(perturbation_couplings_list+list(squared_orders.keys()))) 5003 try: 5004 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else 5005 self._curr_model.get('order_hierarchy') 5006 [elem if not elem.endswith('.sqrt') else elem[:-5]]) 5007 except KeyError: 5008 raise self.InvalidCmd("The loaded model does not defined a "+\ 5009 " coupling order hierarchy for these couplings: %s"%\ 5010 str([so for so in split_orders if so!='WEIGHTED' and so not 5011 in list(self._curr_model['order_hierarchy'].keys())])) 5012 5013 # If the loopOption is 'tree' then the user used the syntax 5014 # [tree= Orders] for the sole purpose of setting split_orders. We 5015 # then empty the perturbation_couplings_list at this stage. 5016 if LoopOption=='tree': 5017 perturbation_couplings_list = [] 5018 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']: 5019 if not isinstance(self._curr_model,loop_base_objects.LoopModel): 5020 raise self.InvalidCmd(\ 5021 "The current model does not allow for loop computations.") 5022 else: 5023 for pert_order in perturbation_couplings_list: 5024 if pert_order not in self._curr_model['perturbation_couplings']: 5025 raise self.InvalidCmd(\ 5026 "Perturbation order %s is not among" % pert_order + \ 5027 " the perturbation orders allowed for by the loop model.") 5028 if not self.options['loop_optimized_output'] and \ 5029 LoopOption not in ['tree','real'] and split_orders!=[]: 5030 logger.warning('The default output mode (loop_optimized_output'+\ 5031 ' = False) does not support evaluations for given powers of'+\ 5032 ' coupling orders. MadLoop output will therefore not be'+\ 5033 ' able to provide such quantities.') 5034 split_orders = [] 5035 5036 # Now extract restrictions 5037 forbidden_particle_ids = \ 5038 self.extract_particle_ids(forbidden_particles) 5039 if forbidden_particle_ids and \ 5040 isinstance(forbidden_particle_ids[0], list): 5041 raise self.InvalidCmd(\ 5042 "Multiparticle %s is or-multiparticle" % part_name + \ 5043 " which can be used only for required s-channels") 5044 forbidden_onsh_schannel_ids = \ 5045 self.extract_particle_ids(forbidden_onsh_schannels) 5046 forbidden_schannel_ids = \ 5047 self.extract_particle_ids(forbidden_schannels) 5048 if forbidden_onsh_schannel_ids and \ 5049 isinstance(forbidden_onsh_schannel_ids[0], list): 5050 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 5051 " which can be used only for required s-channels") 5052 if forbidden_schannel_ids and \ 5053 isinstance(forbidden_schannel_ids[0], list): 5054 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 5055 " which can be used only for required s-channels") 5056 required_schannel_ids = \ 5057 self.extract_particle_ids(required_schannels) 5058 if required_schannel_ids and not \ 5059 isinstance(required_schannel_ids[0], list): 5060 required_schannel_ids = [required_schannel_ids] 5061 5062 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()]) 5063 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1: 5064 raise self.InvalidCmd( 5065 "At most one negative squared order constraint can be specified.") 5066 5067 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()]) 5068 5069 out = base_objects.ProcessDefinition({'legs': myleglist, 5070 'model': self._curr_model, 5071 'id': proc_number, 5072 'orders': orders, 5073 'squared_orders':sqorders_values, 5074 'sqorders_types':sqorders_types, 5075 'constrained_orders': constrained_orders, 5076 'forbidden_particles': forbidden_particle_ids, 5077 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids, 5078 'forbidden_s_channels': forbidden_schannel_ids, 5079 'required_s_channels': required_schannel_ids, 5080 'overall_orders': overall_orders, 5081 'perturbation_couplings': perturbation_couplings_list, 5082 'has_born':HasBorn, 5083 'NLO_mode':LoopOption, 5084 'split_orders':split_orders 5085 }) 5086 return out
5087 # 'is_decay_chain': decay_process\ 5088 5089
5090 - def create_loop_induced(self, line, myprocdef=None):
5091 """ Routine to create the MultiProcess for the loop-induced case""" 5092 5093 args = self.split_arg(line) 5094 5095 warning_duplicate = True 5096 if '--no_warning=duplicate' in args: 5097 warning_duplicate = False 5098 args.remove('--no_warning=duplicate') 5099 5100 # Check the validity of the arguments 5101 self.check_add(args) 5102 if args[0] == 'process': 5103 args = args[1:] 5104 5105 # special option for 1->N to avoid generation of kinematically forbidden 5106 #decay. 5107 if args[-1].startswith('--optimize'): 5108 optimize = True 5109 args.pop() 5110 else: 5111 optimize = False 5112 5113 # Extract potential loop_filter 5114 loop_filter=None 5115 for arg in args: 5116 if arg.startswith('--loop_filter='): 5117 loop_filter = arg[14:] 5118 #if not isinstance(self, extended_cmd.CmdShell): 5119 # raise self.InvalidCmd, "loop_filter is not allowed in web mode" 5120 args = [a for a in args if not a.startswith('--loop_filter=')] 5121 5122 if not myprocdef: 5123 myprocdef = self.extract_process(' '.join(args)) 5124 5125 myprocdef.set('NLO_mode', 'noborn') 5126 5127 # store the first process (for the perl script) 5128 if not self._generate_info: 5129 self._generate_info = line 5130 5131 # Reset Helas matrix elements 5132 #self._curr_matrix_elements = helas_objects.HelasLoopInducedMultiProcess() 5133 5134 5135 # Check that we have the same number of initial states as 5136 # existing processes 5137 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 5138 myprocdef.get_ninitial(): 5139 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 5140 5141 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \ 5142 self._curr_amps[0]['has_born']): 5143 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process") 5144 5145 # Negative coupling order contraints can be given on at most one 5146 # coupling order (and either in squared orders or orders, not both) 5147 if len([1 for val in list(myprocdef.get('orders').values())+\ 5148 list(myprocdef.get('squared_orders').values()) if val<0])>1: 5149 raise MadGraph5Error("Negative coupling order constraints"+\ 5150 " can only be given on one type of coupling and either on"+\ 5151 " squared orders or amplitude orders, not both.") 5152 5153 cpu_time1 = time.time() 5154 5155 # Generate processes 5156 if self.options['group_subprocesses'] == 'Auto': 5157 collect_mirror_procs = True 5158 else: 5159 collect_mirror_procs = self.options['group_subprocesses'] 5160 ignore_six_quark_processes = \ 5161 self.options['ignore_six_quark_processes'] if \ 5162 "ignore_six_quark_processes" in self.options \ 5163 else [] 5164 5165 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 5166 5167 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef, 5168 collect_mirror_procs = collect_mirror_procs, 5169 ignore_six_quark_processes = ignore_six_quark_processes, 5170 optimize=optimize, 5171 loop_filter=loop_filter) 5172 5173 for amp in myproc.get('amplitudes'): 5174 if amp not in self._curr_amps: 5175 self._curr_amps.append(amp) 5176 if amp['has_born']: 5177 raise Exception 5178 elif warning_duplicate: 5179 raise self.InvalidCmd("Duplicate process %s found. Please check your processes." % \ 5180 amp.nice_string_processes()) 5181 5182 # Reset _done_export, since we have new process 5183 self._done_export = False 5184 self._curr_proc_defs.append(myprocdef) 5185 5186 cpu_time2 = time.time() 5187 5188 nprocs = len(myproc.get('amplitudes')) 5189 ndiags = sum([amp.get_number_of_diagrams() for \ 5190 amp in myproc.get('amplitudes')]) 5191 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 5192 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 5193 ndiags = sum([amp.get_number_of_diagrams() for \ 5194 amp in self._curr_amps]) 5195 logger.info("Total: %i processes with %i diagrams" % \ 5196 (len(self._curr_amps), ndiags))
5197 5198 @staticmethod
5199 - def split_process_line(procline):
5200 """Takes a valid process and return 5201 a tuple (core_process, options). This removes 5202 - any NLO specifications. 5203 - any options 5204 [Used by MadSpin] 5205 """ 5206 5207 # remove the tag "[*]": this tag is used in aMC@LNO , 5208 # but it is not a valid syntax for LO 5209 line=procline 5210 pos1=line.find("[") 5211 if pos1>0: 5212 pos2=line.find("]") 5213 if pos2 >pos1: 5214 line=line[:pos1]+line[pos2+1:] 5215 # 5216 # Extract the options: 5217 # 5218 # A. Remove process number (identified by "@") 5219 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 5220 proc_number_re = proc_number_pattern.match(line) 5221 if proc_number_re: 5222 line = proc_number_re.group(1) + proc_number_re.group(3) 5223 5224 # B. search for the beginning of the option string 5225 pos=1000 5226 # start with order 5227 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$") 5228 order_re = order_pattern.match(line) 5229 if (order_re): 5230 pos_order=line.find(order_re.group(2)) 5231 if pos_order>0 and pos_order < pos : pos=pos_order 5232 5233 # then look for slash or dollar 5234 slash = line.find("/") 5235 if slash > 0 and slash < pos: pos=slash 5236 dollar = line.find("$") 5237 if dollar > 0 and dollar < pos: pos=dollar 5238 5239 if pos<1000: 5240 proc_option=line[pos:] 5241 line=line[:pos] 5242 else: 5243 proc_option="" 5244 5245 return line, proc_option
5246
5247 - def get_final_part(self, procline):
5248 """Takes a valid process and return 5249 a set of id of final states particles. [Used by MadSpin] 5250 """ 5251 5252 if not self._curr_model['case_sensitive']: 5253 procline = procline.lower() 5254 pids = self._curr_model.get('name2pdg') 5255 5256 # method. 5257 # 1) look for decay. 5258 # in presence of decay call this routine recursively and veto 5259 # the particles which are decayed 5260 5261 # Deal with decay chain 5262 if ',' in procline: 5263 core, decay = procline.split(',', 1) 5264 core_final = self.get_final_part(core) 5265 5266 #split the decay 5267 all_decays = decay.split(',') 5268 nb_level, tmp_decay = 0, '' 5269 decays = [] 5270 # deal with () 5271 for one_decay in all_decays: 5272 if '(' in one_decay: 5273 nb_level += 1 5274 if ')' in one_decay: 5275 nb_level -= 1 5276 5277 if nb_level: 5278 if tmp_decay: 5279 tmp_decay += ', %s' % one_decay 5280 else: 5281 tmp_decay = one_decay 5282 elif tmp_decay: 5283 final = '%s,%s' % (tmp_decay, one_decay) 5284 final = final.strip() 5285 assert final[0] == '(' and final[-1] == ')' 5286 final = final[1:-1] 5287 decays.append(final) 5288 tmp_decay = '' 5289 else: 5290 decays.append(one_decay) 5291 # remove from the final states all particles which are decayed 5292 for one_decay in decays: 5293 first = one_decay.split('>',1)[0].strip() 5294 if first in pids: 5295 pid = set([pids[first]]) 5296 elif first in self._multiparticles: 5297 pid = set(self._multiparticles[first]) 5298 else: 5299 raise Exception('invalid particle name: %s. ' % first) 5300 core_final.difference_update(pid) 5301 core_final.update(self.get_final_part(one_decay)) 5302 5303 return core_final 5304 5305 # NO DECAY CHAIN 5306 final = set() 5307 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline) 5308 particles = final_states.groups()[0] 5309 for particle in particles.split(): 5310 if '{' in particle: 5311 particle = particle.split('{')[0] 5312 if particle in pids: 5313 final.add(pids[particle]) 5314 elif particle in self._multiparticles: 5315 final.update(set(self._multiparticles[particle])) 5316 elif particle[0].isdigit(): 5317 if particle[1:] in pids: 5318 final.add(pids[particle[1:]]) 5319 elif particle in self._multiparticles: 5320 final.update(set(self._multiparticles[particle[1:]])) 5321 5322 return final
5323
5324 - def extract_particle_ids(self, args):
5325 """Extract particle ids from a list of particle names. If 5326 there are | in the list, this corresponds to an or-list, which 5327 is represented as a list of id lists. An or-list is used to 5328 allow multiple required s-channel propagators to be specified 5329 (e.g. Z/gamma).""" 5330 5331 if isinstance(args, six.string_types): 5332 args.replace("|", " | ") 5333 args = self.split_arg(args) 5334 all_ids = [] 5335 ids=[] 5336 for part_name in args: 5337 mypart = self._curr_model['particles'].get_copy(part_name) 5338 if mypart: 5339 ids.append([mypart.get_pdg_code()]) 5340 elif part_name in self._multiparticles: 5341 ids.append(self._multiparticles[part_name]) 5342 elif part_name == "|": 5343 # This is an "or-multiparticle" 5344 if ids: 5345 all_ids.append(ids) 5346 ids = [] 5347 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()): 5348 ids.append([int(part_name)]) 5349 else: 5350 raise self.InvalidCmd("No particle %s in model" % part_name) 5351 all_ids.append(ids) 5352 # Flatten id list, to take care of multiparticles and 5353 # or-multiparticles 5354 res_lists = [] 5355 for i, id_list in enumerate(all_ids): 5356 res_lists.extend(diagram_generation.expand_list_list(id_list)) 5357 # Trick to avoid duplication while keeping ordering 5358 for ilist, idlist in enumerate(res_lists): 5359 set_dict = {} 5360 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \ 5361 if i not in set_dict] 5362 5363 if len(res_lists) == 1: 5364 res_lists = res_lists[0] 5365 5366 return res_lists
5367
5368 - def optimize_order(self, pdg_list):
5369 """Optimize the order of particles in a pdg list, so that 5370 similar particles are next to each other. Sort according to: 5371 1. pdg > 0, 2. spin, 3. color, 4. mass > 0""" 5372 5373 if not pdg_list: 5374 return 5375 if not isinstance(pdg_list[0], int): 5376 return 5377 5378 model = self._curr_model 5379 pdg_list.sort(key = lambda i: i < 0) 5380 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion()) 5381 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'), 5382 reverse = True) 5383 pdg_list.sort(key = lambda i: \ 5384 model.get_particle(i).get('mass').lower() != 'zero')
5385
5386 - def extract_decay_chain_process(self, line, level_down=False, proc_number=0):
5387 """Recursively extract a decay chain process definition from a 5388 string. Returns a ProcessDefinition.""" 5389 5390 # Start with process number (identified by "@") and overall orders 5391 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*\<?=\s*\d+\s*)*)$") 5392 proc_number_re = proc_number_pattern.match(line) 5393 overall_orders = {} 5394 if proc_number_re: 5395 proc_number = int(proc_number_re.group(2)) 5396 line = proc_number_re.group(1) 5397 if proc_number_re.group(3): 5398 order_pattern = re.compile("^(.*?)\s*(\w+)\s*\<?=\s*(\d+)\s*$") 5399 order_line = proc_number_re.group(3) 5400 order_re = order_pattern.match(order_line) 5401 while order_re: 5402 overall_orders[order_re.group(2)] = int(order_re.group(3)) 5403 order_line = order_re.group(1) 5404 order_re = order_pattern.match(order_line) 5405 logger.info(line) 5406 5407 5408 index_comma = line.find(",") 5409 index_par = line.find(")") 5410 min_index = index_comma 5411 if index_par > -1 and (index_par < min_index or min_index == -1): 5412 min_index = index_par 5413 5414 if min_index > -1: 5415 core_process = self.extract_process(line[:min_index], proc_number, 5416 overall_orders) 5417 else: 5418 core_process = self.extract_process(line, proc_number, 5419 overall_orders) 5420 5421 #level_down = False 5422 5423 while index_comma > -1: 5424 line = line[index_comma + 1:] 5425 if not line.strip(): 5426 break 5427 index_par = line.find(')') 5428 # special cases: parenthesis but no , => remove the paranthesis! 5429 if line.lstrip()[0] == '(' and index_par !=-1 and \ 5430 not ',' in line[:index_par]: 5431 par_start = line.find('(') 5432 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:]) 5433 index_par = line.find(')') 5434 if line.lstrip()[0] == '(': 5435 # Go down one level in process hierarchy 5436 #level_down = True 5437 line = line.lstrip()[1:] 5438 # This is where recursion happens 5439 decay_process, line = \ 5440 self.extract_decay_chain_process(line, 5441 level_down=True) 5442 index_comma = line.find(",") 5443 index_par = line.find(')') 5444 else: 5445 index_comma = line.find(",") 5446 min_index = index_comma 5447 if index_par > -1 and \ 5448 (index_par < min_index or min_index == -1): 5449 min_index = index_par 5450 if min_index > -1: 5451 decay_process = self.extract_process(line[:min_index]) 5452 else: 5453 decay_process = self.extract_process(line) 5454 5455 core_process.get('decay_chains').append(decay_process) 5456 5457 if level_down: 5458 if index_par == -1: 5459 raise self.InvalidCmd("Missing ending parenthesis for decay process") 5460 5461 if index_par < index_comma: 5462 line = line[index_par + 1:] 5463 level_down = False 5464 break 5465 5466 if level_down: 5467 index_par = line.find(')') 5468 if index_par == -1: 5469 raise self.InvalidCmd("Missing ending parenthesis for decay process") 5470 line = line[index_par + 1:] 5471 5472 # Return the core process (ends recursion when there are no 5473 # more decays) 5474 return core_process, line
5475 5476 5477 # Import files
5478 - def do_import(self, line, force=False):
5479 """Main commands: Import files with external formats""" 5480 5481 args = self.split_arg(line) 5482 # Check argument's validity 5483 self.check_import(args) 5484 if args[0].startswith('model'): 5485 self._model_v4_path = None 5486 # Reset amplitudes and matrix elements 5487 self.clean_process() 5488 # Import model 5489 if args[0].endswith('_v4'): 5490 self._curr_model, self._model_v4_path = \ 5491 import_v4.import_model(args[1], self._mgme_dir) 5492 else: 5493 # avoid loading the qcd/qed model twice 5494 if (args[1].startswith('loop_qcd_qed_sm') or\ 5495 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\ 5496 self.options['gauge']!='Feynman': 5497 logger.info('Switching to Feynman gauge because '+\ 5498 'it is the only one supported by the model %s.'%args[1]) 5499 self._curr_model = None 5500 self.do_set('gauge Feynman',log=False) 5501 prefix = not '--noprefix' in args 5502 if prefix: 5503 aloha.aloha_prefix='mdl_' 5504 else: 5505 aloha.aloha_prefix='' 5506 5507 try: 5508 self._curr_model = import_ufo.import_model(args[1], prefix=prefix, 5509 complex_mass_scheme=self.options['complex_mass_scheme']) 5510 except ufomodels.UFOError as err: 5511 model_path, _,_ = import_ufo.get_path_restrict(args[1]) 5512 if six.PY3 and self.options['auto_convert_model']: 5513 logger.info("fail to load model but auto_convert_model is on True. Trying to convert the model") 5514 5515 self.exec_cmd('convert model %s' % model_path, errorhandling=False, printcmd=True, precmd=False, postcmd=False) 5516 logger.info('retry the load of the model') 5517 tmp_opt = dict(self.options) 5518 tmp_opt['auto_convert_model'] = False 5519 with misc.TMP_variable(self, 'options', tmp_opt): 5520 try: 5521 self.exec_cmd('import %s' % line, errorhandling=False, printcmd=True, precmd=False, postcmd=False) 5522 except Exception: 5523 raise err 5524 elif six.PY3: 5525 raise self.InvalidCmd('UFO model not python3 compatible. You can convert it via the command \nconvert model %s\nYou can also type \"set auto_convert_model T\" to automatically convert all python2 module to be python3 compatible in the future.' % model_path) 5526 else: 5527 raise 5528 if os.path.sep in args[1] and "import" in self.history[-1]: 5529 self.history[-1] = 'import model %s' % self._curr_model.get('modelpath+restriction') 5530 5531 if self.options['gauge'] in ['unitary', 'axial']: 5532 if not force and isinstance(self._curr_model,\ 5533 loop_base_objects.LoopModel) and \ 5534 self._curr_model.get('perturbation_couplings') not in \ 5535 [[],['QCD']]: 5536 if 1 not in self._curr_model.get('gauge') : 5537 logger_stderr.warning('This model does not allow Feynman '+\ 5538 'gauge. You will only be able to do tree level '+\ 5539 'QCD loop cmputations with it.') 5540 else: 5541 logger.info('Change to the gauge to Feynman because '+\ 5542 'this loop model allows for more than just tree level'+\ 5543 ' and QCD perturbations.') 5544 self.do_set('gauge Feynman', log=False) 5545 return 5546 if 0 not in self._curr_model.get('gauge') : 5547 logger_stderr.warning('Change the gauge to Feynman since '+\ 5548 'the model does not allow unitary gauge') 5549 self.do_set('gauge Feynman', log=False) 5550 return 5551 else: 5552 if 1 not in self._curr_model.get('gauge') : 5553 logger_stderr.warning('Change the gauge to unitary since the'+\ 5554 ' model does not allow Feynman gauge.'+\ 5555 ' Please re-import the model') 5556 self._curr_model = None 5557 self.do_set('gauge unitary', log= False) 5558 return 5559 5560 if '-modelname' not in args: 5561 self._curr_model.pass_particles_name_in_mg_default() 5562 5563 # Do post-processing of model 5564 self.process_model() 5565 # Reset amplitudes and matrix elements and global checks 5566 self._curr_amps = diagram_generation.AmplitudeList() 5567 # Reset proc defs 5568 self._curr_proc_defs = base_objects.ProcessDefinitionList() 5569 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 5570 process_checks.store_aloha = [] 5571 5572 elif args[0] == 'command': 5573 5574 if not os.path.isfile(args[1]): 5575 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1]) 5576 else: 5577 # Check the status of export and try to use file position if no 5578 #self._export dir are define 5579 self.check_for_export_dir(args[1]) 5580 # Execute the card 5581 self.import_command_file(args[1]) 5582 5583 elif args[0] == 'banner': 5584 type = madevent_interface.MadEventCmd.detect_card_type(args[1]) 5585 if type != 'banner': 5586 raise self.InvalidCmd('The File should be a valid banner') 5587 ban = banner_module.Banner(args[1]) 5588 # Check that this is MG5 banner 5589 if 'mg5proccard' in ban: 5590 for line in ban['mg5proccard'].split('\n'): 5591 if line.startswith('#') or line.startswith('<'): 5592 continue 5593 self.exec_cmd(line) 5594 else: 5595 raise self.InvalidCmd('Only MG5 banner are supported') 5596 5597 if not self._done_export: 5598 self.exec_cmd('output . -f') 5599 5600 ban.split(self._done_export[0]) 5601 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards')) 5602 if '--no_launch' not in args: 5603 self.exec_cmd('launch') 5604 5605 elif args[0] == 'proc_v4': 5606 5607 if len(args) == 1 and self._export_dir: 5608 proc_card = pjoin(self._export_dir, 'Cards', \ 5609 'proc_card.dat') 5610 elif len(args) == 2: 5611 proc_card = args[1] 5612 # Check the status of export and try to use file position is no 5613 # self._export dir are define 5614 self.check_for_export_dir(os.path.realpath(proc_card)) 5615 else: 5616 raise MadGraph5Error('No default directory in output') 5617 5618 5619 #convert and excecute the card 5620 self.import_mg4_proc_card(proc_card)
5621
5622 - def remove_pointless_decay(self, param_card):
5623 """ For simple decay chain: remove diagram that are not in the BR. 5624 param_card should be a ParamCard instance.""" 5625 5626 assert isinstance(param_card, check_param_card.ParamCard) 5627 5628 # Collect amplitudes 5629 amplitudes = diagram_generation.AmplitudeList() 5630 for amp in self._curr_amps: 5631 amplitudes.extend(amp.get_amplitudes()) 5632 5633 decay_tables = param_card['decay'].decay_table 5634 to_remove = [] 5635 for amp in amplitudes: 5636 mother = [l.get('id') for l in amp['process'].get('legs') \ 5637 if not l.get('state')] 5638 if 1 == len(mother): 5639 try: 5640 decay_table = decay_tables[abs(mother[0])] 5641 except KeyError: 5642 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0])) 5643 continue # No BR for this particle -> accept all. 5644 # create the tuple associate to the decay mode 5645 child = [l.get('id') for l in amp['process'].get('legs') \ 5646 if l.get('state')] 5647 if not mother[0] > 0: 5648 child = [x if self._curr_model.get_particle(x)['self_antipart'] 5649 else -x for x in child] 5650 child.sort() 5651 child.insert(0, len(child)) 5652 #check if the decay is present or not: 5653 if tuple(child) not in list(decay_table.keys()): 5654 to_remove.append(amp) 5655 5656 def remove_amp(amps): 5657 for amp in amps[:]: 5658 if amp in to_remove: 5659 amps.remove(amp) 5660 if isinstance(amp, diagram_generation.DecayChainAmplitude): 5661 remove_amp(amp.get('decay_chains')) 5662 for decay in amp.get('decay_chains'): 5663 remove_amp(decay.get('amplitudes'))
5664 remove_amp(self._curr_amps) 5665 5666
5667 - def import_ufo_model(self, model_name):
5668 """ import the UFO model """ 5669 5670 self._curr_model = import_ufo.import_model(model_name)
5671
5672 - def process_model(self):
5673 """Set variables _particle_names and _couplings for tab 5674 completion, define multiparticles""" 5675 5676 # Set variables for autocomplete 5677 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\ 5678 if p.get('propagating')] + \ 5679 [p.get('antiname') for p in self._curr_model.get('particles') \ 5680 if p.get('propagating')] 5681 5682 self._couplings = list(set(sum([list(i.get('orders').keys()) for i in \ 5683 self._curr_model.get('interactions')], []))) 5684 5685 self.add_default_multiparticles()
5686 5687
5688 - def import_mg4_proc_card(self, filepath):
5689 """ read a V4 proc card, convert it and run it in mg5""" 5690 5691 # change the status of this line in the history -> pass in comment 5692 if self.history and self.history[-1].startswith('import proc_v4'): 5693 self.history[-1] = '#%s' % self.history[-1] 5694 5695 # read the proc_card.dat 5696 reader = files.read_from_file(filepath, import_v4.read_proc_card_v4) 5697 if not reader: 5698 raise self.InvalidCmd('\"%s\" is not a valid path' % filepath) 5699 5700 if self._mgme_dir: 5701 # Add comment to history 5702 self.exec_cmd("# Import the model %s" % reader.model, precmd=True) 5703 line = self.exec_cmd('import model_v4 %s -modelname' % \ 5704 (reader.model), precmd=True) 5705 else: 5706 logging.error('No MG_ME installation detected') 5707 return 5708 5709 5710 # Now that we have the model we can split the information 5711 lines = reader.extract_command_lines(self._curr_model) 5712 for line in lines: 5713 self.exec_cmd(line, precmd=True) 5714 5715 return
5716
5717 - def add_default_multiparticles(self):
5718 """ add default particle from file interface.multiparticles_default.txt 5719 """ 5720 5721 defined_multiparticles = list(self._multiparticles.keys()) 5722 removed_multiparticles = [] 5723 # First check if the defined multiparticles are allowed in the 5724 # new model 5725 5726 for key in list(self._multiparticles.keys()): 5727 try: 5728 for part in self._multiparticles[key]: 5729 self._curr_model.get('particle_dict')[part] 5730 except Exception: 5731 del self._multiparticles[key] 5732 defined_multiparticles.remove(key) 5733 removed_multiparticles.append(key) 5734 5735 # Now add default multiparticles 5736 for line in open(pjoin(MG5DIR, 'input', \ 5737 'multiparticles_default.txt')): 5738 if line.startswith('#'): 5739 continue 5740 try: 5741 if not self._curr_model['case_sensitive']: 5742 multipart_name = line.lower().split()[0] 5743 else: 5744 multipart_name = line.split()[0] 5745 if multipart_name not in self._multiparticles: 5746 #self.do_define(line) 5747 self.exec_cmd('define %s' % line, printcmd=False, precmd=True) 5748 except self.InvalidCmd as why: 5749 logger.warning('impossible to set default multiparticles %s because %s' % 5750 (line.split()[0],why)) 5751 if self.history[-1] == 'define %s' % line.strip(): 5752 self.history.pop(-1) 5753 else: 5754 misc.sprint([self.history[-1], 'define %s' % line.strip()]) 5755 5756 scheme = "old" 5757 for qcd_container in ['p', 'j']: 5758 if qcd_container not in self._multiparticles: 5759 continue 5760 multi = self._multiparticles[qcd_container] 5761 b = self._curr_model.get_particle(5) 5762 if not b: 5763 break 5764 5765 if 5 in multi: 5766 if b['mass'] != 'ZERO': 5767 multi.remove(5) 5768 multi.remove(-5) 5769 scheme = 4 5770 elif b['mass'] == 'ZERO': 5771 multi.append(5) 5772 multi.append(-5) 5773 scheme = 5 5774 5775 if scheme in [4,5]: 5776 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme) 5777 for container in ['p', 'j']: 5778 if container in defined_multiparticles: 5779 defined_multiparticles.remove(container) 5780 self.history.append("define p = %s # pass to %s flavors" % \ 5781 (' ' .join([repr(i) for i in self._multiparticles['p']]), 5782 scheme) 5783 ) 5784 self.history.append("define j = p") 5785 5786 5787 if defined_multiparticles: 5788 if 'all' in defined_multiparticles: 5789 defined_multiparticles.remove('all') 5790 logger.info("Kept definitions of multiparticles %s unchanged" % \ 5791 " / ".join(defined_multiparticles)) 5792 5793 for removed_part in removed_multiparticles: 5794 if removed_part in self._multiparticles: 5795 removed_multiparticles.remove(removed_part) 5796 5797 if removed_multiparticles: 5798 logger.info("Removed obsolete multiparticles %s" % \ 5799 " / ".join(removed_multiparticles)) 5800 5801 # add all tag 5802 line = [] 5803 for part in self._curr_model.get('particles'): 5804 line.append('%s %s' % (part.get('name'), part.get('antiname'))) 5805 line = 'all =' + ' '.join(line) 5806 self.do_define(line)
5807
5808 - def advanced_install(self, tool_to_install, 5809 HepToolsInstaller_web_address=None, 5810 additional_options=[]):
5811 """ Uses the HEPToolsInstaller.py script maintened online to install 5812 HEP tools with more complicated dependences. 5813 Additional options will be added to the list when calling HEPInstaller""" 5814 5815 # prevent border effects 5816 add_options = list(additional_options) 5817 5818 # Always refresh the installer if already present 5819 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')): 5820 if HepToolsInstaller_web_address is None: 5821 raise MadGraph5Error("The option 'HepToolsInstaller_web_address'"+\ 5822 " must be specified in function advanced_install"+\ 5823 " if the installers are not already downloaded.") 5824 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')): 5825 os.mkdir(pjoin(MG5DIR,'HEPTools')) 5826 elif not HepToolsInstaller_web_address is None: 5827 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5828 if not HepToolsInstaller_web_address is None: 5829 logger.info('Downloading the HEPToolInstaller at:\n %s'% 5830 HepToolsInstaller_web_address) 5831 # Guess if it is a local or web address 5832 if '//' in HepToolsInstaller_web_address: 5833 misc.wget(HepToolsInstaller_web_address, 5834 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'), 5835 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'), 5836 cwd=MG5DIR) 5837 else: 5838 # If it is a local tarball, then just copy it 5839 shutil.copyfile(HepToolsInstaller_web_address, 5840 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5841 5842 # Untar the file 5843 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'], 5844 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w')) 5845 5846 # Remove the tarball 5847 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5848 5849 5850 # FOR DEBUGGING ONLY, Take HEPToolsInstaller locally 5851 if '--local' in add_options: 5852 add_options.remove('--local') 5853 logger.warning('you are using a local installer. This is intended for debugging only!') 5854 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5855 shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir, 5856 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5857 5858 # Potential change in naming convention 5859 name_map = {'lhapdf6_py3': 'lhapdf6'} 5860 try: 5861 tool = name_map[tool_to_install] 5862 except: 5863 tool = tool_to_install 5864 5865 # Compiler options 5866 compiler_options = [] 5867 if self.options['cpp_compiler'] is not None: 5868 compiler_options.append('--cpp_compiler=%s'% 5869 self.options['cpp_compiler']) 5870 compiler_options.append('--cpp_standard_lib=%s'% 5871 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler'])) 5872 elif misc.which('g++'): 5873 compiler_options.append('--cpp_standard_lib=%s'% 5874 misc.detect_cpp_std_lib_dependence('g++')) 5875 else: 5876 compiler_options.append('--cpp_standard_lib=%s'% 5877 misc.detect_cpp_std_lib_dependence(None)) 5878 5879 if not self.options['fortran_compiler'] is None: 5880 compiler_options.append('--fortran_compiler=%s'% 5881 self.options['fortran_compiler']) 5882 5883 if 'heptools_install_dir' in self.options: 5884 prefix = self.options['heptools_install_dir'] 5885 config_file = '~/.mg5/mg5_configuration.txt' 5886 else: 5887 prefix = pjoin(MG5DIR, 'HEPTools') 5888 config_file = '' 5889 5890 # Add the path of pythia8 if known and the MG5 path 5891 if tool=='mg5amc_py8_interface': 5892 #add_options.append('--mg5_path=%s'%MG5DIR) 5893 # Warn about the soft dependency to gnuplot 5894 if misc.which('gnuplot') is None: 5895 logger.warning("==========") 5896 logger.warning("The optional dependency 'gnuplot' for the tool"+\ 5897 " 'mg5amc_py8_interface' was not found. We recommend that you"+\ 5898 " install it so as to be able to view the plots related to "+\ 5899 " merging with Pythia 8.") 5900 logger.warning("==========") 5901 if self.options['pythia8_path']: 5902 add_options.append( 5903 '--with_pythia8=%s'%self.options['pythia8_path']) 5904 5905 # Special rules for certain tools 5906 if tool=='madanalysis5': 5907 add_options.append('--mg5_path=%s'%MG5DIR) 5908 if not any(opt.startswith(('--with_fastjet', '--veto_fastjet')) for opt in add_options): 5909 fastjet_config = misc.which(self.options['fastjet']) 5910 if fastjet_config: 5911 add_options.append('--with_fastjet=%s'%fastjet_config) 5912 5913 if self.options['delphes_path'] and os.path.isdir( 5914 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))): 5915 add_options.append('--with_delphes3=%s'%\ 5916 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))) 5917 5918 if tool=='pythia8': 5919 # All what's below is to handle the lhapdf dependency of Pythia8 5920 lhapdf_config = misc.which(self.options['lhapdf']) 5921 lhapdf_version = None 5922 if lhapdf_config is None: 5923 lhapdf_version = None 5924 else: 5925 try: 5926 version = misc.Popen( 5927 [lhapdf_config,'--version'], stdout=subprocess.PIPE) 5928 lhapdf_version = int(version.stdout.read().decode()[0]) 5929 if lhapdf_version not in [5,6]: 5930 raise 5931 except: 5932 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+ 5933 " sure '%s --version ' runs properly."%lhapdf_config) 5934 5935 if lhapdf_version is None: 5936 answer = self.ask(question= 5937 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+ 5938 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >", 5939 default='y',text_format='33;32') 5940 if not answer.lower() in ['y','']: 5941 lhapdf_path = None 5942 else: 5943 self.advanced_install('lhapdf6', 5944 additional_options=add_options) 5945 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6') 5946 lhapdf_version = 6 5947 else: 5948 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\ 5949 lhapdf_config),os.path.pardir)) 5950 if lhapdf_version is None: 5951 logger.warning('You decided not to link the Pythia8 installation'+ 5952 ' to LHAPDF. Beware that only built-in PDF sets can be used then.') 5953 else: 5954 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version) 5955 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN') 5956 lhapdf_option = [] 5957 if lhapdf_version is None: 5958 lhapdf_option.append('--with_lhapdf6=OFF') 5959 lhapdf_option.append('--with_lhapdf5=OFF') 5960 elif lhapdf_version==5: 5961 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path) 5962 lhapdf_option.append('--with_lhapdf6=OFF') 5963 elif lhapdf_version==6: 5964 lhapdf_option.append('--with_lhapdf5=OFF') 5965 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path) 5966 # Make sure each otion in add_options appears only once 5967 add_options = list(set(add_options)) 5968 # And that the option '--force' is placed last. 5969 add_options = [opt for opt in add_options if opt!='--force']+\ 5970 (['--force'] if '--force' in add_options else []) 5971 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5972 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8', 5973 '--prefix=%s' % prefix] 5974 + lhapdf_option + compiler_options + add_options) 5975 else: 5976 logger.info('Now installing %s. Be patient...'%tool) 5977 # Make sure each otion in add_options appears only once 5978 add_options.append('--mg5_path=%s'%MG5DIR) 5979 add_options = list(set(add_options)) 5980 add_options.append('--mg5_path=%s'%MG5DIR) 5981 # And that the option '--force' is placed last. 5982 add_options = [opt for opt in add_options if opt!='--force']+\ 5983 (['--force'] if '--force' in add_options else []) 5984 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5985 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'% 5986 prefix] + compiler_options + add_options) 5987 5988 if return_code == 0: 5989 logger.info("%s successfully installed in %s."%( 5990 tool_to_install, prefix),'$MG:color:GREEN') 5991 5992 if tool=='madanalysis5': 5993 if not any(o.startswith(('--with_','--veto_','--update')) for o in add_options): 5994 logger.info(' To install recasting capabilities of madanalysis5 and/or', '$MG:BOLD') 5995 logger.info(' to allow delphes analysis at parton level.','$MG:BOLD') 5996 logger.info(' Please run \'install MadAnalysis5 --with_delphes --update\':', '$MG:BOLD') 5997 5998 elif return_code == 66: 5999 answer = self.ask(question= 6000 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, prefix)+ 6001 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >""" 6002 ,default='y',text_format='33;32') 6003 if not answer.lower() in ['y','']: 6004 logger.info("Installation of %s aborted."%tool_to_install, 6005 '$MG:color:GREEN') 6006 return 6007 else: 6008 return self.advanced_install(tool_to_install, 6009 additional_options=add_options+['--force']) 6010 else: 6011 if tool=='madanalysis5' and '--update' not in add_options and \ 6012 ('--no_MA5_further_install' not in add_options or 6013 '--no_root_in_MA5' in add_options): 6014 if not __debug__: 6015 logger.warning('Default installation of Madanalys5 failed.') 6016 logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.") 6017 logger.warning("This will however limit MA5 applicability for hadron-level analysis.") 6018 logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.") 6019 for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']: 6020 if option not in add_options: 6021 add_options.append(option) 6022 self.advanced_install('madanalysis5', 6023 HepToolsInstaller_web_address=HepToolsInstaller_web_address, 6024 additional_options=add_options) 6025 else: 6026 logger.critical("Default installation of Madanalys5 failed, we suggest you try again with the options '--no_MA5_further_install --no_root_in_MA5'.") 6027 raise self.InvalidCmd("Installation of %s failed."%tool_to_install) 6028 6029 # Post-installation treatment 6030 if tool == 'pythia8': 6031 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 6032 self.exec_cmd('save options %s pythia8_path' % config_file, printcmd=False, log=False) 6033 # Automatically re-install the mg5amc_py8_interface after a fresh 6034 # Pythia8 installation 6035 self.advanced_install('mg5amc_py8_interface', 6036 additional_options=add_options+['--force']) 6037 elif tool == 'lhapdf6': 6038 if six.PY3: 6039 self.options['lhapdf_py3'] = pjoin(prefix,'lhapdf6_py3','bin', 'lhapdf-config') 6040 self.exec_cmd('save options %s lhapdf_py3' % config_file) 6041 self.options['lhapdf'] = self.options['lhapdf_py3'] 6042 else: 6043 self.options['lhapdf_py2'] = pjoin(prefix,'lhapdf6','bin', 'lhapdf-config') 6044 self.exec_cmd('save options %s lhapdf_py2' % config_file) 6045 self.options['lhapdf'] = self.options['lhapdf_py2'] 6046 elif tool == 'lhapdf5': 6047 self.options['lhapdf'] = pjoin(prefix,'lhapdf5','bin', 'lhapdf-config') 6048 self.exec_cmd('save options %s lhapdf' % config_file, printcmd=False, log=False) 6049 elif tool == 'madanalysis5': 6050 self.options['madanalysis5_path'] = pjoin(prefix, 'madanalysis5','madanalysis5') 6051 self.exec_cmd('save options madanalysis5_path', printcmd=False, log=False) 6052 elif tool == 'mg5amc_py8_interface': 6053 # At this stage, pythia is guaranteed to be installed 6054 if self.options['pythia8_path'] in ['',None,'None']: 6055 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 6056 self.options['mg5amc_py8_interface_path'] = pjoin(prefix, 'MG5aMC_PY8_interface') 6057 self.exec_cmd('save options %s mg5amc_py8_interface_path' % config_file, 6058 printcmd=False, log=False) 6059 elif tool == 'collier': 6060 self.options['collier'] = pjoin(prefix,'lib') 6061 self.exec_cmd('save options %s collier' % config_file, printcmd=False, log=False) 6062 elif tool == 'ninja': 6063 if not misc.get_ninja_quad_prec_support(pjoin( 6064 prefix,'ninja','lib')): 6065 logger.warning( 6066 """Successful installation of Ninja, but without support for quadruple precision 6067 arithmetics. If you want to enable this (hence improving the treatment of numerically 6068 unstable points in the loop matrix elements) you can try to reinstall Ninja with: 6069 MG5aMC>install ninja 6070 After having made sure to have selected a C++ compiler in the 'cpp' option of 6071 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""") 6072 self.options['ninja'] = pjoin(prefix,'lib') 6073 self.exec_cmd('save options %s ninja' % config_file, printcmd=False, log=False) 6074 elif '%s_path' % tool in self.options: 6075 self.options['%s_path' % tool] = pjoin(prefix, tool) 6076 self.exec_cmd('save options %s %s_path' % (config_file,tool), printcmd=False, log=False) 6077 6078 # Now warn the user if he didn't add HEPTools first in his environment 6079 # variables. 6080 path_to_be_set = [] 6081 if sys.platform == "darwin": 6082 library_variables = ["DYLD_LIBRARY_PATH"] 6083 else: 6084 library_variables = ["LD_LIBRARY_PATH"] 6085 for variable in library_variables: 6086 if (variable not in os.environ) or \ 6087 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\ 6088 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6089 path_to_be_set.append((variable, 6090 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib')))) 6091 for variable in ["PATH"]: 6092 if (variable not in os.environ) or \ 6093 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\ 6094 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6095 path_to_be_set.append((variable, 6096 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin')))) 6097 if (variable not in os.environ) or \ 6098 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\ 6099 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6100 path_to_be_set.append((variable, 6101 os.path.abspath(pjoin(MG5DIR,'HEPTools','include')))) 6102 6103 if len(path_to_be_set)>0: 6104 shell_type = misc.get_shell_type() 6105 if shell_type in ['bash',None]: 6106 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.bashrc"%\ 6107 (r'\n'.join('export %s=%s%s'% 6108 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 6109 elif shell_type=='tcsh': 6110 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.cshrc"%\ 6111 (r'\n'.join('setenv %s %s%s'% 6112 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 6113 6114 logger.debug("==========") 6115 logger.debug("We recommend that you add to the following paths"+\ 6116 " to your environment variables, so that you are guaranteed that"+\ 6117 " at runtime, MG5_aMC will use the tools you have just installed"+\ 6118 " and not some other versions installed elsewhere on your system.\n"+\ 6119 "You can do so by running the following command in your terminal:" 6120 "\n %s"%modification_line) 6121 logger.debug("==========") 6122 6123 # Return true for successful installation 6124 return True
6125 6126 install_plugin = ['maddm', 'maddump', 'MadSTR'] 6127 install_ad = {'pythia-pgs':['arXiv:0603175'], 6128 'Delphes':['arXiv:1307.6346'], 6129 'Delphes2':['arXiv:0903.2225'], 6130 'SysCalc':['arXiv:1801.08401'], 6131 'Golem95':['arXiv:0807.0605'], 6132 'QCDLoop':['arXiv:0712.1851'], 6133 'pythia8':['arXiv:1410.3012'], 6134 'lhapdf6':['arXiv:1412.7420'], 6135 'lhapdf5':['arXiv:0605240'], 6136 'hepmc':['CPC 134 (2001) 41-46'], 6137 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'], 6138 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'], 6139 'MadAnalysis5':['arXiv:1206.1599'], 6140 'MadAnalysis':['arXiv:1206.1599'], 6141 'collier':['arXiv:1604.06792'], 6142 'oneloop':['arXiv:1007.4716'], 6143 'maddm':['arXiv:1804.00444'], 6144 'maddump':['arXiv:1812.06771'], 6145 'MadSTR':['arXiv:1612.00440']} 6146 6147 install_server = ['http://madgraph.phys.ucl.ac.be/package_info.dat', 6148 'http://madgraph.physics.illinois.edu/package_info.dat'] 6149 install_name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes', 6150 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs', 6151 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'madanalysis5', 6152 'MadAnalysis4':'MadAnalysis', 6153 'SysCalc':'SysCalc', 'Golem95': 'golem95', 6154 'lhapdf6' : 'lhapdf6' if six.PY2 else 'lhapdf6_py3', 6155 'QCDLoop':'QCDLoop','MadAnalysis5':'madanalysis5', 6156 'maddm':'maddm' 6157 } 6158
6159 - def do_install(self, line, paths=None, additional_options=[]):
6160 """Install optional package from the MG suite. 6161 The argument 'additional_options' will be passed to the advanced_install 6162 functions. If it contains the option '--force', then the advanced_install 6163 function will overwrite any existing installation of the tool without 6164 warnings. 6165 """ 6166 6167 # Make sure to avoid any border effect on custom_additional_options 6168 add_options = list(additional_options) 6169 6170 args = self.split_arg(line) 6171 #check the validity of the arguments 6172 install_options = self.check_install(args) 6173 6174 if sys.platform == "darwin": 6175 program = "curl" 6176 else: 6177 program = "wget" 6178 6179 # special command for auto-update 6180 if args[0] == 'update': 6181 self.install_update(['update']+install_options['update_options'],wget=program) 6182 return 6183 elif args[0] == 'looptools': 6184 self.install_reduction_library(force=True) 6185 return 6186 6187 6188 plugin = self.install_plugin 6189 6190 advertisements = self.install_ad 6191 6192 6193 if args[0] in advertisements: 6194 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6195 # logger.info('{:^80}'.format("You are installing '%s', please cite ref(s):"%args[0]), '$MG:BOLD') 6196 # logger.info('{:^80}'.format(', '.join(advertisements[args[0]])), '$MG:color:GREEN') 6197 # logger.info('{:^80}'.format("when using results produced with this tool."), '$MG:BOLD') 6198 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6199 logger.info(" You are installing '%s', please cite ref(s): \033[92m%s\033[0m. " % (args[0], ', '.join(advertisements[args[0]])), '$MG:BOLD') 6200 6201 source = None 6202 # Load file with path of the different program: 6203 import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error 6204 if paths: 6205 path = paths 6206 else: 6207 path = {} 6208 6209 data_path = self.install_server 6210 6211 # Force here to choose one particular server 6212 if any(a.startswith('--source=') for a in args): 6213 source = [a[9:] for a in args if a.startswith('--source=')][-1] 6214 if source == 'uiuc': 6215 r = [1] 6216 elif source == 'ucl': 6217 r = [0] 6218 else: 6219 if source[-1].isdigit() or source[-1] == '/': 6220 source += '/package_info.dat' 6221 data_path.append(source) 6222 r = [2] 6223 else: 6224 r = random.randint(0,1) 6225 r = [r, (1-r)] 6226 if 'MG5aMC_WWW' in os.environ and os.environ['MG5aMC_WWW']: 6227 data_path.append(os.environ['MG5aMC_WWW']+'/package_info.dat') 6228 r.insert(0, 2) 6229 6230 6231 6232 for index in r: 6233 cluster_path = data_path[index] 6234 try: 6235 data = six.moves.urllib.request.urlopen(cluster_path) 6236 except Exception as error: 6237 misc.sprint(str(error), cluster_path) 6238 continue 6239 if data.getcode() != 200: 6240 continue 6241 6242 break 6243 6244 else: 6245 raise MadGraph5Error('''Impossible to connect any of us servers. 6246 Please check your internet connection or retry later''') 6247 for wwwline in data: 6248 split = wwwline.decode().split() 6249 if len(split)!=2: 6250 if '--source' not in line: 6251 source = {0:'uiuc',1:'ucl'}[index] 6252 return self.do_install(line+' --source='+source, paths=paths, additional_options=additional_options) 6253 path[split[0]] = split[1] 6254 6255 ################################################################################ 6256 # TEMPORARY HACK WHERE WE ADD ENTRIES TO WHAT WILL BE EVENTUALLY ON THE WEB 6257 ################################################################################ 6258 # path['XXX'] = 'YYY' 6259 ################################################################################ 6260 6261 if args[0] == 'Delphes': 6262 args[0] = 'Delphes3' 6263 6264 6265 try: 6266 name = self.install_name 6267 name = name[args[0]] 6268 except KeyError: 6269 name = args[0] 6270 if args[0] == 'MadAnalysis4': 6271 args[0] = 'MadAnalysis' 6272 elif args[0] in ['madstr', 'madSTR']: 6273 args[0] = 'MadSTR' 6274 name = 'MadSTR' 6275 6276 if args[0] in self._advanced_install_opts: 6277 # Now launch the advanced installation of the tool args[0] 6278 # path['HEPToolsInstaller'] is the online adress where to downlaod 6279 # the installers if necessary. 6280 # Specify the path of the MG5_aMC_interface 6281 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \ 6282 'MG5aMC_PY8_interface' in path else 'NA' 6283 add_options.append('--mg5amc_py8_interface_tarball=%s'%\ 6284 MG5aMC_PY8_interface_path) 6285 add_options.extend(install_options['options_for_HEPToolsInstaller']) 6286 if not any(opt.startswith('--logging=') for opt in add_options): 6287 add_options.append('--logging=%d' % logger.level) 6288 6289 6290 return self.advanced_install(name, path['HEPToolsInstaller'], 6291 additional_options = add_options) 6292 6293 6294 if args[0] == 'Delphes': 6295 args[0] = 'Delphes3' 6296 6297 6298 #check outdated install 6299 substitution={'Delphes2':'Delphes','pythia-pgs':'pythia8'} 6300 if args[0] in substitution: 6301 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\ 6302 " You should consider installing and using %s, with:\n"%substitution[args[0]]+ 6303 " > install %s"%substitution[args[0]]) 6304 6305 try: 6306 os.system('rm -rf %s' % pjoin(MG5DIR, name)) 6307 except Exception: 6308 pass 6309 6310 if args[0] not in path: 6311 if not source: 6312 if index ==1: 6313 othersource = 'ucl' 6314 else: 6315 othersource = 'uiuc' 6316 # try with the mirror 6317 misc.sprint('try other mirror', othersource, ' '.join(args)) 6318 return self.do_install('%s --source=%s' % (' '.join(args), othersource), 6319 paths, additional_options) 6320 else: 6321 if 'xxx' in advertisements[name][0]: 6322 logger.warning("Program not yet released. Please try later") 6323 else: 6324 raise Exception("Online server are corrupted. No tarball available for %s" % name) 6325 return 6326 6327 # Load that path 6328 logger.info('Downloading %s' % path[args[0]]) 6329 misc.wget(path[args[0]], '%s.tgz' % name, cwd=MG5DIR) 6330 6331 # Untar the file 6332 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6333 stdout=open(os.devnull, 'w')) 6334 6335 if returncode: 6336 raise MadGraph5Error('Fail to download correctly the File. Stop') 6337 6338 6339 # Check that the directory has the correct name 6340 if not os.path.exists(pjoin(MG5DIR, name)): 6341 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith( 6342 name.lower()) and not n.endswith('gz')] 6343 if not created_name: 6344 raise MadGraph5Error('The file was not loaded correctly. Stop') 6345 else: 6346 created_name = created_name[0] 6347 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name)) 6348 6349 if hasattr(self, 'post_install_%s' %name): 6350 return getattr(self, 'post_install_%s' %name)() 6351 6352 logger.info('compile %s. This might take a while.' % name) 6353 6354 # Modify Makefile for pythia-pgs on Mac 64 bit 6355 if args[0] == "pythia-pgs" and sys.maxsize > 2**32: 6356 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 6357 text = open(path).read() 6358 text = text.replace('MBITS=32','MBITS=64') 6359 open(path, 'w').writelines(text) 6360 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')): 6361 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')) 6362 6363 make_flags = [] #flags for the compilation 6364 # Compile the file 6365 # Check for F77 compiler 6366 if 'FC' not in os.environ or not os.environ['FC']: 6367 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None': 6368 compiler = self.options['fortran_compiler'] 6369 elif misc.which('gfortran'): 6370 compiler = 'gfortran' 6371 elif misc.which('g77'): 6372 compiler = 'g77' 6373 else: 6374 raise self.InvalidCmd('Require g77 or Gfortran compiler') 6375 6376 path = None 6377 base_compiler= ['FC=g77','FC=gfortran'] 6378 if args[0] == "pythia-pgs": 6379 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 6380 elif args[0] == 'MadAnalysis': 6381 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile') 6382 if path: 6383 text = open(path).read() 6384 for base in base_compiler: 6385 text = text.replace(base,'FC=%s' % compiler) 6386 open(path, 'w').writelines(text) 6387 os.environ['FC'] = compiler 6388 6389 # For Golem95, use autotools. 6390 if name == 'golem95': 6391 # Run the configure script 6392 ld_path = misc.Popen(['./configure', 6393 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']], 6394 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0].decode() 6395 6396 6397 # For QCDLoop, use autotools. 6398 if name == 'QCDLoop': 6399 # Run the configure script 6400 ld_path = misc.Popen(['./configure', 6401 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'], 6402 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 6403 stdout=subprocess.PIPE).communicate()[0].decode() 6404 6405 # For Delphes edit the makefile to add the proper link to correct library 6406 if args[0] == 'Delphes3': 6407 #change in the makefile 6408 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) 6409 # to 6410 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,/Applications/root_v6.04.08/lib/ 6411 rootsys = os.environ['ROOTSYS'] 6412 text = open(pjoin(MG5DIR, 'Delphes','Makefile')).read() 6413 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)', 6414 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys) 6415 open(pjoin(MG5DIR, 'Delphes','Makefile'),'w').write(text) 6416 6417 # For SysCalc link to lhapdf 6418 if name == 'SysCalc': 6419 if self.options['lhapdf']: 6420 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'], 6421 stdout=subprocess.PIPE).communicate()[0].decode() 6422 ld_path = ld_path.replace('\n','') 6423 if 'LD_LIBRARY_PATH' not in os.environ: 6424 os.environ['LD_LIBRARY_PATH'] = ld_path 6425 elif not os.environ['LD_LIBRARY_PATH']: 6426 os.environ['LD_LIBRARY_PATH'] = ld_path 6427 elif ld_path not in os.environ['LD_LIBRARY_PATH']: 6428 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path 6429 if self.options['lhapdf'] != 'lhapdf-config': 6430 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']): 6431 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH']) 6432 else: 6433 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6') 6434 if self.options['cpp_compiler']: 6435 make_flags.append('CXX=%s' % self.options['cpp_compiler']) 6436 6437 6438 if name in plugin: 6439 logger.info('no compilation needed for plugin. Loading plugin information') 6440 try: 6441 shutil.rmtree(pjoin(MG5DIR, 'PLUGIN', name)) 6442 except Exception: 6443 pass 6444 shutil.move(pjoin(os.path.join(MG5DIR, name)), os.path.join(MG5DIR, 'PLUGIN', name)) 6445 # read the __init__.py to check if we need to add a new executable 6446 pyvers=sys.version[0] 6447 try: 6448 __import__('PLUGIN.%s' % name, globals(), locals(), [], -1) 6449 plugin = sys.modules['PLUGIN.%s' % name] 6450 new_interface = plugin.new_interface 6451 new_output = plugin.new_output 6452 latest_validated_version = plugin.latest_validated_version 6453 minimal_mg5amcnlo_version = plugin.minimal_mg5amcnlo_version 6454 maximal_mg5amcnlo_version = plugin.maximal_mg5amcnlo_version 6455 except Exception as error: 6456 if six.PY2: 6457 raise Exception('Plugin %s fail to be loaded. Please contact the author of the PLUGIN\n Error %s' % (name, error)) 6458 elif six.PY3: 6459 logger.warning('Plugin not python3 compatible! It will run with python2') 6460 text = open(os.path.join(MG5DIR, 'PLUGIN', name, '__init__.py')).read() 6461 if re.search('^\s*new_interface\s*=\s*(?!None).', text, re.M): 6462 new_interface = True 6463 pyvers = 2 6464 else: 6465 misc.sprint(text) 6466 new_output = [] 6467 latest_validated_version = '' 6468 minimal_mg5amcnlo_version = '' 6469 maximal_mg5amcnlo_version = '' 6470 misc.sprint(pyvers) 6471 6472 logger.info('Plugin %s correctly interfaced. Latest official validition for MG5aMC version %s.' % (name, '.'.join(repr(i) for i in latest_validated_version))) 6473 if new_interface: 6474 ff = open(pjoin(MG5DIR, 'bin', '%s.py' % name) , 'w') 6475 if __debug__: 6476 text = '''#! /usr/bin/env python{1} 6477 import os 6478 import sys 6479 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 6480 exe_path = os.path.join(root_path,'bin','mg5_aMC') 6481 sys.argv.pop(0) 6482 os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 6483 '''.format(name,'' if pyvers == 2 else pyvers) 6484 else: 6485 text = '''#! /usr/bin/env python{1} 6486 import os 6487 import sys 6488 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 6489 exe_path = os.path.join(root_path,'bin','mg5_aMC') 6490 sys.argv.pop(0) 6491 os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 6492 '''.format(name,'' if pyvers == 2 else pyvers) 6493 ff.write(text) 6494 ff.close() 6495 import stat 6496 os.chmod(pjoin(MG5DIR, 'bin', '%s.py' % name), stat.S_IRWXU) 6497 logger.info('To use this module, you need to quit MG5aMC and run the executable bin/%s.py' % name) 6498 status=0 6499 6500 elif logger.level <= logging.INFO: 6501 devnull = open(os.devnull,'w') 6502 try: 6503 misc.call(['make', 'clean'], stdout=devnull, stderr=-2) 6504 except Exception: 6505 pass 6506 if name == 'pythia-pgs': 6507 #SLC6 needs to have this first (don't ask why) 6508 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6509 if name in ['golem95','QCDLoop']: 6510 status = misc.call(['make','install'], 6511 cwd = os.path.join(MG5DIR, name)) 6512 else: 6513 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name)) 6514 devnull.close() 6515 else: 6516 try: 6517 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6518 except Exception: 6519 pass 6520 if name == 'pythia-pgs': 6521 #SLC6 needs to have this first (don't ask why) 6522 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6523 if name in ['golem95','QCDLoop']: 6524 status = misc.compile(['install'], mode='', 6525 cwd = os.path.join(MG5DIR, name)) 6526 else: 6527 status = self.compile(make_flags, mode='', 6528 cwd = os.path.join(MG5DIR, name)) 6529 6530 if not status: 6531 logger.info('Installation succeeded') 6532 else: 6533 # For pythia-pgs check when removing the "-fno-second-underscore" flag 6534 if name == 'pythia-pgs': 6535 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio', 6536 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch'] 6537 for f in to_comment: 6538 f = pjoin(MG5DIR, name, *f.split('/')) 6539 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l) 6540 fsock = open(f,'w').write(text) 6541 try: 6542 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6543 except Exception: 6544 pass 6545 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name)) 6546 if not status: 6547 logger.info('Compilation succeeded') 6548 else: 6549 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.') 6550 6551 6552 # Special treatment for TD/Ghostscript program (require by MadAnalysis) 6553 if args[0] == 'MadAnalysis': 6554 try: 6555 os.system('rm -rf td') 6556 os.mkdir(pjoin(MG5DIR, 'td')) 6557 except Exception as error: 6558 print(error) 6559 pass 6560 6561 if sys.platform == "darwin": 6562 logger.info('Downloading TD for Mac') 6563 target = 'https://home.fnal.gov/~parke/TD/td_mac_intel64.tar.gz' 6564 misc.wget(target, 'td.tgz', cwd=pjoin(MG5DIR,'td')) 6565 misc.call(['tar', '-xzpvf', 'td.tgz'], 6566 cwd=pjoin(MG5DIR,'td')) 6567 files.mv(MG5DIR + '/td/td_intel_mac64',MG5DIR+'/td/td') 6568 else: 6569 if sys.maxsize > 2**32: 6570 logger.info('Downloading TD for Linux 64 bit') 6571 target = 'https://home.fnal.gov/~parke/TD/td_linux_64bit.tar.gz' 6572 #logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer. 6573 #In 99% of the case, this is perfectly fine. If you do not have plot, please follow 6574 #instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''') 6575 else: 6576 logger.info('Downloading TD for Linux 32 bit') 6577 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td' 6578 misc.wget(target, 'td', cwd=pjoin(MG5DIR,'td')) 6579 os.chmod(pjoin(MG5DIR,'td','td'), 0o775) 6580 self.options['td_path'] = pjoin(MG5DIR,'td') 6581 6582 if not misc.which('gs'): 6583 logger.warning('''gosthscript not install on your system. This is not required to run MA. 6584 but this prevent to create jpg files and therefore to have the plots in the html output.''') 6585 if sys.platform == "darwin": 6586 logger.warning('''You can download this program at the following link: 6587 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''') 6588 6589 if args[0] == 'Delphes2': 6590 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read() 6591 data = data.replace('data/', 'DELPHESDIR/data/') 6592 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w') 6593 out.write(data) 6594 if args[0] == 'Delphes3': 6595 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')): 6596 card_dir = pjoin(MG5DIR, 'Delphes','cards') 6597 else: 6598 card_dir = pjoin(MG5DIR, 'Delphes','examples') 6599 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6600 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat')) 6601 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6602 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat')) 6603 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'), 6604 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat')) 6605 6606 if not self.options['pythia-pgs_path'] and not self.options['pythia8_path']: 6607 logger.warning("We noticed that no parton-shower module are installed/linked. \n In order to use Delphes from MG5aMC please install/link pythia8.") 6608 6609 #reset the position of the executable 6610 options_name = {'Delphes': 'delphes_path', 6611 'Delphes2': 'delphes_path', 6612 'Delphes3': 'delphes_path', 6613 'ExRootAnalysis': 'exrootanalysis_path', 6614 'MadAnalysis': 'madanalysis_path', 6615 'SysCalc': 'syscalc_path', 6616 'pythia-pgs':'pythia-pgs_path', 6617 'Golem95': 'golem'} 6618 6619 if args[0] in options_name: 6620 opt = options_name[args[0]] 6621 if opt=='golem': 6622 self.options[opt] = pjoin(MG5DIR,name,'lib') 6623 self.exec_cmd('save options %s' % opt, printcmd=False) 6624 elif self.options[opt] != self.options_configuration[opt]: 6625 self.options[opt] = self.options_configuration[opt] 6626 self.exec_cmd('save options %s' % opt, printcmd=False)
6627 6628 6629
6630 - def install_update(self, args, wget):
6631 """ check if the current version of mg5 is up-to-date. 6632 and allow user to install the latest version of MG5 """ 6633 6634 def apply_patch(filetext): 6635 """function to apply the patch""" 6636 text = filetext.read().decode() 6637 6638 pattern = re.compile(r'''^=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6639 #= = = renamed directory 'Template' => 'Template/LO' 6640 for orig, new in pattern.findall(text): 6641 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP')) 6642 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6643 for i, name in enumerate(full_path): 6644 path = os.path.sep.join(full_path[:i+1]) 6645 if path and not os.path.isdir(path): 6646 os.mkdir(path) 6647 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new)) 6648 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP')) 6649 # track rename since patch fail to apply those correctly. 6650 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6651 #=== renamed file 'Template/SubProcesses/addmothers.f' => 'madgraph/iolibs/template_files/addmothers.f' 6652 for orig, new in pattern.findall(text): 6653 print('move %s to %s' % (orig, new)) 6654 try: 6655 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6656 except IOError: 6657 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6658 for i, name in enumerate(full_path): 6659 path = os.path.sep.join(full_path[:i+1]) 6660 if path and not os.path.isdir(path): 6661 os.mkdir(path) 6662 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6663 # track remove/re-added file: 6664 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M) 6665 all_add = pattern.findall(text) 6666 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6667 #all_rm = pattern.findall(text) 6668 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S) 6669 print('this step can take a few minuts. please be patient') 6670 all_rm_add = pattern.findall(text) 6671 #=== added file 'tests/input_files/full_sm/interactions.dat' 6672 for new in all_add: 6673 if new in all_rm_add: 6674 continue 6675 if os.path.isfile(pjoin(MG5DIR, new)): 6676 os.remove(pjoin(MG5DIR, new)) 6677 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6678 #=== removed file 'tests/input_files/full_sm/interactions.dat' 6679 #for old in pattern.findall(text): 6680 # if not os.path.isfile(pjoin(MG5DIR, old)): 6681 # full_path = os.path.dirname(pjoin(MG5DIR, old)).split('/') 6682 # for i, _ in enumerate(full_path): 6683 # path = os.path.sep.join(full_path[:i+1]) 6684 # if path and not os.path.isdir(path): 6685 # os.mkdir(path) 6686 # subprocess.call(['touch', pjoin(MG5DIR, old)]) 6687 6688 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE, 6689 cwd=MG5DIR) 6690 p.communicate(text.encode()) 6691 6692 # check file which are not move 6693 #=== modified file 'Template/LO/Cards/run_card.dat' 6694 #--- old/Template/Cards/run_card.dat 2012-12-06 10:01:04 +0000 6695 #+++ new/Template/LO/Cards/run_card.dat 2013-12-09 02:35:59 +0000 6696 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6697 for match in pattern.findall(text): 6698 new = pjoin(MG5DIR, match[0]) 6699 old = pjoin(MG5DIR, match[1]) 6700 if new == old: 6701 continue 6702 elif os.path.exists(old): 6703 if not os.path.exists(os.path.dirname(new)): 6704 split = new.split('/') 6705 for i in range(1,len(split)): 6706 path = '/'.join(split[:i]) 6707 if not os.path.exists(path): 6708 print('mkdir', path) 6709 os.mkdir(path) 6710 files.cp(old,new) 6711 #=== renamed file 'Template/bin/internal/run_delphes' => 'Template/Common/bin/internal/run_delphes' 6712 #--- old/Template/bin/internal/run_delphes 2011-12-09 07:28:10 +0000 6713 #+++ new/Template/Common/bin/internal/run_delphes 2012-10-23 02:41:37 +0000 6714 #pattern=re.compile('''=== renamed file \'(?P<old>[^\']*)\' => \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P=old)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6715 #for match in pattern.findall(text): 6716 # old = pjoin(MG5DIR, match[0]) 6717 # new = pjoin(MG5DIR, match[1]) 6718 # if new == old: 6719 # continue 6720 # elif os.path.exists(old): 6721 # if not os.path.exists(os.path.dirname(new)): 6722 # split = new.split('/') 6723 # for i in range(1,len(split)): 6724 # path = '/'.join(split[:i]) 6725 # if not os.path.exists(path): 6726 # print 'mkdir', path 6727 # os.mkdir(path) 6728 # files.cp(old,new) 6729 6730 # check that all files in bin directory are executable 6731 for path in misc.glob('*', pjoin(MG5DIR, 'bin')): 6732 misc.call(['chmod', '+x', path]) 6733 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')): 6734 misc.call(['chmod', '+x', path]) 6735 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')): 6736 misc.call(['chmod', '+x', path]) 6737 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')): 6738 misc.call(['chmod', '+x', path]) 6739 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')): 6740 misc.call(['chmod', '+x', path]) 6741 6742 #add empty files/directory 6743 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M) 6744 for match in pattern.findall(text): 6745 if match[0] == 'file': 6746 new = os.path.dirname(pjoin(MG5DIR, match[1])) 6747 else: 6748 new = pjoin(MG5DIR, match[1]) 6749 if not os.path.exists(new): 6750 split = new.split('/') 6751 for i in range(1,len(split)+1): 6752 path = '/'.join(split[:i]) 6753 if path and not os.path.exists(path): 6754 print('mkdir', path) 6755 os.mkdir(path) 6756 if match[0] == 'file': 6757 print('touch ', pjoin(MG5DIR, match[1])) 6758 misc.call(['touch', pjoin(MG5DIR, match[1])]) 6759 # add new symlink 6760 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M) 6761 for new, old in pattern.findall(text): 6762 if not os.path.exists(pjoin(MG5DIR, new)): 6763 files.ln(pjoin(MG5DIR,old), os.path.dirname(pjoin(MG5DIR,new)), os.path.basename(new)) 6764 6765 # Re-compile CutTools and IREGI 6766 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')): 6767 misc.compile(arg=['-j1'],cwd=pjoin(MG5DIR,'vendor','CutTools'),nb_core=1) 6768 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')): 6769 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src')) 6770 6771 # check if it need to download binary: 6772 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M) 6773 if pattern.search(text): 6774 return True 6775 else: 6776 return False
6777 6778 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')] 6779 if mode: 6780 mode = mode[-1] 6781 else: 6782 mode = "userrequest" 6783 force = any([arg=='-f' for arg in args]) 6784 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')] 6785 if timeout: 6786 try: 6787 timeout = int(timeout[-1]) 6788 except ValueError: 6789 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1]) 6790 else: 6791 timeout = self.options['timeout'] 6792 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')] 6793 6794 if input_path: 6795 fsock = open(input_path[0]) 6796 need_binary = apply_patch(fsock) 6797 logger.info('manual patch apply. Please test your version.') 6798 if need_binary: 6799 logger.warning('Note that some files need to be loaded separately!') 6800 sys.exit(0) 6801 6802 options = ['y','n','on_exit'] 6803 if mode == 'mg5_start': 6804 timeout = 2 6805 default = 'n' 6806 update_delay = self.options['auto_update'] * 24 * 3600 6807 if update_delay == 0: 6808 return 6809 elif mode == 'mg5_end': 6810 timeout = 5 6811 default = 'n' 6812 update_delay = self.options['auto_update'] * 24 * 3600 6813 if update_delay == 0: 6814 return 6815 options.remove('on_exit') 6816 elif mode == "userrequest": 6817 default = 'y' 6818 update_delay = 0 6819 else: 6820 raise self.InvalidCmd('Unknown mode for command install update') 6821 6822 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')):# or \ 6823 #os.path.exists(os.path.join(MG5DIR,'.bzr')): 6824 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are: 6825 1) This version was loaded via bazaar (use bzr pull to update instead). 6826 2) This version is a beta release of MG5.""" 6827 if mode == 'userrequest': 6828 raise self.ConfigurationError(error_text) 6829 return 6830 6831 if not misc.which('patch'): 6832 error_text = """Not able to find program \'patch\'. Please reload a clean version 6833 or install that program and retry.""" 6834 if mode == 'userrequest': 6835 raise self.ConfigurationError(error_text) 6836 return 6837 6838 # read the data present in .autoupdate 6839 data = {'last_message':0} 6840 for line in open(os.path.join(MG5DIR,'input','.autoupdate')): 6841 if not line.strip(): 6842 continue 6843 sline = line.split() 6844 data[sline[0]] = int(sline[1]) 6845 6846 #check validity of the file 6847 if 'version_nb' not in data: 6848 if mode == 'userrequest': 6849 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)' 6850 raise self.ConfigurationError(error_text) 6851 return 6852 elif 'last_check' not in data: 6853 data['last_check'] = time.time() 6854 6855 #check if we need to update. 6856 if time.time() - float(data['last_check']) < float(update_delay): 6857 return 6858 6859 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout) 6860 class TimeOutError(Exception): pass 6861 6862 def handle_alarm(signum, frame): 6863 raise TimeOutError 6864 6865 signal.signal(signal.SIGALRM, handle_alarm) 6866 signal.alarm(timeout) 6867 to_update = 0 6868 try: 6869 filetext = six.moves.urllib.request.urlopen('http://madgraph.physics.illinois.edu/mg5amc_build_nb') 6870 signal.alarm(0) 6871 text = filetext.read().decode().split('\n') 6872 web_version = int(text[0].strip()) 6873 try: 6874 msg_version = int(text[1].strip()) 6875 message = '\n'.join(text[2:]) 6876 except: 6877 msg_version = 0 6878 message = "" 6879 except (TimeOutError, ValueError, IOError): 6880 signal.alarm(0) 6881 print('failed to connect server') 6882 if mode == 'mg5_end': 6883 # wait 24h before next check 6884 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6885 fsock.write("version_nb %s\n" % data['version_nb']) 6886 fsock.write("last_check %s\n" % (\ 6887 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1))) 6888 fsock.write("last_message %s\n" % data['last_message']) 6889 fsock.close() 6890 return 6891 6892 if msg_version > data['last_message']: 6893 data['last_message'] = msg_version 6894 logger.info("************* INFORMATION *************", '$MG:BOLD') 6895 logger.info(message.replace('\n','\n ')) 6896 logger.info("************* INFORMATION *************", '$MG:BOLD') 6897 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6898 fsock.write("version_nb %s\n" % data['version_nb']) 6899 fsock.write("last_check %s\n" % (\ 6900 int(time.time()) - 3600 * 24 * (int(self.options['auto_update']) -1))) 6901 fsock.write("last_message %s\n" % data['last_message']) 6902 fsock.close() 6903 6904 if os.path.exists(os.path.join(MG5DIR,'.bzr')): 6905 logger.info("bzr version: use bzr pull to update") 6906 return 6907 6908 if web_version == data['version_nb']: 6909 logger.info('No new version of MG5 available') 6910 # update .autoupdate to prevent a too close check 6911 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6912 fsock.write("version_nb %s\n" % data['version_nb']) 6913 fsock.write("last_check %s\n" % int(time.time())) 6914 fsock.write("last_message %s\n" % data['last_message']) 6915 fsock.close() 6916 return 6917 elif data['version_nb'] > web_version: 6918 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version)) 6919 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6920 fsock.write("version_nb %s\n" % data['version_nb']) 6921 fsock.write("last_check %s\n" % int(time.time())) 6922 fsock.write("last_message %s\n" % data['last_message']) 6923 fsock.close() 6924 return 6925 else: 6926 if not force: 6927 answer = self.ask('New Version of MG5 available! Do you want to update your current version?', 6928 default, options) 6929 else: 6930 answer = default 6931 6932 6933 if answer == 'y': 6934 logger.info('start updating code') 6935 fail = 0 6936 for i in range(data['version_nb'], web_version): 6937 try: 6938 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1)) 6939 except Exception: 6940 print('fail to load patch to build #%s' % (i+1)) 6941 fail = i 6942 break 6943 need_binary = apply_patch(filetext) 6944 if need_binary: 6945 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1) 6946 name = "extra_file%i" % (i+1) 6947 misc.wget(path, '%s.tgz' % name, cwd=MG5DIR) 6948 # Untar the file 6949 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6950 stdout=open(os.devnull, 'w')) 6951 6952 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6953 if not fail: 6954 fsock.write("version_nb %s\n" % web_version) 6955 else: 6956 fsock.write("version_nb %s\n" % fail) 6957 fsock.write("last_check %s\n" % int(time.time())) 6958 fsock.close() 6959 logger.info('Refreshing installation of MG5aMC_PY8_interface.') 6960 self.do_install('mg5amc_py8_interface',additional_options=['--force']) 6961 logger.info('Checking current version. (type ctrl-c to bypass the check)') 6962 subprocess.call([os.path.join('tests','test_manager.py')], 6963 cwd=MG5DIR) 6964 print('new version installed, please relaunch mg5') 6965 try: 6966 os.remove(pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6967 shutil.copy(pjoin(MG5DIR, 'Template','LO','Source','.make_opts'), 6968 pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6969 except: 6970 pass 6971 sys.exit(0) 6972 elif answer == 'n': 6973 # prevent for a future check 6974 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6975 fsock.write("version_nb %s\n" % data['version_nb']) 6976 fsock.write("last_check %s\n" % int(time.time())) 6977 fsock.close() 6978 logger.info('Update bypassed.') 6979 logger.info('The next check for a new version will be performed in %s days' \ 6980 % abs(self.options['auto_update'])) 6981 logger.info('In order to change this delay. Enter the command:') 6982 logger.info('set auto_update X') 6983 logger.info('Putting X to zero will prevent this check at anytime.') 6984 logger.info('You can upgrade your version at any time by typing:') 6985 logger.info('install update') 6986 else: #answer is on_exit 6987 #ensure that the test will be done on exit 6988 #Do not use the set command here!! 6989 self.options['auto_update'] = -1 * self.options['auto_update'] 6990 6991 6992
6993 - def set_configuration(self, config_path=None, final=True):
6994 """ assign all configuration variable from file 6995 ./input/mg5_configuration.txt. assign to default if not define """ 6996 6997 if not self.options: 6998 self.options = dict(self.options_configuration) 6999 self.options.update(self.options_madgraph) 7000 self.options.update(self.options_madevent) 7001 7002 if not config_path: 7003 if 'MADGRAPH_BASE' in os.environ: 7004 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 7005 self.set_configuration(config_path, final=False) 7006 if 'HOME' in os.environ: 7007 config_path = pjoin(os.environ['HOME'],'.mg5', 7008 'mg5_configuration.txt') 7009 if os.path.exists(config_path): 7010 self.set_configuration(config_path, final=False) 7011 config_path = os.path.relpath(pjoin(MG5DIR,'input', 7012 'mg5_configuration.txt')) 7013 return self.set_configuration(config_path, final) 7014 7015 if not os.path.exists(config_path): 7016 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path) 7017 config_file = open(config_path) 7018 7019 # read the file and extract information 7020 logger.info('load MG5 configuration from %s ' % config_file.name) 7021 for line in config_file: 7022 if '#' in line: 7023 line = line.split('#',1)[0] 7024 line = line.replace('\n','').replace('\r\n','') 7025 try: 7026 name, value = line.split('=') 7027 except ValueError: 7028 pass 7029 else: 7030 name = name.strip() 7031 value = value.strip() 7032 if name != 'mg5_path': 7033 self.options[name] = value 7034 if value.lower() == "none" or value=="": 7035 self.options[name] = None 7036 config_file.close() 7037 self.options['stdout_level'] = logging.getLogger('madgraph').level 7038 if not final: 7039 return self.options # the return is usefull for unittest 7040 7041 # Treat each expected input 7042 # 1: Pythia8_path and hewrig++ paths 7043 # try absolute and relative path 7044 for key in self.options: 7045 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path', 7046 'mg5amc_py8_interface_path','madanalysis5_path']: 7047 if self.options[key] in ['None', None]: 7048 self.options[key] = None 7049 continue 7050 path = self.options[key] 7051 #this is for pythia8 7052 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')): 7053 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')): 7054 self.options['pythia8_path'] = None 7055 else: 7056 continue 7057 #this is for mg5amc_py8_interface_path 7058 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')): 7059 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')): 7060 self.options['mg5amc_py8_interface_path'] = None 7061 else: 7062 continue 7063 #this is for madanalysis5 7064 if key == 'madanalysis5_path' and not os.path.isfile(pjoin(MG5DIR, path,'bin','ma5')): 7065 if not os.path.isfile(pjoin(path,'bin','ma5')): 7066 self.options['madanalysis5_path'] = None 7067 else: 7068 ma5path = pjoin(MG5DIR, path) if os.path.isfile(pjoin(MG5DIR, path)) else path 7069 message = misc.is_MA5_compatible_with_this_MG5(ma5path) 7070 if not message is None: 7071 self.options['madanalysis5_path'] = None 7072 logger.warning(message) 7073 continue 7074 7075 #this is for hw++ 7076 if key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 7077 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 7078 self.options['hwpp_path'] = None 7079 else: 7080 continue 7081 # this is for thepeg 7082 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 7083 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 7084 self.options['thepeg_path'] = None 7085 else: 7086 continue 7087 # this is for hepmc 7088 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 7089 if not os.path.isfile(pjoin(path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 7090 self.options['hepmc_path'] = None 7091 else: 7092 continue 7093 7094 elif key in ['golem','samurai']: 7095 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto': 7096 # try to find it automatically on the system 7097 program = misc.which_lib('lib%s.a'%key) 7098 if program != None: 7099 fpath, _ = os.path.split(program) 7100 logger.info('Using %s library in %s' % (key,fpath)) 7101 self.options[key]=fpath 7102 else: 7103 # Try to look for it locally 7104 local_install = { 'golem':'golem95', 7105 'samurai':'samurai'} 7106 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)): 7107 self.options[key]=pjoin(MG5DIR,local_install[key],'lib') 7108 else: 7109 self.options[key]=None 7110 # Make sure that samurai version is recent enough 7111 if key=='samurai' and \ 7112 isinstance(self.options[key],str) and \ 7113 self.options[key].lower() != 'auto': 7114 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')): 7115 try: 7116 version = open(pjoin(self.options[key],os.pardir, 7117 'VERSION'),'r').read() 7118 except IOError: 7119 version = None 7120 if version is None: 7121 self.options[key] = None 7122 logger.info('--------') 7123 logger.info( 7124 """The version of 'samurai' automatically detected seems too old to be compatible 7125 with MG5aMC and it will be turned off. Ask the authors for the latest version if 7126 you want to use samurai. 7127 If you want to enforce its use as-it-is, then specify directly its library folder 7128 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""") 7129 logger.info('--------') 7130 7131 elif key.endswith('path'): 7132 pass 7133 elif key in ['run_mode', 'auto_update']: 7134 self.options[key] = int(self.options[key]) 7135 elif key in ['cluster_type','automatic_html_opening']: 7136 pass 7137 elif key in ['notification_center']: 7138 if self.options[key] in ['False', 'True']: 7139 self.allow_notification_center = eval(self.options[key]) 7140 self.options[key] = self.allow_notification_center 7141 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']: 7142 # Default: try to set parameter 7143 try: 7144 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 7145 except MadGraph5Error as error: 7146 print(error) 7147 logger.warning("Option %s from config file not understood" \ 7148 % key) 7149 else: 7150 if key in self.options_madgraph: 7151 self.history.append('set %s %s' % (key, self.options[key])) 7152 7153 warnings = madevent_interface.MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options) 7154 if warnings: 7155 logger.warning(warnings) 7156 7157 # Configure the way to open a file: 7158 launch_ext.open_file.configure(self.options) 7159 return self.options
7160
7161 - def check_for_export_dir(self, filepath):
7162 """Check if the files is in a valid export directory and assign it to 7163 export path if if is""" 7164 7165 # keep previous if a previous one is defined 7166 if self._export_dir: 7167 return 7168 7169 if os.path.exists(pjoin(os.getcwd(), 'Cards')): 7170 self._export_dir = os.getcwd() 7171 return 7172 7173 path_split = filepath.split(os.path.sep) 7174 if len(path_split) > 2 and path_split[-2] == 'Cards': 7175 self._export_dir = os.path.sep.join(path_split[:-2]) 7176 return
7177
7178 - def do_launch(self, line):
7179 """Main commands: Ask for editing the parameter and then 7180 Execute the code (madevent/standalone/...) 7181 """ 7182 7183 #ensure that MG option are not modified by the launch routine 7184 current_options = dict([(name, self.options[name]) for name in self.options_madgraph]) 7185 start_cwd = os.getcwd() 7186 7187 args = self.split_arg(line) 7188 # check argument validity and normalise argument 7189 (options, args) = _launch_parser.parse_args(args) 7190 self.check_launch(args, options) 7191 options = options.__dict__ 7192 # args is now MODE PATH 7193 7194 if args[0].startswith('standalone'): 7195 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\ 7196 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\ 7197 os.getcwd(),args[1],'SubProcesses','check_poles.f')): 7198 ext_program = launch_ext.MadLoopLauncher(self, args[1], \ 7199 options=self.options, **options) 7200 else: 7201 ext_program = launch_ext.SALauncher(self, args[1], \ 7202 options=self.options, **options) 7203 elif args[0] == 'madevent': 7204 if options['interactive']: 7205 7206 if isinstance(self, cmd.CmdShell): 7207 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options) 7208 else: 7209 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options) 7210 ME.pass_in_web_mode() 7211 stop = self.define_child_cmd_interface(ME) 7212 return stop 7213 7214 #check if this is a cross-section 7215 if not self._generate_info: 7216 # This relaunch an old run -> need to check if this is a 7217 # cross-section or a width 7218 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read() 7219 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1] 7220 generate_info = generate_info.split('#')[0] 7221 else: 7222 generate_info = self._generate_info 7223 7224 if len(generate_info.split('>')[0].strip().split())>1: 7225 ext_program = launch_ext.MELauncher(args[1], self, 7226 shell = isinstance(self, cmd.CmdShell), 7227 options=self.options,**options) 7228 else: 7229 # This is a width computation 7230 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV', 7231 shell = isinstance(self, cmd.CmdShell), 7232 options=self.options,**options) 7233 7234 elif args[0] == 'pythia8': 7235 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options) 7236 7237 elif args[0] == 'aMC@NLO': 7238 if options['interactive']: 7239 if isinstance(self, cmd.CmdShell): 7240 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options) 7241 else: 7242 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options) 7243 ME.pass_in_web_mode() 7244 # transfer interactive configuration 7245 config_line = [l for l in self.history if l.strip().startswith('set')] 7246 for line in config_line: 7247 ME.exec_cmd(line) 7248 stop = self.define_child_cmd_interface(ME) 7249 return stop 7250 ext_program = launch_ext.aMCatNLOLauncher( args[1], self, 7251 shell = isinstance(self, cmd.CmdShell), 7252 **options) 7253 elif args[0] == 'madweight': 7254 import madgraph.interface.madweight_interface as madweight_interface 7255 if options['interactive']: 7256 if isinstance(self, cmd.CmdShell): 7257 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options) 7258 else: 7259 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options) 7260 # transfer interactive configuration 7261 config_line = [l for l in self.history if l.strip().startswith('set')] 7262 for line in config_line: 7263 MW.exec_cmd(line) 7264 stop = self.define_child_cmd_interface(MW) 7265 return stop 7266 ext_program = launch_ext.MWLauncher( self, args[1], 7267 shell = isinstance(self, cmd.CmdShell), 7268 options=self.options,**options) 7269 else: 7270 os.chdir(start_cwd) #ensure to go to the initial path 7271 raise self.InvalidCmd('%s cannot be run from MG5 interface' % args[0]) 7272 7273 7274 ext_program.run() 7275 os.chdir(start_cwd) #ensure to go to the initial path 7276 # ensure that MG options are not changed! 7277 for key, value in current_options.items(): 7278 self.options[key] = value
7279
7280 - def do_load(self, line):
7281 """Not in help: Load information from file""" 7282 7283 args = self.split_arg(line) 7284 # check argument validity 7285 self.check_load(args) 7286 7287 cpu_time1 = time.time() 7288 if args[0] == 'model': 7289 self._curr_model = save_load_object.load_from_file(args[1]) 7290 if self._curr_model.get('parameters'): 7291 # This is a UFO model 7292 self._model_v4_path = None 7293 else: 7294 # This is a v4 model 7295 self._model_v4_path = import_v4.find_model_path(\ 7296 self._curr_model.get('name').replace("_v4", ""), 7297 self._mgme_dir) 7298 7299 # Do post-processing of model 7300 self.process_model() 7301 7302 #save_model.save_model(args[1], self._curr_model) 7303 if isinstance(self._curr_model, base_objects.Model): 7304 cpu_time2 = time.time() 7305 logger.info("Loaded model from file in %0.3f s" % \ 7306 (cpu_time2 - cpu_time1)) 7307 else: 7308 raise self.RWError('Could not load model from file %s' \ 7309 % args[1]) 7310 elif args[0] == 'processes': 7311 amps,proc_defs = save_load_object.load_from_file(args[1]) 7312 if isinstance(amps, diagram_generation.AmplitudeList): 7313 cpu_time2 = time.time() 7314 logger.info("Loaded processes from file in %0.3f s" % \ 7315 (cpu_time2 - cpu_time1)) 7316 if amps: 7317 model = amps[0].get('process').get('model') 7318 if not model.get('parameters'): 7319 # This is a v4 model. Look for path. 7320 self._model_v4_path = import_v4.find_model_path(\ 7321 model.get('name').replace("_v4", ""), 7322 self._mgme_dir) 7323 else: 7324 self._model_v4_path = None 7325 # If not exceptions from previous steps, set 7326 # _curr_amps and _curr_model 7327 self._curr_amps = amps 7328 self._curr_model = model 7329 self._curr_proc_defs = proc_defs 7330 logger.info("Model set from process.") 7331 # Do post-processing of model 7332 self.process_model() 7333 self._done_export = None 7334 else: 7335 raise self.RWError('Could not load processes from file %s' % args[1])
7336 7337
7338 - def do_customize_model(self, line):
7339 """create a restriction card in a interactive way""" 7340 7341 args = self.split_arg(line) 7342 self.check_customize_model(args) 7343 7344 model_path = self._curr_model.get('modelpath') 7345 if not os.path.exists(pjoin(model_path,'build_restrict.py')): 7346 raise self.InvalidCmd('''Model not compatible with this option.''') 7347 7348 # (re)import the full model (get rid of the default restriction) 7349 self._curr_model = import_ufo.import_model(model_path, restrict=False) 7350 7351 #1) create the full param_card 7352 out_path = StringIO.StringIO() 7353 param_writer.ParamCardWriter(self._curr_model, out_path) 7354 # and load it to a python object 7355 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 7356 7357 7358 all_categories = self.ask('','0',[], ask_class=AskforCustomize) 7359 put_to_one = [] 7360 ## Make a Temaplate for the restriction card. (card with no restrict) 7361 for block in param_card: 7362 value_dict = {} 7363 for param in param_card[block]: 7364 value = param.value 7365 if value == 0: 7366 param.value = 0.000001e-99 7367 elif value == 1: 7368 if block != 'qnumbers': 7369 put_to_one.append((block,param.lhacode)) 7370 param.value = random.random() 7371 elif abs(value) in value_dict: 7372 param.value += value_dict[abs(value)] * 1e-4 * param.value 7373 value_dict[abs(value)] += 1 7374 else: 7375 value_dict[abs(value)] = 1 7376 7377 for category in all_categories: 7378 for options in category: 7379 if not options.status: 7380 continue 7381 param = param_card[options.lhablock].get(options.lhaid) 7382 param.value = options.value 7383 7384 logger.info('Loading the resulting model') 7385 # Applying the restriction 7386 self._curr_model = import_ufo.RestrictModel(self._curr_model) 7387 model_name = self._curr_model.get('name') 7388 if model_name == 'mssm': 7389 keep_external=True 7390 else: 7391 keep_external=False 7392 self._curr_model.restrict_model(param_card,keep_external=keep_external) 7393 7394 if args: 7395 name = args[0].split('=',1)[1] 7396 path = pjoin(model_path,'restrict_%s.dat' % name) 7397 logger.info('Save restriction file as %s' % path) 7398 param_card.write(path) 7399 self._curr_model['name'] += '-%s' % name 7400 7401 # if some need to put on one 7402 if put_to_one: 7403 out_path = StringIO.StringIO() 7404 param_writer.ParamCardWriter(self._curr_model, out_path) 7405 # and load it to a python object 7406 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 7407 7408 for (block, lhacode) in put_to_one: 7409 try: 7410 param_card[block].get(lhacode).value = 1 7411 except: 7412 pass # was removed of the model! 7413 self._curr_model.set_parameters_and_couplings(param_card) 7414 7415 if args: 7416 name = args[0].split('=',1)[1] 7417 path = pjoin(model_path,'paramcard_%s.dat' % name) 7418 logger.info('Save default card file as %s' % path) 7419 param_card.write(path)
7420
7421 - def do_save(self, line, check=True, to_keep={}, log=True):
7422 """Not in help: Save information to file""" 7423 7424 7425 args = self.split_arg(line) 7426 # Check argument validity 7427 if check: 7428 self.check_save(args) 7429 7430 if args[0] == 'model': 7431 if self._curr_model: 7432 #save_model.save_model(args[1], self._curr_model) 7433 if save_load_object.save_to_file(args[1], self._curr_model): 7434 logger.info('Saved model to file %s' % args[1]) 7435 else: 7436 raise self.InvalidCmd('No model to save!') 7437 elif args[0] == 'processes': 7438 if self._curr_amps: 7439 if save_load_object.save_to_file(args[1], (self._curr_amps,self._curr_proc_defs) ): 7440 logger.info('Saved processes to file %s' % args[1]) 7441 else: 7442 raise self.InvalidCmd('No processes to save!') 7443 7444 elif args[0] == 'options': 7445 partial_save = False 7446 to_define = {} 7447 7448 if any(not arg.startswith('--') and arg in self.options 7449 for arg in args): 7450 # store in file only those ones 7451 partial_save = True 7452 all_arg = [arg for arg in args[1:] if not arg.startswith('--') and 7453 arg in self.options] 7454 for key in all_arg: 7455 to_define[key] = self.options[key] 7456 else: 7457 # First look at options which should be put in MG5DIR/input 7458 for key, default in self.options_configuration.items(): 7459 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None: 7460 to_define[key] = self.options[key] 7461 7462 if not '--auto' in args: 7463 for key, default in self.options_madevent.items(): 7464 if self.options_madevent[key] != self.options[key] != None: 7465 if '_path' in key and os.path.basename(self.options[key]) == 'None': 7466 continue 7467 to_define[key] = self.options[key] 7468 elif key == 'cluster_queue' and self.options[key] is None: 7469 to_define[key] = self.options[key] 7470 7471 if '--all' in args: 7472 for key, default in self.options_madgraph.items(): 7473 if self.options_madgraph[key] != self.options[key] != None and \ 7474 key != 'stdout_level': 7475 to_define[key] = self.options[key] 7476 elif not '--auto' in args: 7477 for key, default in self.options_madgraph.items(): 7478 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level': 7479 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 7480 % (key,self.options_madgraph[key]) ) 7481 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 7482 7483 if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options: 7484 filepath = args[1] 7485 else: 7486 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 7487 7488 basedir = MG5DIR 7489 if partial_save: 7490 basefile = filepath 7491 else: 7492 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt') 7493 7494 7495 7496 if to_keep: 7497 to_define = to_keep 7498 self.write_configuration(filepath, basefile, basedir, to_define)
7499 7500 # Set an option
7501 - def do_set(self, line, log=True, model_reload=True):
7502 """Set an option, which will be default for coming generations/outputs. 7503 """ 7504 7505 # Be careful: 7506 # This command is associated to a post_cmd: post_set. 7507 args = self.split_arg(line) 7508 7509 # Check the validity of the arguments 7510 self.check_set(args) 7511 7512 if args[0] == 'ignore_six_quark_processes': 7513 if args[1].lower() == 'false': 7514 self.options[args[0]] = False 7515 return 7516 self.options[args[0]] = list(set([abs(p) for p in \ 7517 self._multiparticles[args[1]]\ 7518 if self._curr_model.get_particle(p).\ 7519 is_fermion() and \ 7520 self._curr_model.get_particle(abs(p)).\ 7521 get('color') == 3])) 7522 if log: 7523 logger.info('Ignore processes with >= 6 quarks (%s)' % \ 7524 ",".join([\ 7525 self._curr_model.get_particle(q).get('name') \ 7526 for q in self.options[args[0]]])) 7527 7528 elif args[0] == 'group_subprocesses': 7529 if args[1].lower() not in ['auto', 'nlo']: 7530 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, name="group_subprocesses") 7531 else: 7532 if args[1].lower() == 'nlo': 7533 self.options[args[0]] = "NLO" 7534 else: 7535 self.options[args[0]] = "Auto" 7536 if log: 7537 logger.info('Set group_subprocesses to %s' % \ 7538 str(self.options[args[0]])) 7539 logger.info('Note that you need to regenerate all processes') 7540 self._curr_amps = diagram_generation.AmplitudeList() 7541 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7542 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7543 7544 elif args[0] == "stdout_level": 7545 if args[1].isdigit(): 7546 level = int(args[1]) 7547 else: 7548 level = eval('logging.' + args[1]) 7549 logging.root.setLevel(level) 7550 logging.getLogger('madgraph').setLevel(level) 7551 logging.getLogger('madevent').setLevel(level) 7552 self.options[args[0]] = level 7553 if log: 7554 logger.info('set output information to level: %s' % level) 7555 elif args[0].lower() == "ewscheme": 7556 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." %\ 7557 (self._curr_model.get('name'), args[1])) 7558 logger.info("Importing a model will restore the default scheme") 7559 self._curr_model.change_electroweak_mode(args[1]) 7560 elif args[0] == "complex_mass_scheme": 7561 old = self.options[args[0]] 7562 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, "complex_mass_scheme") 7563 aloha.complex_mass = self.options[args[0]] 7564 aloha_lib.KERNEL.clean() 7565 if self.options[args[0]]: 7566 if old: 7567 if log: 7568 logger.info('Complex mass already activated.') 7569 return 7570 if log: 7571 logger.info('Activate complex mass scheme.') 7572 else: 7573 if not old: 7574 if log: 7575 logger.info('Complex mass already desactivated.') 7576 return 7577 if log: 7578 logger.info('Desactivate complex mass scheme.') 7579 if not self._curr_model: 7580 return 7581 self.exec_cmd('import model %s' % self._curr_model.get('name')) 7582 7583 elif args[0] == "gauge": 7584 # Treat the case where they are no model loaded 7585 if not self._curr_model: 7586 if args[1] == 'unitary': 7587 aloha.unitary_gauge = True 7588 elif args[1] == 'axial': 7589 aloha.unitary_gauge = 2 7590 else: 7591 aloha.unitary_gauge = False 7592 aloha_lib.KERNEL.clean() 7593 self.options[args[0]] = args[1] 7594 if log: logger.info('Passing to gauge %s.' % args[1]) 7595 return 7596 7597 # They are a valid model 7598 able_to_mod = True 7599 if args[1] == 'unitary': 7600 if 0 in self._curr_model.get('gauge'): 7601 aloha.unitary_gauge = True 7602 else: 7603 able_to_mod = False 7604 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \ 7605 % self._curr_model.get('name')) 7606 elif args[1] == 'axial': 7607 if 0 in self._curr_model.get('gauge'): 7608 aloha.unitary_gauge = 2 7609 else: 7610 able_to_mod = False 7611 if log: logger.warning('Note that parton-shower gauge is not allowed for your current model %s' \ 7612 % self._curr_model.get('name')) 7613 else: 7614 if 1 in self._curr_model.get('gauge'): 7615 aloha.unitary_gauge = False 7616 else: 7617 able_to_mod = False 7618 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \ 7619 % self._curr_model.get('name')) 7620 7621 if self.options['gauge'] == args[1]: 7622 return 7623 7624 7625 self.options[args[0]] = args[1] 7626 7627 if able_to_mod and log and args[0] == 'gauge' and \ 7628 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \ 7629 isinstance(self._curr_model,loop_base_objects.LoopModel) and \ 7630 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 7631 logger.warning('You will only be able to do tree level'+\ 7632 ' and QCD corrections in the unitary gauge.') 7633 7634 7635 7636 #re-init all variable 7637 model_name = self._curr_model.get('modelpath+restriction') 7638 self._curr_model = None 7639 self._curr_amps = diagram_generation.AmplitudeList() 7640 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7641 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7642 self._curr_helas_model = None 7643 self._curr_exporter = None 7644 self._done_export = False 7645 import_ufo._import_once = [] 7646 logger.info('Passing to gauge %s.' % args[1]) 7647 7648 if able_to_mod: 7649 # We don't want to go through the MasterCommand again 7650 # because it messes with the interface switching when 7651 # importing a loop model from MG5 7652 if 'modelname' in self.history.get('full_model_line'): 7653 opts = '--modelname' 7654 else: 7655 opts='' 7656 MadGraphCmd.do_import(self,'model %s %s' % (model_name, opts), force=True) 7657 elif log: 7658 logger.info('Note that you have to reload the model') 7659 7660 elif args[0] == 'fortran_compiler': 7661 if args[1] != 'None': 7662 if log: 7663 logger.info('set fortran compiler to %s' % args[1]) 7664 self.options['fortran_compiler'] = args[1] 7665 else: 7666 self.options['fortran_compiler'] = None 7667 elif args[0] == 'default_unset_couplings': 7668 self.options['default_unset_couplings'] = banner_module.ConfigFile.format_variable(args[1], int, name="default_unset_couplings") 7669 elif args[0].startswith('f2py_compiler'): 7670 to_do = True 7671 if args[0].endswith('_py2') and six.PY3: 7672 to_do = False 7673 elif args[0].endswith('_py3') and six.PY2: 7674 to_do = False 7675 if to_do: 7676 if args[1] != 'None': 7677 if log: 7678 logger.info('set f2py compiler to %s' % args[1]) 7679 7680 self.options['f2py_compiler'] = args[1] 7681 else: 7682 self.options['f2py_compiler'] = None 7683 7684 elif args[0] == 'loop_optimized_output': 7685 7686 if log: 7687 logger.info('set loop optimized output to %s' % args[1]) 7688 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7689 self.options[args[0]] = args[1] 7690 if not self.options['loop_optimized_output'] and \ 7691 self.options['loop_color_flows']: 7692 logger.warning("Turning off option 'loop_color_flows'"+\ 7693 " since it is not available for non-optimized loop output.") 7694 self.do_set('loop_color_flows False',log=False) 7695 elif args[0] == 'loop_color_flows': 7696 if log: 7697 logger.info('set loop color flows to %s' % args[1]) 7698 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7699 self.options[args[0]] = args[1] 7700 if self.options['loop_color_flows'] and \ 7701 not self.options['loop_optimized_output']: 7702 logger.warning("Turning on option 'loop_optimized'"+\ 7703 " needed for loop color flow computation.") 7704 self.do_set('loop_optimized_output True',False) 7705 7706 elif args[0] == 'fastjet': 7707 try: 7708 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE, 7709 stderr=subprocess.PIPE) 7710 output, error = p.communicate() 7711 output = output.decode() 7712 res = 0 7713 except Exception: 7714 res = 1 7715 7716 if res != 0 or error: 7717 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \ 7718 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \ 7719 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' + 7720 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n') 7721 self.options[args[0]] = None 7722 if self.history and 'fastjet' in self.history[-1]: 7723 self.history.pop() 7724 elif int(output.split('.')[0]) < 3: 7725 logger.warning('%s is not ' % args[1] + \ 7726 'v3 or greater. Please install FastJet v3+.') 7727 self.options[args[0]] = None 7728 self.history.pop() 7729 else: #everything is fine 7730 logger.info('set fastjet to %s' % args[1]) 7731 self.options[args[0]] = args[1] 7732 7733 elif args[0] in ['golem','samurai','ninja','collier'] and \ 7734 not (args[0] in ['ninja','collier'] and args[1]=='./HEPTools/lib'): 7735 if args[1] in ['None',"''",'""']: 7736 self.options[args[0]] = None 7737 else: 7738 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0])) 7739 if program!=None: 7740 res = 0 7741 logger.info('set %s to %s' % (args[0],args[1])) 7742 self.options[args[0]] = args[1] 7743 else: 7744 res = 1 7745 7746 if res != 0 : 7747 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \ 7748 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \ 7749 'You will NOT be able to run %s otherwise.\n'%args[0]) 7750 7751 elif args[0].startswith('lhapdf'): 7752 to_do = True 7753 if args[0].endswith('_py2') and six.PY3: 7754 to_do = False 7755 elif args[0].endswith('_py3') and six.PY2: 7756 to_do = False 7757 if to_do: 7758 try: 7759 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE, 7760 stderr=subprocess.PIPE) 7761 logger.info('set lhapdf to %s' % args[1]) 7762 self.options['lhapdf'] = args[1] 7763 self.options[args[0]] = args[1] 7764 except Exception: 7765 res = 1 7766 if res != 0: 7767 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \ 7768 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \ 7769 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \ 7770 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \ 7771 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n') 7772 7773 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry', 'max_t_for_channel', 7774 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']: 7775 self.options[args[0]] = int(args[1]) 7776 7777 elif args[0] in ['cluster_local_path']: 7778 self.options[args[0]] = args[1].strip() 7779 7780 elif args[0] == 'cluster_status_update': 7781 if '(' in args[1]: 7782 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 7783 data = data.replace('(','').replace(')','').replace(',',' ').split() 7784 first, second = data[:2] 7785 else: 7786 first, second = args[1:3] 7787 7788 self.options[args[0]] = (int(first), int(second)) 7789 7790 elif args[0] == 'madanalysis5_path': 7791 ma5path = pjoin(MG5DIR, args[1]) if os.path.isfile(pjoin(MG5DIR, args[1])) else args[1] 7792 message = misc.is_MA5_compatible_with_this_MG5(ma5path) 7793 if message is None: 7794 self.options['madanalysis5_path'] = args[1] 7795 else: 7796 logger.warning(message) 7797 7798 elif args[0] == 'OLP': 7799 if six.PY3 and self.options['low_mem_multicore_nlo_generation']: 7800 raise self.InvalidCmd('Not possible to set OLP with both \"low_mem_multicore_nlo_generation\" and python3') 7801 # Reset the amplitudes, MatrixElements and exporter as they might 7802 # depend on this option 7803 self._curr_amps = diagram_generation.AmplitudeList() 7804 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7805 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7806 self._curr_exporter = None 7807 self.options[args[0]] = args[1] 7808 7809 elif args[0] =='output_dependencies': 7810 self.options[args[0]] = args[1] 7811 elif args[0] =='notification_center': 7812 if args[1] in ['None','True','False']: 7813 self.options[args[0]] = eval(args[1]) 7814 self.allow_notification_center = self.options[args[0]] 7815 else: 7816 raise self.InvalidCmd('expected bool for notification_center') 7817 # True/False formatting 7818 elif args[0] in ['crash_on_error', 'auto_convert_model']: 7819 try: 7820 tmp = banner_module.ConfigFile.format_variable(args[1], bool, args[0]) 7821 except Exception: 7822 if args[1].lower() in ['never']: 7823 tmp = args[1].lower() 7824 else: 7825 raise 7826 self.options[args[0]] = tmp 7827 elif args[0] in ['zerowidth_tchannel']: 7828 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, args[0]) 7829 elif args[0] in ['cluster_queue']: 7830 self.options[args[0]] = args[1].strip() 7831 elif args[0] in ['low_mem_multicore_nlo_generation']: 7832 if six.PY3 and self.options['OLP'] != 'MadLoop': 7833 raise self.InvalidCmd('Not possible to set \"low_mem_multicore_nlo_generation\" for an OLP different of MadLoop when running python3') 7834 else: 7835 self.options[args[0]] = args[1] 7836 elif args[0] in self.options: 7837 if args[1] in ['None','True','False']: 7838 self.options[args[0]] = eval(args[1]) 7839 else: 7840 self.options[args[0]] = args[1]
7841
7842 - def post_set(self, stop, line):
7843 """Check if we need to save this in the option file""" 7844 7845 args = self.split_arg(line) 7846 # Check the validity of the arguments 7847 try: 7848 self.check_set(args, log=False) 7849 except Exception: 7850 return stop 7851 7852 if args[0] in self.options_configuration and '--no_save' not in args: 7853 self.exec_cmd('save options %s' % args[0] , log=False) 7854 elif args[0] in self.options_madevent: 7855 if not '--no_save' in line: 7856 logger.info('This option will be the default in any output that you are going to create in this session.') 7857 logger.info('In order to keep this changes permanent please run \'save options\'') 7858 else: 7859 #MadGraph5_aMC@NLO configuration 7860 if not self.history or self.history[-1].split() != line.split(): 7861 self.history.append('set %s' % line) 7862 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set']) 7863 return stop
7864
7865 - def do_open(self, line):
7866 """Open a text file/ eps file / html file""" 7867 7868 args = self.split_arg(line) 7869 # Check Argument validity and modify argument to be the real path 7870 self.check_open(args) 7871 file_path = args[0] 7872 7873 launch_ext.open_file(file_path)
7874
7875 - def do_output(self, line):
7876 """Main commands: Initialize a new Template or reinitialize one""" 7877 7878 args = self.split_arg(line) 7879 # Check Argument validity 7880 self.check_output(args) 7881 7882 noclean = '-noclean' in args 7883 force = '-f' in args 7884 nojpeg = '-nojpeg' in args 7885 if '--noeps=True' in args: 7886 nojpeg = True 7887 flaglist = [] 7888 7889 if '--postpone_model' in args: 7890 flaglist.append('store_model') 7891 if '--hel_recycling=False' in args: 7892 flaglist.append('no_helrecycling') 7893 7894 line_options = dict( (arg[2:].split('=') if "=" in arg else (arg[2:], True)) 7895 for arg in args if arg.startswith('--')) 7896 # line_options = dict(arg[2:].split('=') for arg in args if arg.startswith('--') and '=' not in arg) 7897 main_file_name = "" 7898 try: 7899 main_file_name = args[args.index('-name') + 1] 7900 except Exception: 7901 pass 7902 7903 7904 ################ 7905 # ALOHA OUTPUT # 7906 ################ 7907 if self._export_format == 'aloha': 7908 # catch format 7909 format = [d[9:] for d in args if d.startswith('--format=')] 7910 if not format: 7911 format = 'Fortran' 7912 else: 7913 format = format[-1] 7914 # catch output dir 7915 output = [d for d in args if d.startswith('--output=')] 7916 if not output: 7917 output = import_ufo.find_ufo_path(self._curr_model['name']) 7918 output = pjoin(output, format) 7919 if not os.path.isdir(output): 7920 os.mkdir(output) 7921 else: 7922 output = output[-1] 7923 if not os.path.isdir(output): 7924 raise self.InvalidCmd('%s is not a valid directory' % output) 7925 logger.info('creating routines in directory %s ' % output) 7926 # build the calling list for aloha 7927 names = [d for d in args if not d.startswith('-')] 7928 wanted_lorentz = aloha_fct.guess_routine_from_name(names) 7929 # Create and write ALOHA Routine 7930 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name')) 7931 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz')) 7932 if wanted_lorentz: 7933 aloha_model.compute_subset(wanted_lorentz) 7934 else: 7935 aloha_model.compute_all(save=False) 7936 aloha_model.write(output, format) 7937 return 7938 7939 ################# 7940 ## Other Output # 7941 ################# 7942 # Configuration of what to do: 7943 # check: check status of the directory 7944 # exporter: which exporter to use (v4/cpp/...) 7945 # output: [Template/dir/None] copy the Template, just create dir or do nothing 7946 config = {} 7947 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7948 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'} 7949 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7950 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7951 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7952 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7953 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'} 7954 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'} 7955 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} 7956 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'} 7957 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7958 7959 if self._export_format == 'plugin': 7960 options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output} 7961 else: 7962 options = config[self._export_format] 7963 7964 # check 7965 if os.path.realpath(self._export_dir) == os.getcwd(): 7966 if len(args) == 0: 7967 i=0 7968 while 1: 7969 if os.path.exists('Pythia8_proc_%i' %i): 7970 i+=1 7971 else: 7972 break 7973 os.mkdir('Pythia8_proc_%i' %i) 7974 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i) 7975 logger.info('Create output in %s' % self._export_dir) 7976 elif not args[0] in ['.', '-f']: 7977 raise self.InvalidCmd('Wrong path directory to create in local directory use \'.\'') 7978 elif not noclean and os.path.isdir(self._export_dir) and options['check']: 7979 if not force: 7980 # Don't ask if user already specified force or noclean 7981 logger.info('INFO: directory %s already exists.' % self._export_dir) 7982 logger.info('If you continue this directory will be deleted and replaced.') 7983 answer = self.ask('Do you want to continue?', 'y', ['y','n']) 7984 else: 7985 answer = 'y' 7986 if answer != 'y': 7987 raise self.InvalidCmd('Stopped by user request') 7988 else: 7989 shutil.rmtree(self._export_dir) 7990 7991 # Choose here whether to group subprocesses or not, if the option was 7992 # set to 'Auto' and propagate this choice down the line: 7993 if self.options['group_subprocesses'] in [True, False]: 7994 group_processes = self.options['group_subprocesses'] 7995 elif self.options['group_subprocesses'] == 'Auto': 7996 # By default we set it to True 7997 group_processes = True 7998 # But we turn if off for decay processes which 7999 # have been defined with multiparticle labels, because then 8000 # branching ratios necessitates to keep subprocesses independent. 8001 # That applies only if there is more than one subprocess of course. 8002 if self._curr_amps[0].get_ninitial() == 1 and \ 8003 len(self._curr_amps)>1: 8004 8005 processes = [amp.get('process') for amp in self._curr_amps if 'process' in list(amp.keys())] 8006 if len(set(proc.get('id') for proc in processes))!=len(processes): 8007 # Special warning for loop-induced 8008 if any(proc['perturbation_couplings'] != [] for proc in 8009 processes) and self._export_format == 'madevent': 8010 logger.warning(""" 8011 || The loop-induced decay process you have specified contains several 8012 || subprocesses and, in order to be able to compute individual branching ratios, 8013 || MG5_aMC will *not* group them. Integration channels will also be considered 8014 || for each diagrams and as a result integration will be inefficient. 8015 || It is therefore recommended to perform this simulation by setting the MG5_aMC 8016 || option 'group_subprocesses' to 'True' (before the output of the process). 8017 || Notice that when doing so, processes for which one still wishes to compute 8018 || branching ratios independently can be specified using the syntax: 8019 || -> add process <proc_def> 8020 """) 8021 group_processes = False 8022 8023 #Exporter + Template 8024 if options['exporter'] == 'v4': 8025 self._curr_exporter = export_v4.ExportV4Factory(self, noclean, 8026 group_subprocesses=group_processes, 8027 cmd_options=line_options) 8028 elif options['exporter'] == 'cpp': 8029 self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes, 8030 cmd_options=line_options) 8031 8032 self._curr_exporter.pass_information_from_cmd(self) 8033 8034 if options['output'] == 'Template': 8035 self._curr_exporter.copy_template(self._curr_model) 8036 elif options['output'] == 'dir' and not os.path.isdir(self._export_dir): 8037 os.makedirs(self._export_dir) 8038 8039 # Reset _done_export, since we have new directory 8040 self._done_export = False 8041 8042 if self._export_format == "madevent": 8043 # for MadEvent with MadLoop decide if we keep the box as channel of 8044 #integration or not. Forbid them for matching and for h+j 8045 if self.options['max_npoint_for_channel']: 8046 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel'] 8047 else: 8048 base_objects.Vertex.max_n_loop_for_multichanneling = 3 8049 base_objects.Vertex.max_tpropa = self.options['max_t_for_channel'] 8050 8051 # Perform export and finalize right away 8052 self.export(nojpeg, main_file_name, group_processes, args) 8053 8054 # Automatically run finalize 8055 self.finalize(nojpeg, flaglist=flaglist) 8056 8057 # Remember that we have done export 8058 self._done_export = (self._export_dir, self._export_format) 8059 8060 # Reset _export_dir, so we don't overwrite by mistake later 8061 self._export_dir = None
8062 8063 # Export a matrix element
8064 - def export(self, nojpeg = False, main_file_name = "", group_processes=True, 8065 args=[]):
8066 """Export a generated amplitude to file.""" 8067 8068 8069 # Define the helas call writer 8070 if self._curr_exporter.exporter == 'cpp': 8071 self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model) 8072 elif self._model_v4_path: 8073 assert self._curr_exporter.exporter == 'v4' 8074 self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model) 8075 else: 8076 assert self._curr_exporter.exporter == 'v4' 8077 options = {'zerowidth_tchannel': True} 8078 if self._curr_amps and self._curr_amps[0].get_ninitial() == 1: 8079 options['zerowidth_tchannel'] = False 8080 8081 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model, options=options) 8082 8083 version = [arg[10:] for arg in args if arg.startswith('--version=')] 8084 if version: 8085 version = version[-1] 8086 else: 8087 version = '8.2' 8088 8089 def generate_matrix_elements(self, group_processes=True): 8090 """Helper function to generate the matrix elements before 8091 exporting. Uses the main function argument 'group_processes' to decide 8092 whether to use group_subprocess or not. (it has been set in do_output to 8093 the appropriate value if the MG5 option 'group_subprocesses' was set 8094 to 'Auto'.""" 8095 8096 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']: 8097 to_distinguish = [] 8098 for part in self._curr_model.get('particles'): 8099 if part.get('name') in args and part.get('antiname') in args and\ 8100 part.get('name') != part.get('antiname'): 8101 to_distinguish.append(abs(part.get('pdg_code'))) 8102 # Sort amplitudes according to number of diagrams, 8103 # to get most efficient multichannel output 8104 self._curr_amps.sort(key=lambda x: x.get_number_of_diagrams(),reverse=True) 8105 8106 cpu_time1 = time.time() 8107 ndiags = 0 8108 if not self._curr_matrix_elements.get_matrix_elements(): 8109 if group_processes: 8110 cpu_time1 = time.time() 8111 dc_amps = diagram_generation.DecayChainAmplitudeList(\ 8112 [amp for amp in self._curr_amps if isinstance(amp, \ 8113 diagram_generation.DecayChainAmplitude)]) 8114 non_dc_amps = diagram_generation.AmplitudeList(\ 8115 [amp for amp in self._curr_amps if not \ 8116 isinstance(amp, \ 8117 diagram_generation.DecayChainAmplitude)]) 8118 subproc_groups = group_subprocs.SubProcessGroupList() 8119 matrix_elements_opts = {'optimized_output': 8120 self.options['loop_optimized_output']} 8121 8122 grouping_criteria = self._curr_exporter.grouped_mode 8123 if non_dc_amps: 8124 subproc_groups.extend(\ 8125 group_subprocs.SubProcessGroup.group_amplitudes(\ 8126 non_dc_amps,grouping_criteria, 8127 matrix_elements_opts=matrix_elements_opts)) 8128 8129 if dc_amps: 8130 dc_subproc_group = \ 8131 group_subprocs.DecayChainSubProcessGroup.\ 8132 group_amplitudes(dc_amps, grouping_criteria, 8133 matrix_elements_opts=matrix_elements_opts) 8134 subproc_groups.extend(dc_subproc_group.\ 8135 generate_helas_decay_chain_subproc_groups()) 8136 8137 ndiags = sum([len(m.get('diagrams')) for m in \ 8138 subproc_groups.get_matrix_elements()]) 8139 self._curr_matrix_elements = subproc_groups 8140 # assign a unique id number to all groups 8141 uid = 0 8142 for group in subproc_groups: 8143 uid += 1 # update the identification number 8144 for me in group.get('matrix_elements'): 8145 me.get('processes')[0].set('uid', uid) 8146 else: # Not grouped subprocesses 8147 mode = {} 8148 if self._export_format in [ 'standalone_msP' , 8149 'standalone_msF', 'standalone_rw']: 8150 mode['mode'] = 'MadSpin' 8151 # The conditional statement tests whether we are dealing 8152 # with a loop induced process. 8153 if isinstance(self._curr_amps[0], 8154 loop_diagram_generation.LoopAmplitude): 8155 mode['optimized_output']=self.options['loop_optimized_output'] 8156 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess 8157 compute_loop_nc = True 8158 else: 8159 HelasMultiProcessClass = helas_objects.HelasMultiProcess 8160 compute_loop_nc = False 8161 8162 self._curr_matrix_elements = HelasMultiProcessClass( 8163 self._curr_amps, compute_loop_nc=compute_loop_nc, 8164 matrix_element_opts=mode) 8165 8166 ndiags = sum([len(me.get('diagrams')) for \ 8167 me in self._curr_matrix_elements.\ 8168 get_matrix_elements()]) 8169 # assign a unique id number to all process 8170 uid = 0 8171 for me in self._curr_matrix_elements.get_matrix_elements()[:]: 8172 uid += 1 # update the identification number 8173 me.get('processes')[0].set('uid', uid) 8174 8175 cpu_time2 = time.time() 8176 8177 8178 return ndiags, cpu_time2 - cpu_time1
8179 8180 # Start of the actual routine 8181 8182 ndiags, cpu_time = generate_matrix_elements(self,group_processes) 8183 8184 calls = 0 8185 8186 path = self._export_dir 8187 8188 cpu_time1 = time.time() 8189 8190 # First treat madevent and pythia8 exports, where we need to 8191 # distinguish between grouped and ungrouped subprocesses 8192 8193 # MadEvent 8194 if self._export_format == 'madevent': 8195 calls += self._curr_exporter.export_processes(self._curr_matrix_elements, 8196 self._curr_helas_model) 8197 8198 #try: 8199 # cmd.Cmd.onecmd(self, 'history .') 8200 #except Exception: 8201 # misc.sprint('command history fails.', 10) 8202 # pass 8203 8204 # Pythia 8 8205 elif self._export_format == 'pythia8': 8206 # Output the process files 8207 process_names = [] 8208 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList): 8209 for (group_number, me_group) in enumerate(self._curr_matrix_elements): 8210 exporter = self._curr_exporter.generate_process_directory(\ 8211 me_group.get('matrix_elements'), self._curr_helas_model, 8212 process_string = me_group.get('name'), 8213 process_number = group_number+1, 8214 version = version) 8215 process_names.append(exporter.process_name) 8216 else: 8217 exporter = self._curr_exporter.generate_process_directory(\ 8218 self._curr_matrix_elements, self._curr_helas_model, 8219 process_string = self._generate_info, version = version) 8220 process_names.append(exporter.process_file_name) 8221 8222 # Output the model parameter and ALOHA files 8223 model_name, model_path = exporter.convert_model_to_pythia8(\ 8224 self._curr_model, self._export_dir) 8225 8226 # Generate the main program file 8227 filename, make_filename = \ 8228 self._curr_exporter.generate_example_file_pythia8(path, 8229 model_path, 8230 process_names, 8231 exporter, 8232 main_file_name) 8233 8234 8235 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8236 # Just the matrix.f files 8237 if self._export_format == 'matrix': 8238 for me in matrix_elements: 8239 filename = pjoin(path, 'matrix_' + \ 8240 me.get('processes')[0].shell_string() + ".f") 8241 if os.path.isfile(filename): 8242 logger.warning("Overwriting existing file %s" % filename) 8243 else: 8244 logger.info("Creating new file %s" % filename) 8245 calls = calls + self._curr_exporter.write_matrix_element_v4(\ 8246 writers.FortranWriter(filename),\ 8247 me, self._curr_helas_model) 8248 elif self._export_format in ['madevent', 'pythia8']: 8249 pass 8250 # grouping mode 8251 elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\ 8252 self._curr_exporter.grouped_mode: 8253 modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements) 8254 if modify: 8255 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8256 8257 for me_number, me in enumerate(self._curr_matrix_elements): 8258 calls = calls + \ 8259 self._curr_exporter.generate_subprocess_directory(\ 8260 me, self._curr_helas_model, me_number) 8261 8262 # ungroup mode 8263 else: 8264 for nb,me in enumerate(matrix_elements[:]): 8265 new_calls = self._curr_exporter.generate_subprocess_directory(\ 8266 me, self._curr_helas_model, nb) 8267 if isinstance(new_calls, int): 8268 if new_calls ==0: 8269 matrix_elements.remove(me) 8270 else: 8271 calls = calls + new_calls 8272 8273 if self._generate_info and hasattr(self._curr_exporter, 'write_procdef_mg5'): 8274 # Write the procdef_mg5.dat file with process info 8275 card_path = pjoin(self._export_dir ,'SubProcesses', \ 8276 'procdef_mg5.dat') 8277 self._curr_exporter.write_procdef_mg5(card_path, 8278 self._curr_model['name'], 8279 self._generate_info) 8280 8281 8282 cpu_time2 = time.time() - cpu_time1 8283 8284 logger.info(("Generated helas calls for %d subprocesses " + \ 8285 "(%d diagrams) in %0.3f s") % \ 8286 (len(matrix_elements), 8287 ndiags, cpu_time)) 8288 8289 if calls: 8290 if "cpu_time2" in locals(): 8291 logger.info("Wrote files for %d helas calls in %0.3f s" % \ 8292 (calls, cpu_time2)) 8293 else: 8294 logger.info("Wrote files for %d helas calls" % \ 8295 (calls)) 8296 8297 if self._export_format == 'pythia8': 8298 logger.info("- All necessary files for Pythia 8 generated.") 8299 logger.info("- Run \"launch\" and select %s.cc," % filename) 8300 logger.info(" or go to %s/examples and run" % path) 8301 logger.info(" make -f %s" % make_filename) 8302 logger.info(" (with process_name replaced by process name).") 8303 logger.info(" You can then run ./%s to produce events for the process" % \ 8304 filename) 8305 8306 # Replace the amplitudes with the actual amplitudes from the 8307 # matrix elements, which allows proper diagram drawing also of 8308 # decay chain processes 8309 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8310 self._curr_amps = diagram_generation.AmplitudeList(\ 8311 [me.get('base_amplitude') for me in \ 8312 matrix_elements]) 8313
8314 - def finalize(self, nojpeg, online = False, flaglist=[]):
8315 """Make the html output, write proc_card_mg5.dat and create 8316 madevent.tar.gz for a MadEvent directory""" 8317 8318 compiler_dict = {'fortran': self.options['fortran_compiler'], 8319 'cpp': self.options['cpp_compiler'], 8320 'f2py': self.options['f2py_compiler']} 8321 8322 # Handling of the model. 8323 if self._model_v4_path: 8324 logger.info('Copy %s model files to directory %s' % \ 8325 (os.path.basename(self._model_v4_path), self._export_dir)) 8326 self._curr_exporter.export_model_files(self._model_v4_path) 8327 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS')) 8328 else: 8329 # wanted_lorentz are the lorentz structures which are 8330 # actually used in the wavefunctions and amplitudes in 8331 # these processes 8332 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 8333 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 8334 8335 if self._export_format == 'madevent' and not 'no_helrecycling' in flaglist: 8336 for (name, flag, out) in wanted_lorentz[:]: 8337 if out == 0: 8338 newflag = list(flag) + ['P1N'] 8339 wanted_lorentz.append((name, tuple(newflag), -1)) 8340 8341 # For a unique output of multiple type of exporter need to store this 8342 # information. 8343 if hasattr(self, 'previous_lorentz'): 8344 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz)) 8345 wanted_couplings = list(set(self.previous_couplings + wanted_couplings)) 8346 del self.previous_lorentz 8347 del self.previous_couplings 8348 if 'store_model' in flaglist: 8349 self.previous_lorentz = wanted_lorentz 8350 self.previous_couplings = wanted_couplings 8351 else: 8352 self._curr_exporter.convert_model(self._curr_model, 8353 wanted_lorentz, 8354 wanted_couplings) 8355 8356 # move the old options to the flaglist system. 8357 if nojpeg: 8358 flaglist.append('nojpeg') 8359 if online: 8360 flaglist.append('online') 8361 8362 8363 8364 if self._export_format in ['NLO']: 8365 ## write fj_lhapdf_opts file 8366 # Create configuration file [path to executable] for amcatnlo 8367 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt') 8368 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path', 8369 'hepmc_path'] 8370 to_keep = {} 8371 for opt in opts_to_keep: 8372 if self.options[opt]: 8373 to_keep[opt] = self.options[opt] 8374 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \ 8375 to_keep = to_keep) 8376 8377 elif self._export_format in ['madevent', 'madweight']: 8378 # Create configuration file [path to executable] for madevent 8379 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt') 8380 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, 8381 to_keep={'mg5_path':MG5DIR}) 8382 8383 # Dedicated finalize function. 8384 self._curr_exporter.finalize(self._curr_matrix_elements, 8385 self.history, 8386 self.options, 8387 flaglist) 8388 8389 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']: 8390 logger.info('Output to directory ' + self._export_dir + ' done.') 8391 8392 if self._export_format in ['madevent', 'NLO']: 8393 logger.info('Type \"launch\" to generate events from this process, or see') 8394 logger.info(self._export_dir + '/README') 8395 logger.info('Run \"open index.html\" to see more information about this process.')
8396
8397 - def do_help(self, line):
8398 """ propose some usefull possible action """ 8399 8400 super(MadGraphCmd,self).do_help(line) 8401 8402 if line: 8403 return 8404 8405 if len(self.history) == 0: 8406 last_action_2 = 'mg5_start' 8407 last_action = 'mg5_start' 8408 else: 8409 args = self.history[-1].split() 8410 last_action = args[0] 8411 if len(args)>1: 8412 last_action_2 = '%s %s' % (last_action, args[1]) 8413 else: 8414 last_action_2 = 'none'
8415 8416 8417 8418 # Calculate decay width
8419 - def do_compute_widths(self, line, model=None, do2body=True, decaymodel=None):
8420 """Documented commands:Generate amplitudes for decay width calculation, with fixed 8421 number of final particles (called level) 8422 syntax; compute_widths particle [other particles] [--options=] 8423 8424 - particle/other particles can also be multiparticle name (can also be 8425 pid of the particle) 8426 8427 --body_decay=X [default=4.0025] allow to choose the precision. 8428 if X is an integer: compute all X body decay 8429 if X is a float <1: compute up to the time that total error < X 8430 if X is a float >1: stops at the first condition. 8431 8432 --path=X. Use a given file for the param_card. (default UFO built-in) 8433 8434 special argument: 8435 - skip_2body: allow to not consider those decay (use FR) 8436 - model: use the model pass in argument. 8437 8438 """ 8439 8440 8441 8442 self.change_principal_cmd('MadGraph') 8443 if '--nlo' not in line: 8444 warning_text = """Please note that the automatic computation of the width is 8445 only valid in narrow-width approximation and at tree-level.""" 8446 logger.warning(warning_text) 8447 8448 if not model: 8449 modelname = self._curr_model.get('modelpath+restriction') 8450 with misc.MuteLogger(['madgraph'], ['INFO']): 8451 model = import_ufo.import_model(modelname, decay=True) 8452 self._curr_model = model 8453 8454 if not isinstance(model, model_reader.ModelReader): 8455 model = model_reader.ModelReader(model) 8456 8457 if '--nlo' in line: 8458 # call SMWidth to calculate NLO Width 8459 self.compute_widths_SMWidth(line, model=model) 8460 return 8461 8462 # check the argument and return those in a dictionary format 8463 particles, opts = self.check_compute_widths(self.split_arg(line)) 8464 8465 if opts['path']: 8466 correct = True 8467 param_card = check_param_card.ParamCard(opts['path']) 8468 for param in param_card['decay']: 8469 if param.value == "auto": 8470 param.value = 1 8471 param.format = 'float' 8472 correct = False 8473 if not correct: 8474 if opts['output']: 8475 param_card.write(opts['output']) 8476 opts['path'] = opts['output'] 8477 else: 8478 param_card.write(opts['path']) 8479 8480 data = model.set_parameters_and_couplings(opts['path']) 8481 8482 8483 # find UFO particles linked to the require names. 8484 if do2body: 8485 skip_2body = True 8486 decay_info = {} 8487 for pid in particles: 8488 particle = model.get_particle(pid) 8489 if not hasattr(particle, 'partial_widths'): 8490 skip_2body = False 8491 break 8492 elif not decay_info: 8493 logger_mg.info('Get two body decay from FeynRules formula') 8494 decay_info[pid] = [] 8495 mass = abs(eval(str(particle.get('mass')), data).real) 8496 data = model.set_parameters_and_couplings(opts['path'], scale= mass) 8497 total = 0 8498 8499 # check if the value of alphas is set to zero and raise warning if appropriate 8500 if 'aS' in data and data['aS'] == 0 and particle.get('color') != 1: 8501 logger.warning("aS set to zero for this particle since the running is not defined for such low mass.") 8502 8503 for mode, expr in particle.partial_widths.items(): 8504 tmp_mass = mass 8505 for p in mode: 8506 try: 8507 value_mass = eval(str(p.mass), data) 8508 except Exception: 8509 # the p object can still be UFO reference. since the 8510 # mass name might hve change load back the MG5 one. 8511 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data) 8512 tmp_mass -= abs(value_mass) 8513 if tmp_mass <=0: 8514 continue 8515 8516 decay_to = [p.get('pdg_code') for p in mode] 8517 value = eval(expr,{'cmath':cmath},data).real 8518 if -1e-10 < value < 0: 8519 value = 0 8520 if -1e-5 < value < 0: 8521 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' % 8522 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 8523 value = 0 8524 elif value < 0: 8525 raise Exception('Partial width for %s > %s negative: %s' % \ 8526 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 8527 elif 0 < value < 0.1 and particle['color'] !=1: 8528 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 8529 % (particle.get('name'), value, decay_to)) 8530 value = 0 8531 8532 decay_info[particle.get('pdg_code')].append([decay_to, value]) 8533 total += value 8534 else: 8535 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 8536 opts['path'], opts['output']) 8537 if float(opts['body_decay']) == 2: 8538 return decay_info 8539 else: 8540 skip_2body = True 8541 8542 # 8543 # add info from decay module 8544 # 8545 8546 self.do_decay_diagram('%s %s' % (' '.join([repr(id) for id in particles]), 8547 ' '.join('--%s=%s' % (key,value) 8548 for key,value in opts.items() 8549 if key not in ['precision_channel']) 8550 ), skip_2body=skip_2body, model=decaymodel) 8551 8552 if self._curr_amps: 8553 logger.info('Pass to numerical integration for computing the widths:') 8554 else: 8555 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output']) 8556 8557 8558 8559 return decay_info 8560 8561 # Do the MadEvent integration!! 8562 with misc.TMP_directory(dir=os.getcwd()) as path: 8563 decay_dir = pjoin(path,'temp_decay') 8564 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir)) 8565 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]): 8566 self.exec_cmd('output madevent %s -f' % decay_dir,child=False) 8567 8568 #modify some parameter of the default run_card 8569 run_card = banner_module.RunCard(pjoin(decay_dir,'Cards','run_card.dat')) 8570 if run_card['ickkw']: 8571 run_card['ickkw'] = 0 8572 run_card['xqcut'] = 0 8573 run_card.remove_all_cut() 8574 run_card.write(pjoin(decay_dir,'Cards','run_card.dat')) 8575 8576 # Need to write the correct param_card in the correct place !!! 8577 if os.path.exists(opts['output']): 8578 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 8579 else: 8580 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 8581 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 8582 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat')) 8583 # call a ME interface and define as it as child for correct error handling 8584 me_cmd = madevent_interface.MadEventCmd(decay_dir) 8585 for name, val in self.options.items(): 8586 if name in me_cmd.options and me_cmd.options[name] != val: 8587 self.exec_cmd('set %s %s --no_save' % (name, val)) 8588 #me_cmd.options.update(self.options) 8589 #me_cmd.configure_run_mode(self.options['run_mode']) 8590 #self.define_child_cmd_interface(me_cmd, interface=False) 8591 me_cmd.model_name = self._curr_model['name'] #needed for mssm 8592 me_cmd.options['automatic_html_opening'] = False 8593 8594 me_opts=[('accuracy', opts['precision_channel']), # default 0.01 8595 ('points', 1000), 8596 ('iterations',9)] 8597 me_cmd.exec_cmd('survey decay -f %s' % ( 8598 " ".join(['--%s=%s' % val for val in me_opts])), 8599 postcmd=False) 8600 me_cmd.exec_cmd('combine_events', postcmd=False) 8601 #me_cmd.exec_cmd('store_events', postcmd=False) 8602 me_cmd.collect_decay_widths() 8603 me_cmd.do_quit('') 8604 # cleaning 8605 del me_cmd 8606 8607 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat')) 8608 8609 for pid in particles: 8610 width = param['decay'].get((pid,)).value 8611 particle = self._curr_model.get_particle(pid) 8612 #if particle['color'] !=1 and 0 < width.real < 0.1: 8613 # logger.warning("width of colored particle \"%s(%s)\" lower than QCD scale: %s. Set width to zero " 8614 # % (particle.get('name'), pid, width.real)) 8615 # width = 0 8616 8617 8618 if not pid in param['decay'].decay_table: 8619 continue 8620 if pid not in decay_info: 8621 decay_info[pid] = [] 8622 for BR in param['decay'].decay_table[pid]: 8623 if len(BR.lhacode) == 3 and skip_2body: 8624 continue 8625 if 0 < BR.value * width <0.1 and particle['color'] !=1: 8626 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 8627 % (particle.get('name'), BR.value * width, BR.lhacode[1:])) 8628 8629 continue 8630 8631 decay_info[pid].append([BR.lhacode[1:], BR.value * width]) 8632 8633 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 8634 opts['path'], opts['output']) 8635 8636 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 8637 check_param_card.convert_to_slha1(opts['output']) 8638 return decay_info
8639 8640 8641 8642 # Calculate decay width with SMWidth
8643 - def compute_widths_SMWidth(self, line, model=None):
8644 """Compute widths with SMWidth. 8645 """ 8646 8647 # check the argument and return those in a dictionary format 8648 particles, opts = self.check_compute_widths(self.split_arg(line)) 8649 8650 if opts['path']: 8651 correct = True 8652 param_card = check_param_card.ParamCard(opts['path']) 8653 for param in param_card['decay']: 8654 if param.value == "auto": 8655 param.value = 1 8656 param.format = 'float' 8657 correct = False 8658 if not correct: 8659 if opts['output']: 8660 param_card.write(opts['output']) 8661 opts['path'] = opts['output'] 8662 else: 8663 param_card.write(opts['path']) 8664 8665 if not model: 8666 model_path = self._curr_model.get('modelpath') 8667 model_name = self._curr_model.get('name') 8668 currmodel = self._curr_model 8669 else: 8670 model_path = model.get('modelpath') 8671 model_name = model.get('name') 8672 currmodel = model 8673 8674 if not os.path.exists(pjoin(model_path, 'SMWidth')): 8675 raise self.InvalidCmd("Model %s is not valid for computing NLO width with SMWidth"%model_name) 8676 8677 # determine the EW scheme 8678 externparam = [(param.lhablock.lower(),param.name.lower()) for param \ 8679 in currmodel.get('parameters')[('external',)]] 8680 8681 if ('sminputs','aewm1') in externparam: 8682 # alpha(MZ) scheme 8683 arg2 = "1" 8684 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam: 8685 # Gmu scheme 8686 arg2 = "2" 8687 else: 8688 raise Exception("Do not know the EW scheme in the model %s"%model_name) 8689 8690 #compile the code 8691 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')): 8692 logger.info('Compiling SMWidth. This has to be done only once and'+\ 8693 ' can take a couple of minutes.','$MG:BOLD') 8694 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth', 8695 'makefile_MW5')) 8696 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \ 8697 self.options_configuration['fortran_compiler'] 8698 if current != new: 8699 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current) 8700 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current) 8701 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current) 8702 misc.compile(cwd=pjoin(model_path, 'SMWidth')) 8703 8704 # look for the ident_card.dat 8705 identpath=" " 8706 carddir=os.path.dirname(opts['path']) 8707 if 'ident_card.dat' in os.listdir(carddir): 8708 identpath=pjoin(carddir,'ident_card.dat') 8709 #run the code 8710 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2], 8711 stdout=subprocess.PIPE, 8712 stdin=subprocess.PIPE, 8713 cwd=pjoin(model_path, 'SMWidth')).communicate() 8714 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I) 8715 width_list = pattern.findall(output.decode()) 8716 width_dict = {} 8717 for pid,width in width_list: 8718 width_dict[int(pid)] = float(width) 8719 8720 for pid in particles: 8721 if not pid in width_dict: 8722 width = 0 8723 else: 8724 width = width_dict[pid] 8725 param = param_card['decay'].get((pid,)) 8726 param.value = width 8727 param.format = 'float' 8728 if pid not in param_card['decay'].decay_table: 8729 continue 8730 del param_card['decay'].decay_table[pid] # reset the BR 8731 # write the output file. (the new param_card) 8732 if opts['output']: 8733 param_card.write(opts['output']) 8734 logger.info('Results are written in %s' % opts['output']) 8735 else: 8736 param_card.write(opts['path']) 8737 logger.info('Results are written in %s' % opts['path']) 8738 return
8739 8740 # Calculate decay width
8741 - def do_decay_diagram(self, line, skip_2body=False, model=None):
8742 """Not in help: Generate amplitudes for decay width calculation, with fixed 8743 number of final particles (called level) 8744 syntax; decay_diagram part_name level param_path 8745 args; part_name level param_path 8746 part_name = name of the particle you want to calculate width 8747 level = a.) when level is int, 8748 it means the max number of decay products 8749 b.) when level is float, 8750 it means the required precision for width. 8751 param_path = path for param_card 8752 (this is necessary to determine whether a channel is onshell or not) 8753 e.g. calculate width for higgs up to 2-body decays. 8754 calculate_width h 2 [path] 8755 N.B. param_card must be given so that the program knows which channel 8756 is on shell and which is not. 8757 8758 special argument: 8759 - skip_2body: allow to not consider those decay (use FR) 8760 - model: use the model pass in argument. 8761 """ 8762 8763 if model: 8764 self._curr_decaymodel = model 8765 8766 8767 args = self.split_arg(line) 8768 #check the validity of the arguments 8769 particles, args = self.check_decay_diagram(args) 8770 #print args 8771 pids = particles 8772 level = float(args['body_decay']) 8773 param_card_path = args['path'] 8774 min_br = float(args['min_br']) 8775 8776 # Reset amplitudes 8777 self._curr_amps = diagram_generation.AmplitudeList() 8778 self._curr_proc_defs = base_objects.ProcessDefinitionList() 8779 # Reset Helas matrix elements 8780 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 8781 # Reset _done_export, since we have new process 8782 self._done_export = False 8783 # Also reset _export_format and _export_dir 8784 self._export_format = None 8785 8786 8787 # Setup before find_channels 8788 if not model: 8789 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model, 8790 True) 8791 self._curr_decaymodel.read_param_card(param_card_path) 8792 else: 8793 self._curr_decaymodel = model 8794 model = self._curr_decaymodel 8795 8796 if isinstance(pids, int): 8797 pids = [pids] 8798 8799 first =True 8800 for part_nb,pid in enumerate(pids): 8801 part = self._curr_decaymodel.get_particle(pid) 8802 if part.get('width').lower() == 'zero': 8803 continue 8804 logger_mg.info('get decay diagram for %s' % part['name']) 8805 # Find channels as requested 8806 if level // 1 == level and level >1: 8807 level = int(level) 8808 self._curr_decaymodel.find_channels(part, level, min_br) 8809 if not skip_2body: 8810 amp = part.get_amplitudes(2) 8811 if amp: 8812 self._curr_amps.extend(amp) 8813 8814 for l in range(3, level+1): 8815 amp = part.get_amplitudes(l) 8816 if amp: 8817 self._curr_amps.extend(amp) 8818 else: 8819 max_level = level // 1 8820 if max_level < 2: 8821 max_level = 999 8822 precision = level % 1 8823 if first: 8824 model.find_all_channels(2,generate_abstract=False) 8825 first = False 8826 if not skip_2body: 8827 amp = part.get_amplitudes(2) 8828 if amp: 8829 self._curr_amps.extend(amp) 8830 clevel = 2 8831 while part.get('apx_decaywidth_err').real > precision: 8832 clevel += 1 8833 if clevel > max_level: 8834 logger_mg.info(' stop to %s body-decay. approximate error: %s' % 8835 (max_level, part.get('apx_decaywidth_err')) ) 8836 break 8837 if clevel > 3: 8838 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\ 8839 (part.get('apx_decaywidth_err'), clevel)) 8840 part.find_channels_nextlevel(model, min_br) 8841 #part.group_channels_2_amplitudes(clevel, model, min_br) 8842 amp = part.get_amplitudes(clevel) 8843 if amp: 8844 self._curr_amps.extend(amp) 8845 part.update_decay_attributes(False, True, True, model) 8846 8847 8848 # Set _generate_info 8849 if len(self._curr_amps) > 0: 8850 process = self._curr_amps[0]['process'].nice_string() 8851 #print process 8852 self._generate_info = process[9:] 8853 #print self._generate_info 8854 else: 8855 logger.info("No decay is found")
8856
8857 -class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd):
8858 """Temporary parser"""
8859 8860 #=============================================================================== 8861 # Command Parser 8862 #=============================================================================== 8863 # DRAW 8864 _draw_usage = "draw FILEPATH [options]\n" + \ 8865 "-- draw the diagrams in eps format\n" + \ 8866 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \ 8867 " Example: draw plot_dir . \n" 8868 _draw_parser = misc.OptionParser(usage=_draw_usage) 8869 _draw_parser.add_option("", "--horizontal", default=False, 8870 action='store_true', help="force S-channel to be horizontal") 8871 _draw_parser.add_option("", "--external", default=0, type='float', 8872 help="authorizes external particles to end at top or " + \ 8873 "bottom of diagram. If bigger than zero this tune the " + \ 8874 "length of those line.") 8875 _draw_parser.add_option("", "--max_size", default=1.5, type='float', 8876 help="this forbids external line bigger than max_size") 8877 _draw_parser.add_option("", "--non_propagating", default=True, \ 8878 dest="contract_non_propagating", action='store_false', 8879 help="avoid contractions of non propagating lines") 8880 _draw_parser.add_option("", "--add_gap", default=0, type='float', \ 8881 help="set the x-distance between external particles") 8882 8883 # LAUNCH PROGRAM 8884 _launch_usage = "launch [DIRPATH] [options]\n" + \ 8885 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \ 8886 " By default DIRPATH is the latest created directory \n" + \ 8887 " (for pythia8, it should be the Pythia 8 main directory) \n" + \ 8888 " Example: launch PROC_sm_1 --name=run2 \n" + \ 8889 " Example: launch ../pythia8 \n" 8890 _launch_parser = misc.OptionParser(usage=_launch_usage) 8891 _launch_parser.add_option("-f", "--force", default=False, action='store_true', 8892 help="Use the card present in the directory in order to launch the different program") 8893 _launch_parser.add_option("-n", "--name", default='', type='str', 8894 help="Provide a name to the run (for madevent run)") 8895 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true', 8896 help="submit the job on the cluster") 8897 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true', 8898 help="submit the job on multicore core") 8899 8900 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true', 8901 help="Use Interactive Console [if available]") 8902 _launch_parser.add_option("-s", "--laststep", default='', 8903 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]") 8904 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true', 8905 help="Run the reweight module (reweighting by different model parameter") 8906 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', 8907 help="Run the madspin package")
8908 8909 #=============================================================================== 8910 # Interface for customize question. 8911 #=============================================================================== 8912 -class AskforCustomize(cmd.SmartQuestion):
8913 """A class for asking a question where in addition you can have the 8914 set command define and modifying the param_card/run_card correctly""" 8915
8916 - def __init__(self, question, allow_arg=[], default=None, 8917 mother_interface=None, *arg, **opt):
8918 8919 model_path = mother_interface._curr_model.get('modelpath') 8920 #2) Import the option available in the model 8921 ufo_model = ufomodels.load_model(model_path) 8922 self.all_categories = ufo_model.build_restrict.all_categories 8923 8924 question = self.get_question() 8925 # determine the possible value and how they are linked to the restriction 8926 #options. 8927 allow_arg = ['0'] 8928 self.name2options = {} 8929 for category in self.all_categories: 8930 for options in category: 8931 if not options.first: 8932 continue 8933 self.name2options[str(len(allow_arg))] = options 8934 self.name2options[options.name.replace(' ','')] = options 8935 allow_arg.append(len(allow_arg)) 8936 allow_arg.append('done') 8937 8938 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8939 8940 8941
8942 - def default(self, line):
8943 """Default action if line is not recognized""" 8944 8945 line = line.strip() 8946 args = line.split() 8947 if line == '' and self.default_value is not None: 8948 self.value = self.default_value 8949 # check if input is a file 8950 elif hasattr(self, 'do_%s' % args[0]): 8951 self.do_set(' '.join(args[1:])) 8952 elif line.strip() != '0' and line.strip() != 'done' and \ 8953 str(line) != 'EOF' and line.strip() in self.allow_arg: 8954 option = self.name2options[line.strip()] 8955 option.status = not option.status 8956 self.value = 'repeat' 8957 else: 8958 self.value = line 8959 8960 return self.all_categories
8961
8962 - def reask(self, reprint_opt=True):
8963 """ """ 8964 reprint_opt = True 8965 self.question = self.get_question() 8966 cmd.SmartQuestion.reask(self, reprint_opt)
8967
8968 - def do_set(self, line):
8969 """ """ 8970 self.value = 'repeat' 8971 8972 args = line.split() 8973 if args[0] not in self.name2options: 8974 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' % 8975 (args[0], ', '.join(list(self.name2options.keys())) )) 8976 return 8977 elif len(args) != 2: 8978 logger.warning('Invalid set command. Not correct number of argument') 8979 return 8980 8981 8982 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']: 8983 self.name2options[args[0]].status = True 8984 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']: 8985 self.name2options[args[0]].status = False 8986 else: 8987 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8988 8989 8990
8991 - def get_question(self):
8992 """define the current question.""" 8993 question = '' 8994 i=0 8995 for category in self.all_categories: 8996 question += category.name + ':\n' 8997 for options in category: 8998 if not options.first: 8999 continue 9000 i+=1 9001 question += ' %s: %s [%s]\n' % (i, options.name, 9002 options.display(options.status)) 9003 question += 'Enter a number to change it\'s status or press enter to validate.\n' 9004 question += 'For scripting this function, please type: \'help\'' 9005 return question
9006 9007
9008 - def complete_set(self, text, line, begidx, endidx):
9009 """ Complete the set command""" 9010 signal.alarm(0) # avoid timer if any 9011 args = self.split_arg(line[0:begidx]) 9012 9013 if len(args) == 1: 9014 possibilities = [x for x in self.name2options if not x.isdigit()] 9015 return self.list_completion(text, possibilities, line) 9016 else: 9017 return self.list_completion(text,['True', 'False'], line)
9018 9019
9020 - def do_help(self, line):
9021 '''help message''' 9022 9023 print('This allows you to optimize your model to your needs.') 9024 print('Enter the number associate to the possible restriction/add-on') 9025 print(' to change the status of this restriction/add-on.') 9026 print('') 9027 print('In order to allow scripting of this function you can use the ') 9028 print('function \'set\'. This function takes two argument:') 9029 print('set NAME VALUE') 9030 print(' NAME is the description of the option where you remove all spaces') 9031 print(' VALUE is either True or False') 9032 print(' Example: For the question') 9033 print(''' sm customization: 9034 1: diagonal ckm [True] 9035 2: c mass = 0 [True] 9036 3: b mass = 0 [False] 9037 4: tau mass = 0 [False] 9038 5: muon mass = 0 [True] 9039 6: electron mass = 0 [True] 9040 Enter a number to change it's status or press enter to validate.''') 9041 print(''' you can answer by''') 9042 print(' set diagonalckm False') 9043 print(' set taumass=0 True')
9044
9045 - def cmdloop(self, intro=None):
9046 cmd.SmartQuestion.cmdloop(self, intro) 9047 return self.all_categories
9048 9049 9050 9051 #=============================================================================== 9052 # __main__ 9053 #=============================================================================== 9054 9055 if __name__ == '__main__': 9056 9057 run_option = sys.argv 9058 if len(run_option) > 1: 9059 # The first argument of sys.argv is the name of the program 9060 input_file = open(run_option[1], 'rU') 9061 cmd_line = MadGraphCmd(stdin=input_file) 9062 cmd_line.use_rawinput = False #put it in non interactive mode 9063 cmd_line.cmdloop() 9064 else: 9065 # Interactive mode 9066 MadGraphCmd().cmdloop() 9067