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