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 } 2813 2814 options_madgraph= {'group_subprocesses': 'Auto', 2815 'ignore_six_quark_processes': False, 2816 'low_mem_multicore_nlo_generation': False, 2817 'complex_mass_scheme': False, 2818 'gauge':'unitary', 2819 'stdout_level':None, 2820 'loop_optimized_output':True, 2821 'loop_color_flows':False, 2822 'max_npoint_for_channel': 0 # 0 means automaticly adapted 2823 } 2824 2825 options_madevent = {'automatic_html_opening':True, 2826 'run_mode':2, 2827 'nb_core': None, 2828 'notification_center': True 2829 } 2830 2831 2832 # Variables to store object information 2833 _curr_model = None #base_objects.Model() 2834 _curr_amps = diagram_generation.AmplitudeList() 2835 _curr_proc_defs = base_objects.ProcessDefinitionList() 2836 _curr_matrix_elements = helas_objects.HelasMultiProcess() 2837 _curr_helas_model = None 2838 _curr_exporter = None 2839 _done_export = False 2840 _curr_decaymodel = None 2841 2842 helporder = ['Main commands', 'Documented commands'] 2843 2844
2845 - def preloop(self):
2846 """Initializing before starting the main loop""" 2847 2848 self.prompt = 'MG5_aMC>' 2849 if madgraph.ReadWrite: # prevent on read-only disk 2850 self.do_install('update --mode=mg5_start') 2851 2852 # By default, load the UFO Standard Model 2853 logger.info("Loading default model: sm") 2854 self.exec_cmd('import model sm', printcmd=False, precmd=True) 2855 2856 # preloop mother 2857 CmdExtended.preloop(self)
2858 2859
2860 - def __init__(self, mgme_dir = '', *completekey, **stdin):
2861 """ add a tracker of the history """ 2862 2863 CmdExtended.__init__(self, *completekey, **stdin) 2864 2865 # Set MG/ME directory path 2866 if mgme_dir: 2867 if os.path.isdir(pjoin(mgme_dir, 'Template')): 2868 self._mgme_dir = mgme_dir 2869 logger.info('Setting MG/ME directory to %s' % mgme_dir) 2870 else: 2871 logger.warning('Warning: Directory %s not valid MG/ME directory' % \ 2872 mgme_dir) 2873 self._mgme_dir = MG4DIR 2874 2875 # check that make_opts exists 2876 make_opts = pjoin(MG5DIR, 'Template','LO','Source','make_opts') 2877 make_opts_source = pjoin(MG5DIR, 'Template','LO','Source','.make_opts') 2878 if not os.path.exists(make_opts): 2879 shutil.copy(make_opts_source, make_opts) 2880 elif os.path.getmtime(make_opts) < os.path.getmtime(make_opts_source): 2881 shutil.copy(make_opts_source, make_opts) 2882 2883 # Variables to store state information 2884 self._multiparticles = {} 2885 self.options = {} 2886 self._generate_info = "" # store the first generated process 2887 self._model_v4_path = None 2888 self._export_dir = None 2889 self._export_format = 'madevent' 2890 self._mgme_dir = MG4DIR 2891 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools')) 2892 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src')) 2893 self._comparisons = None 2894 self._cms_checks = [] 2895 self._nlo_modes_for_completion = ['all','virt','real','LOonly'] 2896 2897 # Load the configuration file,i.e.mg5_configuration.txt 2898 self.set_configuration()
2899
2900 - def setup(self):
2901 """ Actions to carry when switching to this interface """ 2902 2903 # Refresh all the interface stored value as things like generated 2904 # processes and amplitudes are not to be reused in between different 2905 # interfaces 2906 # Clear history, amplitudes and matrix elements when a model is imported 2907 # Remove previous imports, generations and outputs from history 2908 self.history.clean(remove_bef_last='import',keep_switch=True) 2909 # Reset amplitudes and matrix elements 2910 self._done_export=False 2911 self._curr_amps = diagram_generation.AmplitudeList() 2912 self._curr_proc_defs = base_objects.ProcessDefinitionList() 2913 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 2914 2915 self._v4_export_formats = ['madevent', 'standalone','standalone_msP','standalone_msF', 2916 'matrix', 'standalone_rw'] 2917 self._export_formats = self._v4_export_formats + ['standalone_cpp', 'pythia8'] 2918 self._nlo_modes_for_completion = ['all','virt','real']
2919
2920 - def do_quit(self, line):
2921 """Not in help: Do quit""" 2922 2923 if self._done_export and \ 2924 os.path.exists(pjoin(self._done_export[0],'RunWeb')): 2925 os.remove(pjoin(self._done_export[0],'RunWeb')) 2926 2927 value = super(MadGraphCmd, self).do_quit(line) 2928 if madgraph.ReadWrite: #prevent to run on Read Only disk 2929 self.do_install('update --mode=mg5_end') 2930 print 2931 2932 misc.EasterEgg('quit') 2933 2934 2935 return value
2936 2937 # Add a process to the existing multiprocess definition 2938 # Generate a new amplitude
2939 - def do_add(self, line):
2940 """Generate an amplitude for a given process and add to 2941 existing amplitudes 2942 or merge two model 2943 """ 2944 2945 args = self.split_arg(line) 2946 2947 2948 warning_duplicate = True 2949 if '--no_warning=duplicate' in args: 2950 warning_duplicate = False 2951 args.remove('--no_warning=duplicate') 2952 2953 diagram_filter = False 2954 if '--diagram_filter' in args: 2955 diagram_filter = True 2956 args.remove('--diagram_filter') 2957 2958 standalone_only = False 2959 if '--standalone' in args: 2960 standalone_only = True 2961 args.remove('--standalone') 2962 2963 # Check the validity of the arguments 2964 self.check_add(args) 2965 2966 if args[0] == 'model': 2967 return self.add_model(args[1:]) 2968 2969 # special option for 1->N to avoid generation of kinematically forbidden 2970 #decay. 2971 if args[-1].startswith('--optimize'): 2972 optimize = True 2973 args.pop() 2974 else: 2975 optimize = False 2976 2977 if args[0] == 'process': 2978 # Rejoin line 2979 line = ' '.join(args[1:]) 2980 2981 # store the first process (for the perl script) 2982 if not self._generate_info: 2983 self._generate_info = line 2984 2985 # Reset Helas matrix elements 2986 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 2987 2988 # Extract process from process definition 2989 if ',' in line: 2990 if ']' in line or '[' in line: 2991 error_msg=\ 2992 """The '[' and ']' syntax cannot be used in cunjunction with decay chains. 2993 This implies that with decay chains: 2994 > Squared coupling order limitations are not available. 2995 > Loop corrections cannot be considered.""" 2996 raise MadGraph5Error(error_msg) 2997 else: 2998 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 2999 myprocdef, line = self.extract_decay_chain_process(line, proc_number=nb_proc) 3000 # Redundant with above, but not completely as in the future 3001 # one might think of allowing the core process to be 3002 # corrected by loops. 3003 if myprocdef.are_decays_perturbed(): 3004 raise MadGraph5Error("Decay processes cannot be perturbed.") 3005 # The two limitations below have some redundancy, but once 3006 # again, they might be relieved (one at a time or together) 3007 # int he future. 3008 if myprocdef.decays_have_squared_orders() or \ 3009 myprocdef['squared_orders']!={}: 3010 raise MadGraph5Error("Decay processes cannot specify "+\ 3011 "squared orders constraints.") 3012 if myprocdef.are_negative_orders_present(): 3013 raise MadGraph5Error("Decay processes cannot include negative"+\ 3014 " coupling orders constraints.") 3015 else: 3016 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 3017 myprocdef = self.extract_process(line, proc_number=nb_proc) 3018 3019 3020 3021 # Check that we have something 3022 if not myprocdef: 3023 raise self.InvalidCmd("Empty or wrong format process, please try again.") 3024 # Check that we have the same number of initial states as 3025 # existing processes 3026 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 3027 myprocdef.get_ninitial() and not standalone_only: 3028 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 3029 3030 self._curr_proc_defs.append(myprocdef) 3031 3032 # Negative coupling order contraints can be given on at most one 3033 # coupling order (and either in squared orders or orders, not both) 3034 if len([1 for val in myprocdef.get('orders').values()+\ 3035 myprocdef.get('squared_orders').values() if val<0])>1: 3036 raise MadGraph5Error("Negative coupling order constraints"+\ 3037 " can only be given on one type of coupling and either on"+\ 3038 " squared orders or amplitude orders, not both.") 3039 3040 cpu_time1 = time.time() 3041 3042 # Generate processes 3043 if self.options['group_subprocesses'] == 'Auto': 3044 collect_mirror_procs = True 3045 else: 3046 collect_mirror_procs = self.options['group_subprocesses'] 3047 ignore_six_quark_processes = \ 3048 self.options['ignore_six_quark_processes'] if \ 3049 "ignore_six_quark_processes" in self.options \ 3050 else [] 3051 3052 myproc = diagram_generation.MultiProcess(myprocdef, 3053 collect_mirror_procs = collect_mirror_procs, 3054 ignore_six_quark_processes = ignore_six_quark_processes, 3055 optimize=optimize, diagram_filter=diagram_filter) 3056 3057 3058 for amp in myproc.get('amplitudes'): 3059 if amp not in self._curr_amps: 3060 self._curr_amps.append(amp) 3061 elif warning_duplicate: 3062 raise self.InvalidCmd, "Duplicate process %s found. Please check your processes." % \ 3063 amp.nice_string_processes() 3064 3065 # Reset _done_export, since we have new process 3066 self._done_export = False 3067 3068 cpu_time2 = time.time() 3069 3070 nprocs = len(myproc.get('amplitudes')) 3071 ndiags = sum([amp.get_number_of_diagrams() for \ 3072 amp in myproc.get('amplitudes')]) 3073 3074 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 3075 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 3076 ndiags = sum([amp.get_number_of_diagrams() for \ 3077 amp in self._curr_amps]) 3078 logger.info("Total: %i processes with %i diagrams" % \ 3079 (len(self._curr_amps), ndiags))
3080
3081 - def add_model(self, args):
3082 """merge two model""" 3083 3084 model_path = args[0] 3085 recreate = ('--recreate' in args) 3086 keep_decay = ('--keep_decay' in args) 3087 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')] 3088 if output_dir: 3089 output_dir = output_dir[0] 3090 recreate = True 3091 restrict_name = '' 3092 else: 3093 name = os.path.basename(self._curr_model.get('modelpath')) 3094 restrict_name = self._curr_model.get('restrict_name') 3095 output_dir = pjoin(MG5DIR, 'models', '%s__%s' % (name, 3096 os.path.basename(model_path))) 3097 3098 if os.path.exists(output_dir): 3099 if recreate: 3100 shutil.rmtree(output_dir) 3101 else: 3102 logger.info('Model already created! Loading it from %s' % output_dir) 3103 oldmodel = self._curr_model.get('modelpath') 3104 new_model_name = output_dir 3105 if restrict_name: 3106 new_model_name = '%s-%s' % (output_dir, restrict_name) 3107 try: 3108 self.exec_cmd('import model %s' % new_model_name, errorhandling=False, 3109 printcmd=False, precmd=True, postcmd=True) 3110 except Exception, error: 3111 logger.debug('fail to load model %s with error:\n %s' % (output_dir, error)) 3112 logger.warning('Fail to load the model. Restore previous model') 3113 self.exec_cmd('import model %s' % oldmodel, errorhandling=False, 3114 printcmd=False, precmd=True, postcmd=True) 3115 raise Exception('Invalid Model! Please retry with the option \'--recreate\'.') 3116 else: 3117 return 3118 3119 #Need to do the work!!! 3120 import models.usermod as usermod 3121 base_model = copy.deepcopy(usermod.UFOModel(self._curr_model.get('modelpath'))) 3122 3123 identify = dict(tuple(a.split('=')) for a in args if '=' in a) 3124 base_model.add_model(path=model_path, identify_particles=identify) 3125 base_model.write(output_dir) 3126 3127 if keep_decay and os.path.exists(pjoin(self._curr_model.get('modelpath'), 'decays.py')): 3128 base_model.mod_file(pjoin(pjoin(self._curr_model.get('modelpath'), 'decays.py')), 3129 pjoin(pjoin(output_dir, 'decays.py'))) 3130 3131 new_model_name = output_dir 3132 if restrict_name: 3133 new_model_name = '%s-%s' % (output_dir, restrict_name) 3134 3135 if 'modelname' in self.history.get('full_model_line'): 3136 opts = '--modelname' 3137 else: 3138 opts='' 3139 self.exec_cmd('import model %s %s' % (new_model_name, opts), errorhandling=False, 3140 printcmd=False, precmd=True, postcmd=True)
3141 3142 3143 # Define a multiparticle label
3144 - def do_define(self, line, log=True):
3145 """Define a multiparticle""" 3146 3147 self.avoid_history_duplicate('define %s' % line, ['define']) 3148 if not self._curr_model: 3149 self.do_import('model sm') 3150 self.history.append('define %s' % line) 3151 if not self._curr_model['case_sensitive']: 3152 # Particle names lowercase 3153 line = line.lower() 3154 # Make sure there are spaces around =, | and / 3155 line = line.replace("=", " = ") 3156 line = line.replace("|", " | ") 3157 line = line.replace("/", " / ") 3158 args = self.split_arg(line) 3159 # check the validity of the arguments 3160 self.check_define(args) 3161 3162 label = args[0] 3163 remove_ids = [] 3164 try: 3165 remove_index = args.index("/") 3166 except ValueError: 3167 pass 3168 else: 3169 remove_ids = args[remove_index + 1:] 3170 args = args[:remove_index] 3171 3172 pdg_list = self.extract_particle_ids(args[1:]) 3173 remove_list = self.extract_particle_ids(remove_ids) 3174 pdg_list = [p for p in pdg_list if p not in remove_list] 3175 3176 self.optimize_order(pdg_list) 3177 self._multiparticles[label] = pdg_list 3178 if log: 3179 logger.info("Defined multiparticle %s" % \ 3180 self.multiparticle_string(label))
3181 3182 # Display
3183 - def do_display(self, line, output=sys.stdout):
3184 """Display current internal status""" 3185 3186 args = self.split_arg(line) 3187 #check the validity of the arguments 3188 self.check_display(args) 3189 3190 if args[0] == 'diagrams': 3191 self.draw(' '.join(args[1:])) 3192 3193 if args[0] == 'particles' and len(args) == 1: 3194 propagating_particle = [] 3195 nb_unpropagating = 0 3196 for particle in self._curr_model['particles']: 3197 if particle.get('propagating'): 3198 propagating_particle.append(particle) 3199 else: 3200 nb_unpropagating += 1 3201 3202 print "Current model contains %i particles:" % \ 3203 len(propagating_particle) 3204 part_antipart = [part for part in propagating_particle \ 3205 if not part['self_antipart']] 3206 part_self = [part for part in propagating_particle \ 3207 if part['self_antipart']] 3208 for part in part_antipart: 3209 print part['name'] + '/' + part['antiname'], 3210 print '' 3211 for part in part_self: 3212 print part['name'], 3213 print '' 3214 if nb_unpropagating: 3215 print 'In addition of %s un-physical particle mediating new interactions.' \ 3216 % nb_unpropagating 3217 3218 elif args[0] == 'particles': 3219 for arg in args[1:]: 3220 if arg.isdigit() or (arg[0] == '-' and arg[1:].isdigit()): 3221 particle = self._curr_model.get_particle(abs(int(arg))) 3222 else: 3223 particle = self._curr_model['particles'].find_name(arg) 3224 if not particle: 3225 raise self.InvalidCmd, 'no particle %s in current model' % arg 3226 3227 print "Particle %s has the following properties:" % particle.get_name() 3228 print str(particle) 3229 3230 elif args[0] == 'interactions' and len(args) == 1: 3231 text = "Current model contains %i interactions\n" % \ 3232 len(self._curr_model['interactions']) 3233 for i, inter in enumerate(self._curr_model['interactions']): 3234 text += str(i+1) + ':' 3235 for part in inter['particles']: 3236 if part['is_part']: 3237 text += part['name'] 3238 else: 3239 text += part['antiname'] 3240 text += " " 3241 text += " ".join(order + '=' + str(inter['orders'][order]) \ 3242 for order in inter['orders']) 3243 text += '\n' 3244 pydoc.pager(text) 3245 3246 elif args[0] == 'interactions' and len(args)==2 and args[1].isdigit(): 3247 for arg in args[1:]: 3248 if int(arg) > len(self._curr_model['interactions']): 3249 raise self.InvalidCmd, 'no interaction %s in current model' % arg 3250 if int(arg) == 0: 3251 print 'Special interactions which identify two particles' 3252 else: 3253 print "Interactions %s has the following property:" % arg 3254 print self._curr_model['interactions'][int(arg)-1] 3255 3256 elif args[0] == 'interactions': 3257 request_part = args[1:] 3258 text = '' 3259 for i, inter in enumerate(self._curr_model['interactions']): 3260 present_part = [part['is_part'] and part['name'] or part['antiname'] 3261 for part in inter['particles'] 3262 if (part['is_part'] and part['name'] in request_part) or 3263 (not part['is_part'] and part['antiname'] in request_part)] 3264 if len(present_part) < len(request_part): 3265 continue 3266 # check that all particles are selected at least once 3267 if set(present_part) != set(request_part): 3268 continue 3269 # check if a particle is asked more than once 3270 if len(request_part) > len(set(request_part)): 3271 for p in request_part: 3272 if request_part.count(p) > present_part.count(p): 3273 continue 3274 3275 name = str(i+1) + ' : ' 3276 for part in inter['particles']: 3277 if part['is_part']: 3278 name += part['name'] 3279 else: 3280 name += part['antiname'] 3281 name += " " 3282 text += "\nInteractions %s has the following property:\n" % name 3283 text += str(self._curr_model['interactions'][i]) 3284 3285 text += '\n' 3286 print name 3287 if text =='': 3288 text += 'No matching for any interactions' 3289 pydoc.pager(text) 3290 3291 3292 elif args[0] == 'parameters' and len(args) == 1: 3293 text = "Current model contains %i parameters\n" % \ 3294 sum([len(part) for part in 3295 self._curr_model['parameters'].values()]) 3296 keys = self._curr_model['parameters'].keys() 3297 def key_sort(x, y): 3298 if ('external',) == x: 3299 return -1 3300 elif ('external',) == y: 3301 return +1 3302 elif len(x) < len(y): 3303 return -1 3304 else: 3305 return 1
3306 keys.sort(key_sort) 3307 for key in keys: 3308 item = self._curr_model['parameters'][key] 3309 text += '\nparameter type: %s\n' % str(key) 3310 for value in item: 3311 if hasattr(value, 'expr'): 3312 if value.value is not None: 3313 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3314 else: 3315 text+= ' %s = %s\n' % (value.name, value.expr) 3316 else: 3317 if value.value is not None: 3318 text+= ' %s = %s\n' % (value.name, value.value) 3319 else: 3320 text+= ' %s \n' % (value.name) 3321 pydoc.pager(text) 3322 3323 elif args[0] == 'processes': 3324 for amp in self._curr_amps: 3325 print amp.nice_string_processes() 3326 3327 elif args[0] == 'diagrams_text': 3328 text = "\n".join([amp.nice_string() for amp in self._curr_amps]) 3329 pydoc.pager(text) 3330 3331 elif args[0] == 'multiparticles': 3332 print 'Multiparticle labels:' 3333 for key in self._multiparticles: 3334 print self.multiparticle_string(key) 3335 3336 elif args[0] == 'coupling_order': 3337 hierarchy = self._curr_model['order_hierarchy'].items() 3338 #self._curr_model.get_order_hierarchy().items() 3339 def order(first, second): 3340 if first[1] < second[1]: 3341 return -1 3342 else: 3343 return 1
3344 hierarchy.sort(order) 3345 for order in hierarchy: 3346 print ' %s : weight = %s' % order 3347 3348 elif args[0] == 'couplings' and len(args) == 1: 3349 if self._model_v4_path: 3350 print 'No couplings information available in V4 model' 3351 return 3352 text = '' 3353 text = "Current model contains %i couplings\n" % \ 3354 sum([len(part) for part in 3355 self._curr_model['couplings'].values()]) 3356 keys = self._curr_model['couplings'].keys() 3357 def key_sort(x, y): 3358 if ('external',) == x: 3359 return -1 3360 elif ('external',) == y: 3361 return +1 3362 elif len(x) < len(y): 3363 return -1 3364 else: 3365 return 1 3366 keys.sort(key_sort) 3367 for key in keys: 3368 item = self._curr_model['couplings'][key] 3369 text += '\ncouplings type: %s\n' % str(key) 3370 for value in item: 3371 if value.value is not None: 3372 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3373 else: 3374 text+= ' %s = %s\n' % (value.name, value.expr) 3375 3376 pydoc.pager(text) 3377 3378 elif args[0] == 'couplings': 3379 if self._model_v4_path: 3380 print 'No couplings information available in V4 model' 3381 return 3382 3383 try: 3384 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3385 print 'Note that this is the UFO informations.' 3386 print ' "display couplings" present the actual definition' 3387 print 'prints the current states of mode' 3388 print eval('ufomodel.couplings.%s.nice_string()'%args[1]) 3389 except Exception: 3390 raise self.InvalidCmd, 'no couplings %s in current model' % args[1] 3391 3392 elif args[0] == 'lorentz': 3393 if self._model_v4_path: 3394 print 'No lorentz information available in V4 model' 3395 return 3396 elif len(args) == 1: 3397 raise self.InvalidCmd,\ 3398 'display lorentz require an argument: the name of the lorentz structure.' 3399 return 3400 try: 3401 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3402 print eval('ufomodel.lorentz.%s.nice_string()'%args[1]) 3403 except Exception: 3404 raise self.InvalidCmd, 'no lorentz %s in current model' % args[1] 3405 3406 elif args[0] == 'checks': 3407 outstr = '' 3408 if self._comparisons: 3409 comparisons = self._comparisons[0] 3410 if len(args) > 1 and args[1] == 'failed': 3411 comparisons = [c for c in comparisons if not c['passed']] 3412 outstr += "Process check results:" 3413 for comp in comparisons: 3414 outstr += "\n%s:" % comp['process'].nice_string() 3415 outstr += "\n Phase space point: (px py pz E)" 3416 for i, p in enumerate(comp['momenta']): 3417 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p) 3418 outstr += "\n Permutation values:" 3419 outstr += "\n " + str(comp['values']) 3420 if comp['passed']: 3421 outstr += "\n Process passed (rel. difference %.9e)" % \ 3422 comp['difference'] 3423 else: 3424 outstr += "\n Process failed (rel. difference %.9e)" % \ 3425 comp['difference'] 3426 3427 used_aloha = sorted(self._comparisons[1]) 3428 if used_aloha: 3429 outstr += "\nChecked ALOHA routines:" 3430 for aloha in used_aloha: 3431 aloha_str = aloha[0] 3432 if aloha[1]: 3433 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]]) 3434 aloha_str += "_%d" % aloha[2] 3435 outstr += "\n" + aloha_str 3436 3437 outstr += '\n' 3438 for cms_check in self._cms_checks: 3439 outstr += '*'*102+'\n' 3440 outstr += 'Complex Mass Scheme check:\n' 3441 outstr += ' -> check %s\n'%cms_check['line'] 3442 outstr += '*'*102+'\n' 3443 tmp_options = copy.copy(cms_check['options']) 3444 tmp_options['show_plot']=False 3445 outstr += process_checks.output_complex_mass_scheme( 3446 cms_check['cms_result'], cms_check['output_path'], 3447 tmp_options, self._curr_model) + '\n' 3448 outstr += '*'*102+'\n\n' 3449 pydoc.pager(outstr) 3450 3451 elif args[0] == 'options': 3452 if len(args) == 1: 3453 to_print = lambda name: True 3454 else: 3455 to_print = lambda name: any(poss in name for poss in args[1:]) 3456 3457 outstr = " MadGraph5_aMC@NLO Options \n" 3458 outstr += " ---------------- \n" 3459 keys = self.options_madgraph.keys() 3460 keys.sort() 3461 for key in keys: 3462 if not to_print(key): 3463 continue 3464 default = self.options_madgraph[key] 3465 value = self.options[key] 3466 if value == default: 3467 outstr += " %25s \t:\t%s\n" % (key,value) 3468 else: 3469 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3470 outstr += "\n" 3471 outstr += " MadEvent Options \n" 3472 outstr += " ---------------- \n" 3473 keys = self.options_madevent.keys() 3474 keys.sort() 3475 for key in keys: 3476 if not to_print(key): 3477 continue 3478 default = self.options_madevent[key] 3479 value = self.options[key] 3480 if value == default: 3481 outstr += " %25s \t:\t%s\n" % (key,value) 3482 else: 3483 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3484 outstr += "\n" 3485 outstr += " Configuration Options \n" 3486 outstr += " --------------------- \n" 3487 keys = self.options_configuration.keys() 3488 keys.sort() 3489 for key in keys: 3490 if not to_print(key): 3491 continue 3492 default = self.options_configuration[key] 3493 value = self.options[key] 3494 if value == default: 3495 outstr += " %25s \t:\t%s\n" % (key,value) 3496 else: 3497 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3498 3499 output.write(outstr) 3500 elif args[0] in ["variable"]: 3501 super(MadGraphCmd, self).do_display(line, output) 3502 3503
3504 - def multiparticle_string(self, key):
3505 """Returns a nicely formatted string for the multiparticle""" 3506 3507 if self._multiparticles[key] and \ 3508 isinstance(self._multiparticles[key][0], list): 3509 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\ 3510 get('particle_dict')[part_id].get_name() \ 3511 for part_id in id_list]) \ 3512 for id_list in self._multiparticles[key]])) 3513 else: 3514 return "%s = %s" % (key, " ".join([self._curr_model.\ 3515 get('particle_dict')[part_id].get_name() \ 3516 for part_id in self._multiparticles[key]]))
3517
3518 - def do_tutorial(self, line):
3519 """Activate/deactivate the tutorial mode.""" 3520 3521 args = self.split_arg(line) 3522 self.check_tutorial(args) 3523 tutorials = {'MadGraph5': logger_tuto, 3524 'aMCatNLO': logger_tuto_nlo, 3525 'MadLoop': logger_tuto_madloop} 3526 try: 3527 tutorials[args[0]].setLevel(logging.INFO) 3528 for mode in [m for m in tutorials.keys() if m != args[0]]: 3529 tutorials[mode].setLevel(logging.ERROR) 3530 except KeyError: 3531 logger_tuto.info("\n\tThanks for using the tutorial!") 3532 logger_tuto.setLevel(logging.ERROR) 3533 logger_tuto_nlo.info("\n\tThanks for using the aMC@NLO tutorial!") 3534 logger_tuto_nlo.setLevel(logging.ERROR) 3535 logger_tuto_madloop.info("\n\tThanks for using MadLoop tutorial!") 3536 logger_tuto_madloop.setLevel(logging.ERROR) 3537 3538 if not self._mgme_dir: 3539 logger_tuto.info(\ 3540 "\n\tWarning: To use all features in this tutorial, " + \ 3541 "please run from a" + \ 3542 "\n\t valid MG_ME directory.")
3543 3544 3545
3546 - def draw(self, line,selection='all',type=''):
3547 """ draw the Feynman diagram for the given process. 3548 Type refers to born, real or loop""" 3549 3550 args = self.split_arg(line) 3551 # Check the validity of the arguments 3552 self.check_draw(args) 3553 3554 # Check if we plot a decay chain 3555 if any([isinstance(a, diagram_generation.DecayChainAmplitude) for \ 3556 a in self._curr_amps]) and not self._done_export: 3557 warn = 'WARNING: You try to draw decay chain diagrams without first running output.\n' 3558 warn += '\t The decay processes will be drawn separately' 3559 logger.warning(warn) 3560 3561 (options, args) = _draw_parser.parse_args(args) 3562 options = draw_lib.DrawOption(options) 3563 start = time.time() 3564 3565 # Collect amplitudes 3566 amplitudes = diagram_generation.AmplitudeList() 3567 3568 for amp in self._curr_amps: 3569 amplitudes.extend(amp.get_amplitudes()) 3570 3571 for amp in amplitudes: 3572 filename = pjoin(args[0], 'diagrams_' + \ 3573 amp.get('process').shell_string() + ".eps") 3574 3575 if selection=='all' and type != 'loop': 3576 diags=amp.get('diagrams') 3577 elif selection=='born': 3578 diags=amp.get('born_diagrams') 3579 elif selection=='loop' or type == 'loop': 3580 diags=base_objects.DiagramList([d for d in 3581 amp.get('loop_diagrams') if d.get('type')>0]) 3582 if len(diags) > 5000: 3583 logger.warning('Displaying only the first 5000 diagrams') 3584 diags = base_objects.DiagramList(diags[:5000]) 3585 3586 plot = draw.MultiEpsDiagramDrawer(diags, 3587 filename, 3588 model=self._curr_model, 3589 amplitude=amp, 3590 legend=amp.get('process').input_string(), 3591 diagram_type=type) 3592 3593 3594 logger.info("Drawing " + \ 3595 amp.get('process').nice_string()) 3596 plot.draw(opt=options) 3597 logger.info("Wrote file " + filename) 3598 self.exec_cmd('open %s' % filename) 3599 3600 stop = time.time() 3601 logger.info('time to draw %s' % (stop - start))
3602 3603 # Perform checks
3604 - def do_check(self, line):
3605 """Check a given process or set of processes""" 3606 3607 def create_lambda_values_list(lower_bound, N): 3608 """ Returns a list of values spanning the range [1.0, lower_bound] with 3609 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered 3610 by N values uniformly distributed. For example, lower_bound=1e-2 3611 and N=5 returns: 3612 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]""" 3613 3614 lCMS_values = [1] 3615 exp = 0 3616 n = 0 3617 while lCMS_values[-1]>=lower_bound: 3618 n = (n+1) 3619 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N))) 3620 if lCMS_values[-1]==lCMS_values[-2]: 3621 lCMS_values.pop() 3622 exp = (n+1)//N 3623 3624 lCMS_values = lCMS_values[:-1] 3625 if lCMS_values[-1]!=lower_bound: 3626 lCMS_values.append(lower_bound) 3627 3628 return lCMS_values
3629 3630 ###### BEGIN do_check 3631 3632 args = self.split_arg(line) 3633 # Check args validity 3634 param_card = self.check_check(args) 3635 3636 options= {'events':None} # If the momentum needs to be picked from a event file 3637 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card): 3638 logger_check.info("Will use the param_card contained in the banner and the events associated") 3639 import madgraph.various.banner as banner 3640 options['events'] = param_card 3641 mybanner = banner.Banner(param_card) 3642 param_card = mybanner.charge_card('param_card') 3643 3644 aloha_lib.KERNEL.clean() 3645 # Back up the gauge for later 3646 gauge = str(self.options['gauge']) 3647 options['reuse'] = args[1]=="-reuse" 3648 args = args[:1]+args[2:] 3649 # For the stability check the user can specify the statistics (i.e 3650 # number of trial PS points) as a second argument 3651 if args[0] in ['stability', 'profile']: 3652 options['npoints'] = int(args[1]) 3653 args = args[:1]+args[2:] 3654 3655 MLoptions={} 3656 i=-1 3657 CMS_options = {} 3658 while args[i].startswith('--'): 3659 option = args[i].split('=') 3660 if option[0] =='--energy': 3661 options['energy']=float(option[1]) 3662 elif option[0]=='--split_orders': 3663 options['split_orders']=int(option[1]) 3664 elif option[0]=='--helicity': 3665 try: 3666 options['helicity']=int(option[1]) 3667 except ValueError: 3668 raise self.InvalidCmd("The value of the 'helicity' option"+\ 3669 " must be an integer, not %s."%option[1]) 3670 elif option[0]=='--reduction': 3671 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')] 3672 elif option[0]=='--collier_mode': 3673 MLoptions['COLLIERMode']=int(option[1]) 3674 elif option[0]=='--collier_cache': 3675 MLoptions['COLLIERGlobalCache']=int(option[1]) 3676 elif option[0]=='--collier_req_acc': 3677 if option[1]!='auto': 3678 MLoptions['COLLIERRequiredAccuracy']=float(option[1]) 3679 elif option[0]=='--collier_internal_stability_test': 3680 MLoptions['COLLIERUseInternalStabilityTest']=eval(option[1]) 3681 elif option[0]=='--CTModeRun': 3682 try: 3683 MLoptions['CTModeRun']=int(option[1]) 3684 except ValueError: 3685 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\ 3686 " must be an integer, not %s."%option[1]) 3687 elif option[0]=='--offshellness': 3688 CMS_options['offshellness'] = float(option[1]) 3689 if CMS_options['offshellness']<=-1.0: 3690 raise self.InvalidCmd('Offshellness must be number larger or'+ 3691 ' equal to -1.0, not %f'%CMS_options['offshellness']) 3692 elif option[0]=='--analyze': 3693 options['analyze'] = option[1] 3694 elif option[0]=='--show_plot': 3695 options['show_plot'] = 'true' in option[1].lower() 3696 elif option[0]=='--report': 3697 options['report'] = option[1].lower() 3698 elif option[0]=='--seed': 3699 options['seed'] = int(option[1]) 3700 elif option[0]=='--name': 3701 if '.' in option[1]: 3702 raise self.InvalidCmd("Do not specify the extension in the"+ 3703 " name of the run") 3704 CMS_options['name'] = option[1] 3705 elif option[0]=='--resonances': 3706 if option[1]=='all': 3707 CMS_options['resonances'] = 'all' 3708 else: 3709 try: 3710 resonances=eval(option[1]) 3711 except: 3712 raise self.InvalidCmd("Could not evaluate 'resonances'"+ 3713 " option '%s'"%option[1]) 3714 if isinstance(resonances,int) and resonances>0: 3715 CMS_options['resonances'] = resonances 3716 elif isinstance(resonances,list) and all(len(res)==2 and 3717 isinstance(res[0],int) and all(isinstance(i, int) for i in 3718 res[1]) for res in resonances): 3719 CMS_options['resonances'] = resonances 3720 else: 3721 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+ 3722 " or and integer or a list of tuples of the form "+ 3723 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1]) 3724 elif option[0]=='--tweak': 3725 # Lists the sets of custom and widths modifications to apply 3726 value = option[1] 3727 # Set a shortcuts for applying all relevant tweaks 3728 if value=='alltweaks': 3729 value=str(['default','seed667(seed667)','seed668(seed668)', 3730 'allwidths->0.9*allwidths(widths_x_0.9)', 3731 'allwidths->0.99*allwidths(widths_x_0.99)', 3732 'allwidths->1.01*allwidths(widths_x_1.01)', 3733 'allwidths->1.1*allwidths(widths_x_1.1)', 3734 'logp->logm(logp2logm)','logm->logp(logm2logp)']) 3735 try: 3736 tweaks = eval(value) 3737 if isinstance(tweaks, str): 3738 tweaks = [value] 3739 elif not isinstance(tweaks,list): 3740 tweaks = [value] 3741 except: 3742 tweaks = [value] 3743 if not all(isinstance(t,str) for t in tweaks): 3744 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value) 3745 CMS_options['tweak'] = [] 3746 for tweakID, tweakset in enumerate(tweaks): 3747 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset) 3748 if specs: 3749 tweakset = specs.group('tweakset') 3750 name = specs.group('name') 3751 else: 3752 if tweakset!='default': 3753 name = 'tweak_%d'%(tweakID+1) 3754 else: 3755 name = '' 3756 new_tweak_set = {'custom':[],'params':{},'name':name} 3757 for tweak in tweakset.split('&'): 3758 if tweak=='default': 3759 continue 3760 if tweak.startswith('seed'): 3761 new_tweak_set['custom'].append(tweak) 3762 continue 3763 try: 3764 param, replacement = tweak.split('->') 3765 except ValueError: 3766 raise self.InvalidCmd("Tweak specification '%s'"%\ 3767 tweak+" is incorrect. It should be of"+\ 3768 " the form a->_any_function_of_(a,lambdaCMS).") 3769 if param in ['logp','logm','log'] and \ 3770 replacement in ['logp','logm','log']: 3771 new_tweak_set['custom'].append(tweak) 3772 continue 3773 try: 3774 # for safety prefix parameters, because 'as' for alphas 3775 # is a python reserved name for example 3776 orig_param, orig_replacement = param, replacement 3777 replacement = replacement.replace(param, 3778 '__tmpprefix__%s'%param) 3779 param = '__tmpprefix__%s'%param 3780 res = float(eval(replacement.lower(), 3781 {'lambdacms':1.0,param.lower():98.85})) 3782 except: 3783 raise self.InvalidCmd("The substitution expression "+ 3784 "'%s' for the tweaked parameter"%orig_replacement+ 3785 " '%s' could not be evaluated. It must be an "%orig_param+ 3786 "expression of the parameter and 'lambdaCMS'.") 3787 new_tweak_set['params'][param.lower()] = replacement.lower() 3788 CMS_options['tweak'].append(new_tweak_set) 3789 3790 elif option[0]=='--recompute_width': 3791 if option[1].lower() not in ['never','always','first_time','auto']: 3792 raise self.InvalidCmd("The option 'recompute_width' can "+\ 3793 "only be 'never','always', 'first_time' or 'auto' (default).") 3794 CMS_options['recompute_width'] = option[1] 3795 elif option[0]=='--loop_filter': 3796 # Specify a loop, filter. See functions get_loop_filter and 3797 # user_filter in loop_diagram_generation.LoopAmplitude for 3798 # information on usage. 3799 CMS_options['loop_filter'] = '='.join(option[1:]) 3800 elif option[0]=='--diff_lambda_power': 3801 #'secret' option to chose by which lambda power one should divide 3802 # the nwa-cms difference. Useful to set to 2 when doing the Born check 3803 # to see whether the NLO check will have sensitivity to the CMS 3804 # implementation 3805 try: 3806 CMS_options['diff_lambda_power']=float(option[1]) 3807 except ValueError: 3808 raise self.InvalidCmd("the '--diff_lambda_power' option"+\ 3809 " must be an integer or float, not '%s'."%option[1]) 3810 elif option[0]=='--lambda_plot_range': 3811 try: 3812 plot_range=eval(option[1]) 3813 except Exception as e: 3814 raise self.InvalidCmd("The plot range specified %s"%option[1]+\ 3815 " is not a valid syntax. Error:\n%s"%str(e)) 3816 if not isinstance(plot_range,(list,tuple)) or \ 3817 len(plot_range)!=2 or any(not isinstance(p,(float,int)) 3818 for p in plot_range): 3819 raise self.InvalidCmd("The plot range specified %s"\ 3820 %option[1]+" is invalid") 3821 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range]) 3822 elif option[0]=='--lambdaCMS': 3823 try: 3824 lambda_values = eval(option[1]) 3825 except SyntaxError: 3826 raise self.InvalidCmd("'%s' is not a correct"%option[1]+ 3827 " python expression for lambdaCMS values.") 3828 if isinstance(lambda_values,list): 3829 if lambda_values[0]!=1.0: 3830 raise self.InvalidCmd("The first value of the lambdaCMS values"+ 3831 " specified must be 1.0, not %s"%str(lambda_values)) 3832 for l in lambda_values: 3833 if not isinstance(l,float): 3834 raise self.InvalidCmd("All lambda CMS values must be"+ 3835 " float, not '%s'"%str(l)) 3836 elif isinstance(lambda_values,(tuple,float)): 3837 # Format here is then (lower_bound, N) were lower_bound is 3838 # the minimum lambdaCMS value that must be probed and the 3839 # integer N is the number of such values that must be 3840 # uniformly distributed in each intervale [1.0e-i,1.0e-(i+1)] 3841 if isinstance(lambda_values, float): 3842 # Use default of 10 for the number of lambda values 3843 lower_bound = lambda_values 3844 N = 10 3845 else: 3846 if isinstance(lambda_values[0],float) and \ 3847 isinstance(lambda_values[1],int): 3848 lower_bound = lambda_values[0] 3849 N = lambda_values[1] 3850 else: 3851 raise self.InvalidCmd("'%s' must be a "%option[1]+ 3852 "tuple with types (float, int).") 3853 lambda_values = create_lambda_values_list(lower_bound,N) 3854 else: 3855 raise self.InvalidCmd("'%s' must be an expression"%option[1]+ 3856 " for either a float, tuple or list.") 3857 lower_bound = lambda_values[-1] 3858 # and finally add 5 points for stability test on the last values 3859 # Depending on how the stab test will behave at NLO, we can 3860 # consider automatically adding the values below 3861 # for stab in range(1,6): 3862 # lambda_values.append((1.0+(stab/100.0))*lower_bound) 3863 3864 CMS_options['lambdaCMS'] = lambda_values 3865 elif option[0]=='--cms': 3866 try: 3867 CMS_expansion_orders, CMS_expansion_parameters = \ 3868 option[1].split(',') 3869 except ValueError: 3870 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 3871 args[i]+" is incorrect.") 3872 CMS_options['expansion_orders'] = [expansion_order for 3873 expansion_order in CMS_expansion_orders.split('&')] 3874 CMS_options['expansion_parameters'] = {} 3875 for expansion_parameter in CMS_expansion_parameters.split('&'): 3876 try: 3877 param, replacement = expansion_parameter.split('->') 3878 except ValueError: 3879 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 3880 expansion_parameter+" is incorrect. It should be of"+\ 3881 " the form a->_any_function_of_(a,lambdaCMS).") 3882 try: 3883 # for safety prefix parameters, because 'as' for alphas 3884 # is a python reserved name for example 3885 orig_param, orig_replacement = param, replacement 3886 replacement = replacement.replace(param, 3887 '__tmpprefix__%s'%param) 3888 param = '__tmpprefix__%s'%param 3889 res = float(eval(replacement.lower(), 3890 {'lambdacms':1.0,param.lower():98.85})) 3891 except: 3892 raise self.InvalidCmd("The substitution expression "+ 3893 "'%s' for CMS expansion parameter"%orig_replacement+ 3894 " '%s' could not be evaluated. It must be an "%orig_param+ 3895 "expression of the parameter and 'lambdaCMS'.") 3896 # Put everything lower case as it will be done when 3897 # accessing model variables 3898 CMS_options['expansion_parameters'][param.lower()]=\ 3899 replacement.lower() 3900 else: 3901 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0]) 3902 3903 i=i-1 3904 args = args[:i+1] 3905 3906 if args[0]=='options': 3907 # Simple printout of the check command options 3908 logger_check.info("Options for the command 'check' are:") 3909 logger_check.info("{:<20} {}".format(' name','default value')) 3910 logger_check.info("-"*40) 3911 for key, value in options.items(): 3912 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 3913 return 3914 3915 if args[0].lower()=='cmsoptions': 3916 # Simple printout of the special check cms options 3917 logger_check.info("Special options for the command 'check cms' are:") 3918 logger_check.info("{:<20} {}".format(' name','default value')) 3919 logger_check.info("-"*40) 3920 for key, value in CMS_options.items(): 3921 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 3922 return 3923 3924 # Set the seed here if not in cms check and if specified 3925 if args[0]!='cms' and options['seed']!=-1: 3926 # Not necessarily optimal as there could be additional call to 3927 # random() as the code develops, but at least it will encompass 3928 # everything in this way. 3929 logger_check.info('Setting random seed to %d.'%options['seed']) 3930 random.seed(options['seed']) 3931 3932 proc_line = " ".join(args[1:]) 3933 # Don't try to extract the process if just re-analyzing a saved run 3934 if not (args[0]=='cms' and options['analyze']!='None'): 3935 myprocdef = self.extract_process(proc_line) 3936 3937 # Check that we have something 3938 if not myprocdef: 3939 raise self.InvalidCmd("Empty or wrong format process, please try again.") 3940 # For the check command, only the mode 'virt' make sense. 3941 if myprocdef.get('NLO_mode')=='all': 3942 myprocdef.set('NLO_mode','virt') 3943 else: 3944 myprocdef = None 3945 3946 # If the test has to write out on disk, it should do so at the location 3947 # specified below where the user must be sure to have writing access. 3948 output_path = os.getcwd() 3949 3950 if args[0] in ['timing','stability', 'profile'] and not \ 3951 myprocdef.get('perturbation_couplings'): 3952 raise self.InvalidCmd("Only loop processes can have their "+ 3953 " timings or stability checked.") 3954 3955 if args[0]=='gauge' and \ 3956 not myprocdef.get('perturbation_couplings') in [[],['QCD']]: 3957 raise self.InvalidCmd( 3958 """Feynman vs unitary gauge comparisons can only be done if there are no loop 3959 propagators affected by this gauge. Typically, either processes at tree level 3960 or including only QCD perturbations can be considered here.""") 3961 3962 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2: 3963 raise self.InvalidCmd("The current model does not allow for both "+\ 3964 "Feynman and unitary gauge.") 3965 3966 # Disable some loggers 3967 loggers = [logging.getLogger('madgraph.diagram_generation'), 3968 logging.getLogger('madgraph.loop_diagram_generation'), 3969 logging.getLogger('ALOHA'), 3970 logging.getLogger('madgraph.helas_objects'), 3971 logging.getLogger('madgraph.loop_exporter'), 3972 logging.getLogger('madgraph.export_v4'), 3973 logging.getLogger('cmdprint'), 3974 logging.getLogger('madgraph.model'), 3975 logging.getLogger('madgraph.base_objects')] 3976 old_levels = [log.level for log in loggers] 3977 for log in loggers: 3978 log.setLevel(logging.WARNING) 3979 3980 # run the check 3981 cpu_time1 = time.time() 3982 # Run matrix element generation check on processes 3983 3984 # The aloha python output has trouble when doing (tree level of course) 3985 # python output and that loop_mode is True at the beginning. 3986 # So as a temporary fix for the problem that after doing a check at NLO 3987 # then a check at LO will fail, I make sure I set it to False if the 3988 # process is a tree-level one 3989 if myprocdef: 3990 if myprocdef.get('perturbation_couplings')==[]: 3991 aloha.loop_mode = False 3992 3993 comparisons = [] 3994 gauge_result = [] 3995 gauge_result_no_brs = [] 3996 lorentz_result =[] 3997 nb_processes = 0 3998 timings = [] 3999 stability = [] 4000 profile_time = [] 4001 profile_stab = [] 4002 cms_results = [] 4003 4004 if "_cuttools_dir" in dir(self): 4005 CT_dir = self._cuttools_dir 4006 else: 4007 CT_dir ="" 4008 if "MLReductionLib" in MLoptions: 4009 if 1 in MLoptions["MLReductionLib"]: 4010 MLoptions["MLReductionLib"].remove(1) 4011 # directories for TIR 4012 TIR_dir={} 4013 if "_iregi_dir" in dir(self): 4014 TIR_dir['iregi_dir']=self._iregi_dir 4015 else: 4016 if "MLReductionLib" in MLoptions: 4017 if 3 in MLoptions["MLReductionLib"]: 4018 logger_check.warning('IREGI not available on your system; it will be skipped.') 4019 MLoptions["MLReductionLib"].remove(3) 4020 4021 if 'pjfry' in self.options and isinstance(self.options['pjfry'],str): 4022 TIR_dir['pjfry_dir']=self.options['pjfry'] 4023 else: 4024 if "MLReductionLib" in MLoptions: 4025 if 2 in MLoptions["MLReductionLib"]: 4026 logger_check.warning('PJFRY not available on your system; it will be skipped.') 4027 MLoptions["MLReductionLib"].remove(2) 4028 4029 if 'golem' in self.options and isinstance(self.options['golem'],str): 4030 TIR_dir['golem_dir']=self.options['golem'] 4031 else: 4032 if "MLReductionLib" in MLoptions: 4033 if 4 in MLoptions["MLReductionLib"]: 4034 logger_check.warning('GOLEM not available on your system; it will be skipped.') 4035 MLoptions["MLReductionLib"].remove(4) 4036 4037 if 'samurai' in self.options and isinstance(self.options['samurai'],str): 4038 TIR_dir['samurai_dir']=self.options['samurai'] 4039 else: 4040 if "MLReductionLib" in MLoptions: 4041 if 5 in MLoptions["MLReductionLib"]: 4042 logger_check.warning('Samurai not available on your system; it will be skipped.') 4043 MLoptions["MLReductionLib"].remove(5) 4044 4045 if 'collier' in self.options and isinstance(self.options['collier'],str): 4046 TIR_dir['collier_dir']=self.options['collier'] 4047 else: 4048 if "MLReductionLib" in MLoptions: 4049 if 7 in MLoptions["MLReductionLib"]: 4050 logger_check.warning('Collier not available on your system; it will be skipped.') 4051 MLoptions["MLReductionLib"].remove(7) 4052 4053 if 'ninja' in self.options and isinstance(self.options['ninja'],str): 4054 TIR_dir['ninja_dir']=self.options['ninja'] 4055 else: 4056 if "MLReductionLib" in MLoptions: 4057 if 6 in MLoptions["MLReductionLib"]: 4058 logger_check.warning('Ninja not available on your system; it will be skipped.') 4059 MLoptions["MLReductionLib"].remove(6) 4060 4061 if args[0] in ['timing']: 4062 timings = process_checks.check_timing(myprocdef, 4063 param_card = param_card, 4064 cuttools=CT_dir, 4065 tir=TIR_dir, 4066 options = options, 4067 cmd = self, 4068 output_path = output_path, 4069 MLOptions = MLoptions 4070 ) 4071 4072 if args[0] in ['stability']: 4073 stability=process_checks.check_stability(myprocdef, 4074 param_card = param_card, 4075 cuttools=CT_dir, 4076 tir=TIR_dir, 4077 options = options, 4078 output_path = output_path, 4079 cmd = self, 4080 MLOptions = MLoptions) 4081 4082 if args[0] in ['profile']: 4083 # In this case timing and stability will be checked one after the 4084 # other without re-generating the process. 4085 profile_time, profile_stab = process_checks.check_profile(myprocdef, 4086 param_card = param_card, 4087 cuttools=CT_dir, 4088 tir=TIR_dir, 4089 options = options, 4090 MLOptions = MLoptions, 4091 output_path = output_path, 4092 cmd = self) 4093 4094 if args[0] in ['gauge', 'full'] and \ 4095 len(self._curr_model.get('gauge')) == 2 and\ 4096 myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4097 4098 line = " ".join(args[1:]) 4099 myprocdef = self.extract_process(line) 4100 if gauge == 'unitary': 4101 myprocdef_unit = myprocdef 4102 self.do_set('gauge Feynman', log=False) 4103 myprocdef_feyn = self.extract_process(line) 4104 else: 4105 myprocdef_feyn = myprocdef 4106 self.do_set('gauge unitary', log=False) 4107 myprocdef_unit = self.extract_process(line) 4108 4109 nb_part_unit = len(myprocdef_unit.get('model').get('particles')) 4110 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles')) 4111 if nb_part_feyn == nb_part_unit: 4112 logger_check.error('No Goldstone present for this check!!') 4113 gauge_result_no_brs = process_checks.check_unitary_feynman( 4114 myprocdef_unit, myprocdef_feyn, 4115 param_card = param_card, 4116 options=options, 4117 cuttools=CT_dir, 4118 tir=TIR_dir, 4119 reuse = options['reuse'], 4120 output_path = output_path, 4121 cmd = self) 4122 4123 # restore previous settings 4124 self.do_set('gauge %s' % gauge, log=False) 4125 nb_processes += len(gauge_result_no_brs) 4126 4127 if args[0] in ['permutation', 'full']: 4128 comparisons = process_checks.check_processes(myprocdef, 4129 param_card = param_card, 4130 quick = True, 4131 cuttools=CT_dir, 4132 tir=TIR_dir, 4133 reuse = options['reuse'], 4134 cmd = self, 4135 output_path = output_path, 4136 options=options) 4137 nb_processes += len(comparisons[0]) 4138 4139 if args[0] in ['lorentz', 'full']: 4140 myprocdeff = copy.copy(myprocdef) 4141 lorentz_result = process_checks.check_lorentz(myprocdeff, 4142 param_card = param_card, 4143 cuttools=CT_dir, 4144 tir=TIR_dir, 4145 reuse = options['reuse'], 4146 cmd = self, 4147 output_path = output_path, 4148 options=options) 4149 nb_processes += len(lorentz_result) 4150 4151 if args[0] in ['brs', 'full']: 4152 gauge_result = process_checks.check_gauge(myprocdef, 4153 param_card = param_card, 4154 cuttools=CT_dir, 4155 tir=TIR_dir, 4156 reuse = options['reuse'], 4157 cmd = self, 4158 output_path = output_path, 4159 options=options) 4160 nb_processes += len(gauge_result) 4161 4162 # The CMS check is typically more complicated and slower than others 4163 # so we don't run it automatically with 'full'. 4164 if args[0] in ['cms']: 4165 4166 cms_original_setup = self.options['complex_mass_scheme'] 4167 process_line = " ".join(args[1:]) 4168 # Merge in the CMS_options to the options 4169 for key, value in CMS_options.items(): 4170 if key=='tweak': 4171 continue 4172 if key not in options: 4173 options[key] = value 4174 else: 4175 raise MadGraph5Error,"Option '%s' is both in the option"%key+\ 4176 " and CMS_option dictionary." 4177 4178 if options['analyze']=='None': 4179 cms_results = [] 4180 for tweak in CMS_options['tweak']: 4181 options['tweak']=tweak 4182 # Try to guess the save path and try to load it before running 4183 guessed_proc = myprocdef.get_process( 4184 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4185 if not leg.get('state')], 4186 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4187 if leg.get('state')]) 4188 save_path = process_checks.CMS_save_path('pkl', 4189 {'ordered_processes':[guessed_proc.base_string()], 4190 'perturbation_orders':guessed_proc.get('perturbation_couplings')}, 4191 self._curr_model, options, output_path=output_path) 4192 if os.path.isfile(save_path) and options['reuse']: 4193 cms_result = save_load_object.load_from_file(save_path) 4194 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"% 4195 (tweak['name'],save_path)) 4196 if cms_result is None: 4197 raise self.InvalidCmd('The complex mass scheme check result'+ 4198 " file below could not be read.\n %s"%save_path) 4199 else: 4200 cms_result = process_checks.check_complex_mass_scheme( 4201 process_line, 4202 param_card = param_card, 4203 cuttools=CT_dir, 4204 tir=TIR_dir, 4205 cmd = self, 4206 output_path = output_path, 4207 MLOptions = MLoptions, 4208 options=options) 4209 # Now set the correct save path 4210 save_path = process_checks.CMS_save_path('pkl', cms_result, 4211 self._curr_model, options, output_path=output_path) 4212 cms_results.append((cms_result,save_path,tweak['name'])) 4213 else: 4214 cms_result = save_load_object.load_from_file( 4215 options['analyze'].split(',')[0]) 4216 cms_results.append((cms_result,options['analyze'].split(',')[0], 4217 CMS_options['tweak'][0]['name'])) 4218 if cms_result is None: 4219 raise self.InvalidCmd('The complex mass scheme check result'+ 4220 " file below could not be read.\n %s" 4221 %options['analyze'].split(',')[0]) 4222 4223 # restore previous settings 4224 self.do_set('complex_mass_scheme %s'%str(cms_original_setup), 4225 log=False) 4226 # Use here additional key 'ordered_processes' 4227 nb_processes += len(cms_result['ordered_processes']) 4228 4229 cpu_time2 = time.time() 4230 logger_check.info("%i check performed in %s"% (nb_processes, 4231 misc.format_time(int(cpu_time2 - cpu_time1)))) 4232 4233 if args[0] in ['cms']: 4234 text = "Note that the complex mass scheme test in principle only\n" 4235 text+= "works for stable particles in final states.\n\ns" 4236 if args[0] not in ['timing','stability', 'profile', 'cms']: 4237 if self.options['complex_mass_scheme']: 4238 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n" 4239 text+= "results only for stable particles in final states.\n\ns" 4240 elif not myprocdef.get('perturbation_couplings'): 4241 text = "Note That all width have been set to zero for those checks\n\n" 4242 else: 4243 text = "\n" 4244 else: 4245 text ="\n" 4246 4247 if timings: 4248 text += 'Timing result for the '+('optimized' if \ 4249 self.options['loop_optimized_output'] else 'default')+' output:\n' 4250 4251 text += process_checks.output_timings(myprocdef, timings) 4252 if stability: 4253 text += 'Stability result for the '+('optimized' if \ 4254 self.options['loop_optimized_output'] else 'default')+' output:\n' 4255 text += process_checks.output_stability(stability,output_path) 4256 4257 if profile_time and profile_stab: 4258 text += 'Timing result '+('optimized' if \ 4259 self.options['loop_optimized_output'] else 'default')+':\n' 4260 text += process_checks.output_profile(myprocdef, profile_stab, 4261 profile_time, output_path, options['reuse']) + '\n' 4262 if lorentz_result: 4263 text += 'Lorentz invariance results:\n' 4264 text += process_checks.output_lorentz_inv(lorentz_result) + '\n' 4265 if gauge_result: 4266 text += 'Gauge results:\n' 4267 text += process_checks.output_gauge(gauge_result) + '\n' 4268 if gauge_result_no_brs: 4269 text += 'Gauge results (switching between Unitary/Feynman):\n' 4270 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n' 4271 if cms_results: 4272 text += 'Complex mass scheme results (varying width in the off-shell regions):\n' 4273 cms_result = cms_results[0][0] 4274 if len(cms_results)>1: 4275 analyze = [] 4276 for i, (cms_res, save_path, tweakname) in enumerate(cms_results): 4277 save_load_object.save_to_file(save_path, cms_res) 4278 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"% 4279 (tweakname,save_path)) 4280 if i==0: 4281 analyze.append(save_path) 4282 else: 4283 analyze.append('%s(%s)'%(save_path,tweakname)) 4284 options['analyze']=','.join(analyze) 4285 options['tweak'] = CMS_options['tweak'][0] 4286 4287 self._cms_checks.append({'line':line, 'cms_result':cms_result, 4288 'options':options, 'output_path':output_path}) 4289 text += process_checks.output_complex_mass_scheme(cms_result, 4290 output_path, options, self._curr_model, 4291 output='concise_text' if options['report']=='concise' else 'text')+'\n' 4292 4293 if comparisons and len(comparisons[0])>0: 4294 text += 'Process permutation results:\n' 4295 text += process_checks.output_comparisons(comparisons[0]) + '\n' 4296 self._comparisons = comparisons 4297 4298 # We use the reuse tag for an alternative way of skipping the pager. 4299 if len(text.split('\n'))>20 and not '-reuse' in line and text!='': 4300 if 'test_manager' not in sys.argv[0]: 4301 pydoc.pager(text) 4302 4303 # Restore diagram logger 4304 for i, log in enumerate(loggers): 4305 log.setLevel(old_levels[i]) 4306 4307 # Output the result to the interface directly if short enough or if it 4308 # was anyway not output to the pager 4309 if len(text.split('\n'))<=20 or options['reuse']: 4310 # Useful to really specify what logger is used for ML acceptance tests 4311 logging.getLogger('madgraph.check_cmd').info(text) 4312 else: 4313 logging.getLogger('madgraph.check_cmd').debug(text) 4314 4315 # clean the globals created. 4316 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL) 4317 if not options['reuse']: 4318 process_checks.clean_up(self._mgme_dir) 4319 4320 # Generate a new amplitude
4321 - def do_generate(self, line):
4322 """Main commands: Generate an amplitude for a given process""" 4323 4324 aloha_lib.KERNEL.clean() 4325 # Reset amplitudes 4326 self._curr_amps = diagram_generation.AmplitudeList() 4327 # Reset Process definition 4328 self._curr_proc_defs = base_objects.ProcessDefinitionList() 4329 # Reset Helas matrix elements 4330 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4331 self._generate_info = line 4332 # Reset _done_export, since we have new process 4333 self._done_export = False 4334 # Also reset _export_format and _export_dir 4335 self._export_format = None 4336 4337 4338 # Call add process 4339 args = self.split_arg(line) 4340 args.insert(0, 'process') 4341 self.do_add(" ".join(args))
4342
4343 - def extract_process(self, line, proc_number = 0, overall_orders = {}):
4344 """Extract a process definition from a string. Returns 4345 a ProcessDefinition.""" 4346 4347 orig_line = line 4348 # Check basic validity of the line 4349 if not len(re.findall('>\D', line)) in [1,2]: 4350 self.do_help('generate') 4351 raise self.InvalidCmd('Wrong use of \">\" special character.') 4352 4353 4354 # Perform sanity modifications on the lines: 4355 # Add a space before and after any > , $ / | [ ] 4356 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)") 4357 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line) 4358 4359 # Use regular expressions to extract s-channel propagators, 4360 # forbidden s-channel propagators/particles, coupling orders 4361 # and process number, starting from the back 4362 4363 # Start with process number (identified by "@") 4364 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4365 proc_number_re = proc_number_pattern.match(line) 4366 if proc_number_re: 4367 proc_number = int(proc_number_re.group(2)) 4368 line = proc_number_re.group(1)+ proc_number_re.group(3) 4369 #overall_order are already handle but it is better to pass the info to each group 4370 4371 # Now check for perturbation orders, specified in between squared brackets 4372 perturbation_couplings_pattern = \ 4373 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\ 4374 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 4375 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 4376 perturbation_couplings = "" 4377 LoopOption= 'tree' 4378 HasBorn= True 4379 if perturbation_couplings_re: 4380 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 4381 option=perturbation_couplings_re.group("option") 4382 if option: 4383 if option in self._valid_nlo_modes: 4384 LoopOption=option 4385 if option=='sqrvirt': 4386 LoopOption='virt' 4387 HasBorn=False 4388 elif option=='noborn': 4389 HasBorn=False 4390 else: 4391 raise self.InvalidCmd, "NLO mode %s is not valid. "%option+\ 4392 "Valid modes are %s. "%str(self._valid_nlo_modes) 4393 else: 4394 LoopOption='all' 4395 4396 line = perturbation_couplings_re.group("proc")+\ 4397 perturbation_couplings_re.group("rest") 4398 4399 ## Now check for orders/squared orders/constrained orders 4400 order_pattern = re.compile(\ 4401 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\ 4402 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*") 4403 order_re = order_pattern.match(line) 4404 squared_orders = {} 4405 orders = {} 4406 constrained_orders = {} 4407 ## The 'split_orders' (i.e. those for which individual matrix element 4408 ## evalutations must be provided for each corresponding order value) are 4409 ## defined from the orders specified in between [] and any order for 4410 ## which there are squared order constraints. 4411 split_orders = [] 4412 while order_re: 4413 type = order_re.group('type') 4414 if order_re.group('name').endswith('^2'): 4415 if type not in self._valid_sqso_types: 4416 raise self.InvalidCmd, "Type of squared order "+\ 4417 "constraint '%s'"% type+" is not supported." 4418 if type == '=': 4419 name = order_re.group('name') 4420 value = order_re.group('value') 4421 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4422 {'n':name, 'v': value}) 4423 type = "<=" 4424 squared_orders[order_re.group('name')[:-2]] = \ 4425 (int(order_re.group('value')),type) 4426 else: 4427 if type not in self._valid_amp_so_types: 4428 raise self.InvalidCmd, \ 4429 "Amplitude order constraints can only be of type %s"%\ 4430 (', '.join(self._valid_amp_so_types))+", not '%s'."%type 4431 name = order_re.group('name') 4432 value = int(order_re.group('value')) 4433 if type in ['=', '<=']: 4434 if type == '=' and value != 0: 4435 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4436 {'n':name, 'v': value}) 4437 orders[name] = value 4438 elif type == "==": 4439 constrained_orders[name] = (value, type) 4440 if name not in squared_orders: 4441 squared_orders[name] = (2 * value,'==') 4442 if True:#name not in orders: 4443 orders[name] = value 4444 4445 elif type == ">": 4446 constrained_orders[name] = (value, type) 4447 if name not in squared_orders: 4448 squared_orders[name] = (2 * value,'>') 4449 4450 line = order_re.group('before') 4451 order_re = order_pattern.match(line) 4452 4453 #only allow amplitue restrctions >/ == for LO/tree level 4454 if constrained_orders and LoopOption != 'tree': 4455 raise self.InvalidCmd, \ 4456 "Amplitude order constraints (for not LO processes) can only be of type %s"%\ 4457 (', '.join(['<=']))+", not '%s'."%type 4458 4459 # If the squared orders are defined but not the orders, assume 4460 # orders=sq_orders. In case the squared order has a negative value or is 4461 # defined with the '>' operato, then this order correspondingly set to 4462 # be maximal (99) since there is no way to know, during generation, if 4463 # the amplitude being contstructed will be leading or not. 4464 if orders=={} and squared_orders!={}: 4465 for order in squared_orders.keys(): 4466 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>': 4467 orders[order]=squared_orders[order][0] 4468 else: 4469 orders[order]=99 4470 4471 if not self._curr_model['case_sensitive']: 4472 # Particle names lowercase 4473 line = line.lower() 4474 4475 # Now check for forbidden particles, specified using "/" 4476 slash = line.find("/") 4477 dollar = line.find("$") 4478 forbidden_particles = "" 4479 if slash > 0: 4480 if dollar > slash: 4481 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line) 4482 else: 4483 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line) 4484 if forbidden_particles_re: 4485 forbidden_particles = forbidden_particles_re.group(2) 4486 line = forbidden_particles_re.group(1) 4487 if len(forbidden_particles_re.groups()) > 2: 4488 line = line + forbidden_particles_re.group(3) 4489 4490 # Now check for forbidden schannels, specified using "$$" 4491 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line) 4492 forbidden_schannels = "" 4493 if forbidden_schannels_re: 4494 forbidden_schannels = forbidden_schannels_re.group(2) 4495 line = forbidden_schannels_re.group(1) 4496 4497 # Now check for forbidden onshell schannels, specified using "$" 4498 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line) 4499 forbidden_onsh_schannels = "" 4500 if forbidden_onsh_schannels_re: 4501 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2) 4502 line = forbidden_onsh_schannels_re.group(1) 4503 4504 # Now check for required schannels, specified using "> >" 4505 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line) 4506 required_schannels = "" 4507 if required_schannels_re: 4508 required_schannels = required_schannels_re.group(2) 4509 line = required_schannels_re.group(1) + ">" + \ 4510 required_schannels_re.group(3) 4511 4512 args = self.split_arg(line) 4513 4514 myleglist = base_objects.MultiLegList() 4515 state = False 4516 4517 # Extract process 4518 for part_name in args: 4519 if part_name == '>': 4520 if not myleglist: 4521 raise self.InvalidCmd, "No final state particles" 4522 state = True 4523 continue 4524 4525 mylegids = [] 4526 if part_name in self._multiparticles: 4527 if isinstance(self._multiparticles[part_name][0], list): 4528 raise self.InvalidCmd,\ 4529 "Multiparticle %s is or-multiparticle" % part_name + \ 4530 " which can be used only for required s-channels" 4531 mylegids.extend(self._multiparticles[part_name]) 4532 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit(): 4533 if int(part_name) in self._curr_model.get('particle_dict'): 4534 mylegids.append(int(part_name)) 4535 else: 4536 raise self.InvalidCmd, \ 4537 "No pdg_code %s in model" % part_name 4538 else: 4539 mypart = self._curr_model['particles'].get_copy(part_name) 4540 if mypart: 4541 mylegids.append(mypart.get_pdg_code()) 4542 4543 if mylegids: 4544 myleglist.append(base_objects.MultiLeg({'ids':mylegids, 4545 'state':state})) 4546 else: 4547 raise self.InvalidCmd, "No particle %s in model" % part_name 4548 4549 # Apply the keyword 'all' for perturbed coupling orders. 4550 if perturbation_couplings.lower()=='all': 4551 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings']) 4552 4553 if filter(lambda leg: leg.get('state') == True, myleglist): 4554 # We have a valid process 4555 # Extract perturbation orders 4556 perturbation_couplings_list = perturbation_couplings.split() 4557 if perturbation_couplings_list==['']: 4558 perturbation_couplings_list=[] 4559 # Correspondingly set 'split_order' from the squared orders and the 4560 # perturbation couplings list 4561 split_orders=list(set(perturbation_couplings_list+squared_orders.keys())) 4562 try: 4563 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else 4564 self._curr_model['order_hierarchy'] 4565 [elem if not elem.endswith('.sqrt') else elem[:-5]]) 4566 except KeyError: 4567 raise self.InvalidCmd, "The loaded model does not defined a "+\ 4568 " coupling order hierarchy for these couplings: %s"%\ 4569 str([so for so in split_orders if so!='WEIGHTED' and so not 4570 in self._curr_model['order_hierarchy'].keys()]) 4571 4572 # If the loopOption is 'tree' then the user used the syntax 4573 # [tree= Orders] for the sole purpose of setting split_orders. We 4574 # then empty the perturbation_couplings_list at this stage. 4575 if LoopOption=='tree': 4576 perturbation_couplings_list = [] 4577 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']: 4578 if not isinstance(self._curr_model,loop_base_objects.LoopModel): 4579 raise self.InvalidCmd(\ 4580 "The current model does not allow for loop computations.") 4581 else: 4582 for pert_order in perturbation_couplings_list: 4583 if pert_order not in self._curr_model['perturbation_couplings']: 4584 raise self.InvalidCmd(\ 4585 "Perturbation order %s is not among" % pert_order + \ 4586 " the perturbation orders allowed for by the loop model.") 4587 if not self.options['loop_optimized_output'] and \ 4588 LoopOption not in ['tree','real'] and split_orders!=[]: 4589 logger.warning('The default output mode (loop_optimized_output'+\ 4590 ' = False) does not support evaluations for given powers of'+\ 4591 ' coupling orders. MadLoop output will therefore not be'+\ 4592 ' able to provide such quantities.') 4593 split_orders = [] 4594 4595 # Now extract restrictions 4596 forbidden_particle_ids = \ 4597 self.extract_particle_ids(forbidden_particles) 4598 if forbidden_particle_ids and \ 4599 isinstance(forbidden_particle_ids[0], list): 4600 raise self.InvalidCmd(\ 4601 "Multiparticle %s is or-multiparticle" % part_name + \ 4602 " which can be used only for required s-channels") 4603 forbidden_onsh_schannel_ids = \ 4604 self.extract_particle_ids(forbidden_onsh_schannels) 4605 forbidden_schannel_ids = \ 4606 self.extract_particle_ids(forbidden_schannels) 4607 if forbidden_onsh_schannel_ids and \ 4608 isinstance(forbidden_onsh_schannel_ids[0], list): 4609 raise self.InvalidCmd,\ 4610 "Multiparticle %s is or-multiparticle" % part_name + \ 4611 " which can be used only for required s-channels" 4612 if forbidden_schannel_ids and \ 4613 isinstance(forbidden_schannel_ids[0], list): 4614 raise self.InvalidCmd,\ 4615 "Multiparticle %s is or-multiparticle" % part_name + \ 4616 " which can be used only for required s-channels" 4617 required_schannel_ids = \ 4618 self.extract_particle_ids(required_schannels) 4619 if required_schannel_ids and not \ 4620 isinstance(required_schannel_ids[0], list): 4621 required_schannel_ids = [required_schannel_ids] 4622 4623 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()]) 4624 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1: 4625 raise self.InvalidCmd( 4626 "At most one negative squared order constraint can be specified.") 4627 4628 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()]) 4629 4630 4631 out = base_objects.ProcessDefinition({'legs': myleglist, 4632 'model': self._curr_model, 4633 'id': proc_number, 4634 'orders': orders, 4635 'squared_orders':sqorders_values, 4636 'sqorders_types':sqorders_types, 4637 'constrained_orders': constrained_orders, 4638 'forbidden_particles': forbidden_particle_ids, 4639 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids, 4640 'forbidden_s_channels': forbidden_schannel_ids, 4641 'required_s_channels': required_schannel_ids, 4642 'overall_orders': overall_orders, 4643 'perturbation_couplings': perturbation_couplings_list, 4644 'has_born':HasBorn, 4645 'NLO_mode':LoopOption, 4646 'split_orders':split_orders 4647 }) 4648 return out
4649 # 'is_decay_chain': decay_process\ 4650 4651
4652 - def create_loop_induced(self, line, myprocdef=None):
4653 """ Routine to create the MultiProcess for the loop-induced case""" 4654 4655 args = self.split_arg(line) 4656 4657 warning_duplicate = True 4658 if '--no_warning=duplicate' in args: 4659 warning_duplicate = False 4660 args.remove('--no_warning=duplicate') 4661 4662 # Check the validity of the arguments 4663 self.check_add(args) 4664 if args[0] == 'process': 4665 args = args[1:] 4666 4667 # special option for 1->N to avoid generation of kinematically forbidden 4668 #decay. 4669 if args[-1].startswith('--optimize'): 4670 optimize = True 4671 args.pop() 4672 else: 4673 optimize = False 4674 4675 4676 if not myprocdef: 4677 myprocdef = self.extract_process(' '.join(args)) 4678 4679 myprocdef.set('NLO_mode', 'noborn') 4680 4681 # store the first process (for the perl script) 4682 if not self._generate_info: 4683 self._generate_info = line 4684 4685 # Reset Helas matrix elements 4686 #self._curr_matrix_elements = helas_objects.HelasLoopInducedMultiProcess() 4687 4688 4689 # Check that we have the same number of initial states as 4690 # existing processes 4691 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 4692 myprocdef.get_ninitial(): 4693 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 4694 4695 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \ 4696 self._curr_amps[0]['has_born']): 4697 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process") 4698 4699 # Negative coupling order contraints can be given on at most one 4700 # coupling order (and either in squared orders or orders, not both) 4701 if len([1 for val in myprocdef.get('orders').values()+\ 4702 myprocdef.get('squared_orders').values() if val<0])>1: 4703 raise MadGraph5Error("Negative coupling order constraints"+\ 4704 " can only be given on one type of coupling and either on"+\ 4705 " squared orders or amplitude orders, not both.") 4706 4707 cpu_time1 = time.time() 4708 4709 # Generate processes 4710 if self.options['group_subprocesses'] == 'Auto': 4711 collect_mirror_procs = True 4712 else: 4713 collect_mirror_procs = self.options['group_subprocesses'] 4714 ignore_six_quark_processes = \ 4715 self.options['ignore_six_quark_processes'] if \ 4716 "ignore_six_quark_processes" in self.options \ 4717 else [] 4718 4719 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 4720 4721 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef, 4722 collect_mirror_procs = collect_mirror_procs, 4723 ignore_six_quark_processes = ignore_six_quark_processes, 4724 optimize=optimize) 4725 4726 for amp in myproc.get('amplitudes'): 4727 if amp not in self._curr_amps: 4728 self._curr_amps.append(amp) 4729 if amp['has_born']: 4730 raise Exception 4731 elif warning_duplicate: 4732 raise self.InvalidCmd, "Duplicate process %s found. Please check your processes." % \ 4733 amp.nice_string_processes() 4734 4735 # Reset _done_export, since we have new process 4736 self._done_export = False 4737 4738 cpu_time2 = time.time() 4739 4740 nprocs = len(myproc.get('amplitudes')) 4741 ndiags = sum([amp.get_number_of_diagrams() for \ 4742 amp in myproc.get('amplitudes')]) 4743 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 4744 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 4745 ndiags = sum([amp.get_number_of_diagrams() for \ 4746 amp in self._curr_amps]) 4747 logger.info("Total: %i processes with %i diagrams" % \ 4748 (len(self._curr_amps), ndiags))
4749 4750 @staticmethod
4751 - def split_process_line(procline):
4752 """Takes a valid process and return 4753 a tuple (core_process, options). This removes 4754 - any NLO specifications. 4755 - any options 4756 [Used by MadSpin] 4757 """ 4758 4759 # remove the tag "[*]": this tag is used in aMC@LNO , 4760 # but it is not a valid syntax for LO 4761 line=procline 4762 pos1=line.find("[") 4763 if pos1>0: 4764 pos2=line.find("]") 4765 if pos2 >pos1: 4766 line=line[:pos1]+line[pos2+1:] 4767 # 4768 # Extract the options: 4769 # 4770 # A. Remove process number (identified by "@") 4771 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4772 proc_number_re = proc_number_pattern.match(line) 4773 if proc_number_re: 4774 line = proc_number_re.group(1) + proc_number_re.group(3) 4775 4776 # B. search for the beginning of the option string 4777 pos=1000 4778 # start with order 4779 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$") 4780 order_re = order_pattern.match(line) 4781 if (order_re): 4782 pos_order=line.find(order_re.group(2)) 4783 if pos_order>0 and pos_order < pos : pos=pos_order 4784 4785 # then look for slash or dollar 4786 slash = line.find("/") 4787 if slash > 0 and slash < pos: pos=slash 4788 dollar = line.find("$") 4789 if dollar > 0 and dollar < pos: pos=dollar 4790 4791 if pos<1000: 4792 proc_option=line[pos:] 4793 line=line[:pos] 4794 else: 4795 proc_option="" 4796 4797 return line, proc_option
4798
4799 - def get_final_part(self, procline):
4800 """Takes a valid process and return 4801 a set of id of final states particles. [Used by MadSpin] 4802 """ 4803 4804 if not self._curr_model['case_sensitive']: 4805 procline = procline.lower() 4806 pids = self._curr_model.get('name2pdg') 4807 4808 # method. 4809 # 1) look for decay. 4810 # in presence of decay call this routine recursively and veto 4811 # the particles which are decayed 4812 4813 # Deal with decay chain 4814 if ',' in procline: 4815 core, decay = procline.split(',', 1) 4816 core_final = self.get_final_part(core) 4817 4818 #split the decay 4819 all_decays = decay.split(',') 4820 nb_level, tmp_decay = 0, '' 4821 decays = [] 4822 # deal with () 4823 for one_decay in all_decays: 4824 if '(' in one_decay: 4825 nb_level += 1 4826 if ')' in one_decay: 4827 nb_level -= 1 4828 4829 if nb_level: 4830 if tmp_decay: 4831 tmp_decay += ', %s' % one_decay 4832 else: 4833 tmp_decay = one_decay 4834 elif tmp_decay: 4835 final = '%s,%s' % (tmp_decay, one_decay) 4836 final = final.strip() 4837 assert final[0] == '(' and final[-1] == ')' 4838 final = final[1:-1] 4839 decays.append(final) 4840 tmp_decay = '' 4841 else: 4842 decays.append(one_decay) 4843 # remove from the final states all particles which are decayed 4844 for one_decay in decays: 4845 first = one_decay.split('>',1)[0].strip() 4846 if first in pids: 4847 pid = set([pids[first]]) 4848 elif first in self._multiparticles: 4849 pid = set(self._multiparticles[first]) 4850 else: 4851 raise Exception, 'invalid particle name: %s. ' % first 4852 core_final.difference_update(pid) 4853 core_final.update(self.get_final_part(one_decay)) 4854 4855 return core_final 4856 4857 # NO DECAY CHAIN 4858 final = set() 4859 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline) 4860 particles = final_states.groups()[0] 4861 for particle in particles.split(): 4862 if particle in pids: 4863 final.add(pids[particle]) 4864 elif particle in self._multiparticles: 4865 final.update(set(self._multiparticles[particle])) 4866 return final
4867
4868 - def extract_particle_ids(self, args):
4869 """Extract particle ids from a list of particle names. If 4870 there are | in the list, this corresponds to an or-list, which 4871 is represented as a list of id lists. An or-list is used to 4872 allow multiple required s-channel propagators to be specified 4873 (e.g. Z/gamma).""" 4874 4875 if isinstance(args, basestring): 4876 args.replace("|", " | ") 4877 args = self.split_arg(args) 4878 all_ids = [] 4879 ids=[] 4880 for part_name in args: 4881 mypart = self._curr_model['particles'].get_copy(part_name) 4882 if mypart: 4883 ids.append([mypart.get_pdg_code()]) 4884 elif part_name in self._multiparticles: 4885 ids.append(self._multiparticles[part_name]) 4886 elif part_name == "|": 4887 # This is an "or-multiparticle" 4888 if ids: 4889 all_ids.append(ids) 4890 ids = [] 4891 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()): 4892 ids.append([int(part_name)]) 4893 else: 4894 raise self.InvalidCmd("No particle %s in model" % part_name) 4895 all_ids.append(ids) 4896 # Flatten id list, to take care of multiparticles and 4897 # or-multiparticles 4898 res_lists = [] 4899 for i, id_list in enumerate(all_ids): 4900 res_lists.extend(diagram_generation.expand_list_list(id_list)) 4901 # Trick to avoid duplication while keeping ordering 4902 for ilist, idlist in enumerate(res_lists): 4903 set_dict = {} 4904 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \ 4905 if i not in set_dict] 4906 4907 if len(res_lists) == 1: 4908 res_lists = res_lists[0] 4909 4910 return res_lists
4911
4912 - def optimize_order(self, pdg_list):
4913 """Optimize the order of particles in a pdg list, so that 4914 similar particles are next to each other. Sort according to: 4915 1. pdg > 0, 2. spin, 3. color, 4. mass > 0""" 4916 4917 if not pdg_list: 4918 return 4919 if not isinstance(pdg_list[0], int): 4920 return 4921 4922 model = self._curr_model 4923 pdg_list.sort(key = lambda i: i < 0) 4924 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion()) 4925 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'), 4926 reverse = True) 4927 pdg_list.sort(key = lambda i: \ 4928 model.get_particle(i).get('mass').lower() != 'zero')
4929
4930 - def extract_decay_chain_process(self, line, level_down=False, proc_number=0):
4931 """Recursively extract a decay chain process definition from a 4932 string. Returns a ProcessDefinition.""" 4933 4934 # Start with process number (identified by "@") and overall orders 4935 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*=\s*\d+\s*)*)$") 4936 proc_number_re = proc_number_pattern.match(line) 4937 overall_orders = {} 4938 if proc_number_re: 4939 proc_number = int(proc_number_re.group(2)) 4940 line = proc_number_re.group(1) 4941 if proc_number_re.group(3): 4942 order_pattern = re.compile("^(.*?)\s*(\w+)\s*=\s*(\d+)\s*$") 4943 order_line = proc_number_re.group(3) 4944 order_re = order_pattern.match(order_line) 4945 while order_re: 4946 overall_orders[order_re.group(2)] = int(order_re.group(3)) 4947 order_line = order_re.group(1) 4948 order_re = order_pattern.match(order_line) 4949 logger.info(line) 4950 4951 4952 index_comma = line.find(",") 4953 index_par = line.find(")") 4954 min_index = index_comma 4955 if index_par > -1 and (index_par < min_index or min_index == -1): 4956 min_index = index_par 4957 4958 if min_index > -1: 4959 core_process = self.extract_process(line[:min_index], proc_number, 4960 overall_orders) 4961 else: 4962 core_process = self.extract_process(line, proc_number, 4963 overall_orders) 4964 4965 #level_down = False 4966 4967 while index_comma > -1: 4968 line = line[index_comma + 1:] 4969 if not line.strip(): 4970 break 4971 index_par = line.find(')') 4972 # special cases: parenthesis but no , => remove the paranthesis! 4973 if line.lstrip()[0] == '(' and index_par !=-1 and \ 4974 not ',' in line[:index_par]: 4975 par_start = line.find('(') 4976 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:]) 4977 index_par = line.find(')') 4978 if line.lstrip()[0] == '(': 4979 # Go down one level in process hierarchy 4980 #level_down = True 4981 line = line.lstrip()[1:] 4982 # This is where recursion happens 4983 decay_process, line = \ 4984 self.extract_decay_chain_process(line, 4985 level_down=True) 4986 index_comma = line.find(",") 4987 index_par = line.find(')') 4988 else: 4989 index_comma = line.find(",") 4990 min_index = index_comma 4991 if index_par > -1 and \ 4992 (index_par < min_index or min_index == -1): 4993 min_index = index_par 4994 if min_index > -1: 4995 decay_process = self.extract_process(line[:min_index]) 4996 else: 4997 decay_process = self.extract_process(line) 4998 4999 core_process.get('decay_chains').append(decay_process) 5000 5001 if level_down: 5002 if index_par == -1: 5003 raise self.InvalidCmd, \ 5004 "Missing ending parenthesis for decay process" 5005 5006 if index_par < index_comma: 5007 line = line[index_par + 1:] 5008 level_down = False 5009 break 5010 5011 if level_down: 5012 index_par = line.find(')') 5013 if index_par == -1: 5014 raise self.InvalidCmd, \ 5015 "Missing ending parenthesis for decay process" 5016 line = line[index_par + 1:] 5017 5018 # Return the core process (ends recursion when there are no 5019 # more decays) 5020 return core_process, line
5021 5022 5023 # Import files
5024 - def do_import(self, line, force=False):
5025 """Main commands: Import files with external formats""" 5026 5027 args = self.split_arg(line) 5028 # Check argument's validity 5029 self.check_import(args) 5030 if args[0].startswith('model'): 5031 self._model_v4_path = None 5032 # Reset amplitudes and matrix elements 5033 self._curr_amps = diagram_generation.AmplitudeList() 5034 # Reset proc defs 5035 self._curr_proc_defs = base_objects.ProcessDefinitionList() 5036 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 5037 # Import model 5038 if args[0].endswith('_v4'): 5039 self._curr_model, self._model_v4_path = \ 5040 import_v4.import_model(args[1], self._mgme_dir) 5041 else: 5042 # avoid loading the qcd/qed model twice 5043 if (args[1].startswith('loop_qcd_qed_sm') or\ 5044 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\ 5045 self.options['gauge']!='Feynman': 5046 logger.info('Switching to Feynman gauge because '+\ 5047 'it is the only one supported by the model %s.'%args[1]) 5048 self._curr_model = None 5049 self.do_set('gauge Feynman',log=False) 5050 prefix = not '--noprefix' in args 5051 if prefix: 5052 aloha.aloha_prefix='mdl_' 5053 else: 5054 aloha.aloha_prefix='' 5055 5056 try: 5057 self._curr_model = import_ufo.import_model(args[1], prefix=prefix, 5058 complex_mass_scheme=self.options['complex_mass_scheme']) 5059 except import_ufo.UFOImportError, error: 5060 if 'not a valid UFO model' in str(error): 5061 logger_stderr.warning('WARNING: %s' % error) 5062 logger_stderr.warning('Try to recover by running '+\ 5063 'automatically `import model_v4 %s` instead.'% args[1]) 5064 self.exec_cmd('import model_v4 %s ' % args[1], precmd=True) 5065 return 5066 if self.options['gauge']=='unitary': 5067 if not force and isinstance(self._curr_model,\ 5068 loop_base_objects.LoopModel) and \ 5069 self._curr_model.get('perturbation_couplings') not in \ 5070 [[],['QCD']]: 5071 if 1 not in self._curr_model.get('gauge') : 5072 logger_stderr.warning('This model does not allow Feynman '+\ 5073 'gauge. You will only be able to do tree level '+\ 5074 'QCD loop cmputations with it.') 5075 else: 5076 logger.info('Change to the gauge to Feynman because '+\ 5077 'this loop model allows for more than just tree level'+\ 5078 ' and QCD perturbations.') 5079 self.do_set('gauge Feynman', log=False) 5080 return 5081 if 0 not in self._curr_model.get('gauge') : 5082 logger_stderr.warning('Change the gauge to Feynman since '+\ 5083 'the model does not allow unitary gauge') 5084 self.do_set('gauge Feynman', log=False) 5085 return 5086 else: 5087 if 1 not in self._curr_model.get('gauge') : 5088 logger_stderr.warning('Change the gauge to unitary since the'+\ 5089 ' model does not allow Feynman gauge.'+\ 5090 ' Please re-import the model') 5091 self._curr_model = None 5092 self.do_set('gauge unitary', log= False) 5093 return 5094 5095 if '-modelname' not in args: 5096 self._curr_model.pass_particles_name_in_mg_default() 5097 5098 # Do post-processing of model 5099 self.process_model() 5100 # Reset amplitudes and matrix elements and global checks 5101 self._curr_amps = diagram_generation.AmplitudeList() 5102 # Reset proc defs 5103 self._curr_proc_defs = base_objects.ProcessDefinitionList() 5104 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 5105 process_checks.store_aloha = [] 5106 5107 elif args[0] == 'command': 5108 5109 if not os.path.isfile(args[1]): 5110 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1]) 5111 else: 5112 # Check the status of export and try to use file position if no 5113 #self._export dir are define 5114 self.check_for_export_dir(args[1]) 5115 # Execute the card 5116 self.import_command_file(args[1]) 5117 5118 elif args[0] == 'banner': 5119 type = madevent_interface.MadEventCmd.detect_card_type(args[1]) 5120 if type != 'banner': 5121 raise self.InvalidCmd, 'The File should be a valid banner' 5122 ban = banner_module.Banner(args[1]) 5123 # Check that this is MG5 banner 5124 if 'mg5proccard' in ban: 5125 for line in ban['mg5proccard'].split('\n'): 5126 if line.startswith('#') or line.startswith('<'): 5127 continue 5128 self.exec_cmd(line) 5129 else: 5130 raise self.InvalidCmd, 'Only MG5 banner are supported' 5131 5132 if not self._done_export: 5133 self.exec_cmd('output . -f') 5134 5135 ban.split(self._done_export[0]) 5136 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards')) 5137 if '--no_launch' not in args: 5138 self.exec_cmd('launch') 5139 5140 elif args[0] == 'proc_v4': 5141 5142 if len(args) == 1 and self._export_dir: 5143 proc_card = pjoin(self._export_dir, 'Cards', \ 5144 'proc_card.dat') 5145 elif len(args) == 2: 5146 proc_card = args[1] 5147 # Check the status of export and try to use file position is no 5148 # self._export dir are define 5149 self.check_for_export_dir(os.path.realpath(proc_card)) 5150 else: 5151 raise MadGraph5Error('No default directory in output') 5152 5153 5154 #convert and excecute the card 5155 self.import_mg4_proc_card(proc_card)
5156
5157 - def remove_pointless_decay(self, param_card):
5158 """ For simple decay chain: remove diagram that are not in the BR. 5159 param_card should be a ParamCard instance.""" 5160 5161 assert isinstance(param_card, check_param_card.ParamCard) 5162 5163 # Collect amplitudes 5164 amplitudes = diagram_generation.AmplitudeList() 5165 for amp in self._curr_amps: 5166 amplitudes.extend(amp.get_amplitudes()) 5167 5168 decay_tables = param_card['decay'].decay_table 5169 to_remove = [] 5170 for amp in amplitudes: 5171 mother = [l.get('id') for l in amp['process'].get('legs') \ 5172 if not l.get('state')] 5173 if 1 == len(mother): 5174 try: 5175 decay_table = decay_tables[abs(mother[0])] 5176 except KeyError: 5177 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0])) 5178 continue # No BR for this particle -> accept all. 5179 # create the tuple associate to the decay mode 5180 child = [l.get('id') for l in amp['process'].get('legs') \ 5181 if l.get('state')] 5182 if not mother[0] > 0: 5183 child = [x if self._curr_model.get_particle(x)['self_antipart'] 5184 else -x for x in child] 5185 child.sort() 5186 child.insert(0, len(child)) 5187 #check if the decay is present or not: 5188 if tuple(child) not in decay_table.keys(): 5189 to_remove.append(amp) 5190 5191 def remove_amp(amps): 5192 for amp in amps[:]: 5193 if amp in to_remove: 5194 amps.remove(amp) 5195 if isinstance(amp, diagram_generation.DecayChainAmplitude): 5196 remove_amp(amp.get('decay_chains')) 5197 for decay in amp.get('decay_chains'): 5198 remove_amp(decay.get('amplitudes'))
5199 remove_amp(self._curr_amps) 5200 5201
5202 - def import_ufo_model(self, model_name):
5203 """ import the UFO model """ 5204 5205 self._curr_model = import_ufo.import_model(model_name)
5206
5207 - def process_model(self):
5208 """Set variables _particle_names and _couplings for tab 5209 completion, define multiparticles""" 5210 5211 # Set variables for autocomplete 5212 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\ 5213 if p.get('propagating')] + \ 5214 [p.get('antiname') for p in self._curr_model.get('particles') \ 5215 if p.get('propagating')] 5216 5217 self._couplings = list(set(sum([i.get('orders').keys() for i in \ 5218 self._curr_model.get('interactions')], []))) 5219 5220 self.add_default_multiparticles()
5221 5222
5223 - def import_mg4_proc_card(self, filepath):
5224 """ read a V4 proc card, convert it and run it in mg5""" 5225 5226 # change the status of this line in the history -> pass in comment 5227 if self.history and self.history[-1].startswith('import proc_v4'): 5228 self.history[-1] = '#%s' % self.history[-1] 5229 5230 # read the proc_card.dat 5231 reader = files.read_from_file(filepath, import_v4.read_proc_card_v4) 5232 if not reader: 5233 raise self.InvalidCmd('\"%s\" is not a valid path' % filepath) 5234 5235 if self._mgme_dir: 5236 # Add comment to history 5237 self.exec_cmd("# Import the model %s" % reader.model, precmd=True) 5238 line = self.exec_cmd('import model_v4 %s -modelname' % \ 5239 (reader.model), precmd=True) 5240 else: 5241 logging.error('No MG_ME installation detected') 5242 return 5243 5244 5245 # Now that we have the model we can split the information 5246 lines = reader.extract_command_lines(self._curr_model) 5247 for line in lines: 5248 self.exec_cmd(line, precmd=True) 5249 5250 return
5251
5252 - def add_default_multiparticles(self):
5253 """ add default particle from file interface.multiparticles_default.txt 5254 """ 5255 5256 defined_multiparticles = self._multiparticles.keys() 5257 removed_multiparticles = [] 5258 # First check if the defined multiparticles are allowed in the 5259 # new model 5260 5261 for key in self._multiparticles.keys(): 5262 try: 5263 for part in self._multiparticles[key]: 5264 self._curr_model.get('particle_dict')[part] 5265 except Exception: 5266 del self._multiparticles[key] 5267 defined_multiparticles.remove(key) 5268 removed_multiparticles.append(key) 5269 5270 # Now add default multiparticles 5271 for line in open(pjoin(MG5DIR, 'input', \ 5272 'multiparticles_default.txt')): 5273 if line.startswith('#'): 5274 continue 5275 try: 5276 if not self._curr_model['case_sensitive']: 5277 multipart_name = line.lower().split()[0] 5278 else: 5279 multipart_name = line.split()[0] 5280 if multipart_name not in self._multiparticles: 5281 #self.do_define(line) 5282 self.exec_cmd('define %s' % line, printcmd=False, precmd=True) 5283 except self.InvalidCmd, why: 5284 logger_stderr.warning('impossible to set default multiparticles %s because %s' % 5285 (line.split()[0],why)) 5286 if self.history[-1] == 'define %s' % line.strip(): 5287 self.history.pop(-1) 5288 else: 5289 misc.sprint([self.history[-1], 'define %s' % line.strip()]) 5290 5291 scheme = "old" 5292 for qcd_container in ['p', 'j']: 5293 if qcd_container not in self._multiparticles: 5294 continue 5295 multi = self._multiparticles[qcd_container] 5296 b = self._curr_model.get_particle(5) 5297 if not b: 5298 break 5299 5300 if 5 in multi: 5301 if b['mass'] != 'ZERO': 5302 multi.remove(5) 5303 multi.remove(-5) 5304 scheme = 4 5305 elif b['mass'] == 'ZERO': 5306 multi.append(5) 5307 multi.append(-5) 5308 scheme = 5 5309 5310 if scheme in [4,5]: 5311 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme) 5312 for container in ['p', 'j']: 5313 if container in defined_multiparticles: 5314 defined_multiparticles.remove(container) 5315 self.history.append("define p = %s # pass to %s flavors" % \ 5316 (' ' .join([`i` for i in self._multiparticles['p']]), 5317 scheme) 5318 ) 5319 self.history.append("define j = p") 5320 5321 5322 if defined_multiparticles: 5323 if 'all' in defined_multiparticles: 5324 defined_multiparticles.remove('all') 5325 logger.info("Kept definitions of multiparticles %s unchanged" % \ 5326 " / ".join(defined_multiparticles)) 5327 5328 for removed_part in removed_multiparticles: 5329 if removed_part in self._multiparticles: 5330 removed_multiparticles.remove(removed_part) 5331 5332 if removed_multiparticles: 5333 logger.info("Removed obsolete multiparticles %s" % \ 5334 " / ".join(removed_multiparticles)) 5335 5336 # add all tag 5337 line = [] 5338 for part in self._curr_model.get('particles'): 5339 line.append('%s %s' % (part.get('name'), part.get('antiname'))) 5340 line = 'all =' + ' '.join(line) 5341 self.do_define(line)
5342
5343 - def advanced_install(self, tool_to_install, 5344 HepToolsInstaller_web_address=None, 5345 additional_options=[]):
5346 """ Uses the HEPToolsInstaller.py script maintened online to install 5347 HEP tools with more complicated dependences. 5348 Additional options will be added to the list when calling HEPInstaller""" 5349 5350 # prevent border effects 5351 add_options = list(additional_options) 5352 5353 # Always refresh the installer if already present 5354 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')): 5355 if HepToolsInstaller_web_address is None: 5356 raise MadGraph5Error, "The option 'HepToolsInstaller_web_address'"+\ 5357 " must be specified in function advanced_install"+\ 5358 " if the installers are not already downloaded." 5359 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')): 5360 os.mkdir(pjoin(MG5DIR,'HEPTools')) 5361 elif not HepToolsInstaller_web_address is None: 5362 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5363 if not HepToolsInstaller_web_address is None: 5364 logger.info('Downloading the HEPToolInstaller at:\n %s'% 5365 HepToolsInstaller_web_address) 5366 # Guess if it is a local or web address 5367 if '//' in HepToolsInstaller_web_address: 5368 if sys.platform == "darwin": 5369 misc.call(['curl', HepToolsInstaller_web_address, '-o%s' 5370 %pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')], 5371 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'), 5372 cwd=MG5DIR) 5373 else: 5374 misc.call(['wget', HepToolsInstaller_web_address, 5375 '--output-document=%s'% pjoin(MG5DIR,'HEPTools', 5376 'HEPToolsInstallers.tar.gz')], stderr=open(os.devnull, 'w'), 5377 stdout=open(os.devnull, 'w'), cwd=MG5DIR) 5378 else: 5379 # If it is a local tarball, then just copy it 5380 shutil.copyfile(HepToolsInstaller_web_address, 5381 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5382 5383 # Untar the file 5384 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'], 5385 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w')) 5386 5387 # Remove the tarball 5388 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5389 5390 5391 # FOR DEBUGGING ONLY, Take HEPToolsInstaller locally 5392 if '--local' in add_options: 5393 add_options.remove('--local') 5394 logger.warning('you are using a local installer. This is intended for debugging only!') 5395 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5396 shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir, 5397 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5398 5399 # Potential change in naming convention 5400 name_map = {} 5401 try: 5402 tool = name_map[tool_to_install] 5403 except: 5404 tool = tool_to_install 5405 5406 # Compiler options 5407 compiler_options = [] 5408 if self.options['cpp_compiler'] is not None: 5409 compiler_options.append('--cpp_compiler=%s'% 5410 self.options['cpp_compiler']) 5411 compiler_options.append('--cpp_standard_lib=%s'% 5412 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler'])) 5413 elif misc.which('g++'): 5414 compiler_options.append('--cpp_standard_lib=%s'% 5415 misc.detect_cpp_std_lib_dependence('g++')) 5416 else: 5417 compiler_options.append('--cpp_standard_lib=%s'% 5418 misc.detect_cpp_std_lib_dependence(None)) 5419 5420 if not self.options['fortran_compiler'] is None: 5421 compiler_options.append('--fortran_compiler=%s'% 5422 self.options['fortran_compiler']) 5423 5424 if 'heptools_install_dir' in self.options: 5425 prefix = self.options['heptools_install_dir'] 5426 config_file = '~/.mg5/mg5_configuration.txt' 5427 else: 5428 prefix = pjoin(MG5DIR, 'HEPTools') 5429 config_file = '' 5430 5431 # Add the path of pythia8 if known and the MG5 path 5432 if tool=='mg5amc_py8_interface': 5433 add_options.append('--mg5_path=%s'%MG5DIR) 5434 # Warn about the soft dependency to gnuplot 5435 if misc.which('gnuplot') is None: 5436 logger.warning("==========") 5437 logger.warning("The optional dependency 'gnuplot' for the tool"+\ 5438 " 'mg5amc_py8_interface' was not found. We recommend that you"+\ 5439 " install it so as to be able to view the plots related to "+\ 5440 " merging with Pythia 8.") 5441 logger.warning("==========") 5442 if self.options['pythia8_path']: 5443 add_options.append( 5444 '--with_pythia8=%s'%self.options['pythia8_path']) 5445 5446 # Special rules for certain tools 5447 if tool=='madanalysis5': 5448 add_options.append('--mg5_path=%s'%MG5DIR) 5449 if not any(opt.startswith(('--with_fastjet', '--veto_fastjet')) for opt in add_options): 5450 fastjet_config = misc.which(self.options['fastjet']) 5451 if fastjet_config: 5452 add_options.append('--with_fastjet=%s'%fastjet_config) 5453 5454 if self.options['delphes_path'] and os.path.isdir( 5455 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))): 5456 add_options.append('--with_delphes3=%s'%\ 5457 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))) 5458 5459 if tool=='pythia8': 5460 # All what's below is to handle the lhapdf dependency of Pythia8 5461 lhapdf_config = misc.which(self.options['lhapdf']) 5462 lhapdf_version = None 5463 if lhapdf_config is None: 5464 lhapdf_version = None 5465 else: 5466 try: 5467 version = misc.Popen( 5468 [lhapdf_config,'--version'], stdout=subprocess.PIPE) 5469 lhapdf_version = int(version.stdout.read()[0]) 5470 if lhapdf_version not in [5,6]: 5471 raise 5472 except: 5473 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+ 5474 " sure '%s --version ' runs properly."%lhapdf_config) 5475 5476 if lhapdf_version is None: 5477 answer = self.ask(question= 5478 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+ 5479 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >", 5480 default='y',text_format='33;32') 5481 if not answer.lower() in ['y','']: 5482 lhapdf_path = None 5483 else: 5484 self.advanced_install('lhapdf6', 5485 additional_options=add_options) 5486 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6') 5487 lhapdf_version = 6 5488 else: 5489 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\ 5490 lhapdf_config),os.path.pardir)) 5491 if lhapdf_version is None: 5492 logger.warning('You decided not to link the Pythia8 installation'+ 5493 ' to LHAPDF. Beware that only built-in PDF sets can be used then.') 5494 else: 5495 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version) 5496 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN') 5497 lhapdf_option = [] 5498 if lhapdf_version is None: 5499 lhapdf_option.append('--with_lhapdf6=OFF') 5500 lhapdf_option.append('--with_lhapdf5=OFF') 5501 elif lhapdf_version==5: 5502 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path) 5503 lhapdf_option.append('--with_lhapdf6=OFF') 5504 elif lhapdf_version==6: 5505 lhapdf_option.append('--with_lhapdf5=OFF') 5506 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path) 5507 # Make sure each otion in add_options appears only once 5508 add_options = list(set(add_options)) 5509 # And that the option '--force' is placed last. 5510 add_options = [opt for opt in add_options if opt!='--force']+\ 5511 (['--force'] if '--force' in add_options else []) 5512 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5513 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8', 5514 '--prefix=%s' % prefix] 5515 + lhapdf_option + compiler_options + add_options) 5516 else: 5517 logger.info('Now installing %s. Be patient...'%tool) 5518 # Make sure each otion in add_options appears only once 5519 add_options = list(set(add_options)) 5520 # And that the option '--force' is placed last. 5521 add_options = [opt for opt in add_options if opt!='--force']+\ 5522 (['--force'] if '--force' in add_options else []) 5523 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5524 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'% 5525 prefix] + compiler_options + add_options) 5526 5527 if return_code == 0: 5528 logger.info("%s successfully installed in %s."%( 5529 tool_to_install, prefix),'$MG:color:GREEN') 5530 5531 if tool=='madanalysis5': 5532 if not any(o.startswith(('--with_','--veto_','--update')) for o in add_options): 5533 logger.info(' To install recasting capabilities of madanalysis5 and/or', '$MG:color:BLACK') 5534 logger.info(' to allow delphes analysis at parton level.','$MG:color:BLACK') 5535 logger.info(' Please run \'install MadAnalysis5 --with_delphes --update\':', '$MG:color:BLACK') 5536 5537 elif return_code == 66: 5538 answer = self.ask(question= 5539 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, prefix)+ 5540 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >""" 5541 ,default='y',text_format='33;32') 5542 if not answer.lower() in ['y','']: 5543 logger.info("Installation of %s aborted."%tool_to_install, 5544 '$MG:color:GREEN') 5545 return 5546 else: 5547 return self.advanced_install(tool_to_install, 5548 additional_options=add_options+['--force']) 5549 else: 5550 if tool=='madanalysis5' and '--update' not in add_options and \ 5551 ('--no_MA5_further_install' not in add_options or 5552 '--no_root_in_MA5' in add_options): 5553 if not __debug__: 5554 logger.warning('Default installation of Madanalys5 failed.') 5555 logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.") 5556 logger.warning("This will however limit MA5 applicability for hadron-level analysis.") 5557 logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.") 5558 for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']: 5559 if option not in add_options: 5560 add_options.append(option) 5561 self.advanced_install('madanalysis5', 5562 HepToolsInstaller_web_address=HepToolsInstaller_web_address, 5563 additional_options=add_options) 5564 else: 5565 logger.critical("Default installation of Madanalys5 failed, we suggest you try again with the options '--no_MA5_further_install --no_root_in_MA5'.") 5566 raise self.InvalidCmd("Installation of %s failed."%tool_to_install) 5567 5568 # Post-installation treatment 5569 if tool == 'pythia8': 5570 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 5571 self.exec_cmd('save options %s pythia8_path' % config_file, printcmd=False, log=False) 5572 # Automatically re-install the mg5amc_py8_interface after a fresh 5573 # Pythia8 installation 5574 self.advanced_install('mg5amc_py8_interface', 5575 additional_options=add_options+['--force']) 5576 elif tool == 'lhapdf6': 5577 self.options['lhapdf'] = pjoin(prefix,'lhapdf6','bin', 'lhapdf-config') 5578 self.exec_cmd('save options %s lhapdf' % config_file) 5579 elif tool == 'lhapdf5': 5580 self.options['lhapdf'] = pjoin(prefix,'lhapdf5','bin', 'lhapdf-config') 5581 self.exec_cmd('save options %s lhapdf' % config_file, printcmd=False, log=False) 5582 elif tool == 'madanalysis5': 5583 self.options['madanalysis5_path'] = pjoin(prefix, 'madanalysis5','madanalysis5') 5584 self.exec_cmd('save options madanalysis5_path', printcmd=False, log=False) 5585 elif tool == 'mg5amc_py8_interface': 5586 # At this stage, pythia is guaranteed to be installed 5587 if self.options['pythia8_path'] in ['',None,'None']: 5588 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 5589 self.options['mg5amc_py8_interface_path'] = pjoin(prefix, 'MG5aMC_PY8_interface') 5590 self.exec_cmd('save options %s mg5amc_py8_interface_path' % config_file, 5591 printcmd=False, log=False) 5592 elif tool == 'collier': 5593 self.options['collier'] = pjoin(prefix,'lib') 5594 self.exec_cmd('save options %s collier' % config_file, printcmd=False, log=False) 5595 elif tool == 'ninja': 5596 if not misc.get_ninja_quad_prec_support(pjoin( 5597 prefix,'ninja','lib')): 5598 logger.warning( 5599 """Successful installation of Ninja, but without support for quadruple precision 5600 arithmetics. If you want to enable this (hence improving the treatment of numerically 5601 unstable points in the loop matrix elements) you can try to reinstall Ninja with: 5602 MG5aMC>install ninja 5603 After having made sure to have selected a C++ compiler in the 'cpp' option of 5604 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""") 5605 self.options['ninja'] = pjoin(prefix,'lib') 5606 self.exec_cmd('save options %s ninja' % config_file, printcmd=False, log=False) 5607 5608 # Now warn the user if he didn't add HEPTools first in his environment 5609 # variables. 5610 path_to_be_set = [] 5611 if sys.platform == "darwin": 5612 library_variables = ["DYLD_LIBRARY_PATH"] 5613 else: 5614 library_variables = ["LD_LIBRARY_PATH"] 5615 for variable in library_variables: 5616 if (variable not in os.environ) or \ 5617 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\ 5618 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 5619 path_to_be_set.append((variable, 5620 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib')))) 5621 for variable in ["PATH"]: 5622 if (variable not in os.environ) or \ 5623 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\ 5624 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 5625 path_to_be_set.append((variable, 5626 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin')))) 5627 if (variable not in os.environ) or \ 5628 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\ 5629 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 5630 path_to_be_set.append((variable, 5631 os.path.abspath(pjoin(MG5DIR,'HEPTools','include')))) 5632 5633 if len(path_to_be_set)>0: 5634 shell_type = misc.get_shell_type() 5635 if shell_type in ['bash',None]: 5636 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.bashrc"%\ 5637 (r'\n'.join('export %s=%s%s'% 5638 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 5639 elif shell_type=='tcsh': 5640 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.cshrc"%\ 5641 (r'\n'.join('setenv %s %s%s'% 5642 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 5643 5644 logger.debug("==========") 5645 logger.debug("We recommend that you add to the following paths"+\ 5646 " to your environment variables, so that you are guaranteed that"+\ 5647 " at runtime, MG5_aMC will use the tools you have just installed"+\ 5648 " and not some other versions installed elsewhere on your system.\n"+\ 5649 "You can do so by running the following command in your terminal:" 5650 "\n %s"%modification_line) 5651 logger.debug("==========") 5652 5653 # Return true for successful installation 5654 return True
5655
5656 - def do_install(self, line, paths=None, additional_options=[]):
5657 """Install optional package from the MG suite. 5658 The argument 'additional_options' will be passed to the advanced_install 5659 functions. If it contains the option '--force', then the advanced_install 5660 function will overwrite any existing installation of the tool without 5661 warnings. 5662 """ 5663 5664 # Make sure to avoid any border effect on custom_additional_options 5665 add_options = list(additional_options) 5666 5667 args = self.split_arg(line) 5668 #check the validity of the arguments 5669 install_options = self.check_install(args) 5670 5671 if sys.platform == "darwin": 5672 program = "curl" 5673 else: 5674 program = "wget" 5675 5676 # special command for auto-update 5677 if args[0] == 'update': 5678 self.install_update(['update']+install_options['update_options'],wget=program) 5679 return 5680 5681 plugin = ['maddm'] 5682 5683 advertisements = {'pythia-pgs':['arXiv:0603175'], 5684 'Delphes':['arXiv:1307.6346'], 5685 'Delphes2':['arXiv:0903.2225'], 5686 'SysCalc':['arXiv:XXXX.YYYYY'], 5687 'Golem95':['arXiv:0807.0605'], 5688 'PJFry':['arXiv:1210.4095','arXiv:1112.0500'], 5689 'QCDLoop':['arXiv:0712.1851'], 5690 'pythia8':['arXiv:1410.3012'], 5691 'lhapdf6':['arXiv:1412.7420'], 5692 'lhapdf5':['arXiv:0605240'], 5693 'hepmc':['CPC 134 (2001) 41-46'], 5694 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'], 5695 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'], 5696 'MadAnalysis5':['arXiv:1206.1599'], 5697 'MadAnalysis':['arXiv:1206.1599'], 5698 'collier':['arXiv:1604.06792'], 5699 'oneloop':['arXiv:1007.4716'], 5700 'maddm':['arXiv:1505.04190']} 5701 5702 5703 if args[0] in advertisements: 5704 # logger.info('{:^80}'.format("-"*70), '$MG:color:BLACK') 5705 # logger.info('{:^80}'.format("You are installing '%s', please cite ref(s):"%args[0]), '$MG:color:BLACK') 5706 # logger.info('{:^80}'.format(', '.join(advertisements[args[0]])), '$MG:color:GREEN') 5707 # logger.info('{:^80}'.format("when using results produced with this tool."), '$MG:color:BLACK') 5708 # logger.info('{:^80}'.format("-"*70), '$MG:color:BLACK') 5709 logger.info(" You are installing '%s', please cite ref(s): \033[92m%s\033[0m. " % (args[0], ', '.join(advertisements[args[0]])), '$MG:color:BLACK') 5710 5711 # Load file with path of the different program: 5712 import urllib 5713 if paths: 5714 path = paths 5715 else: 5716 path = {} 5717 5718 data_path = ['http://madgraph.phys.ucl.ac.be/package_info.dat', 5719 'http://madgraph.physics.illinois.edu/package_info.dat'] 5720 5721 r = random.randint(0,1) 5722 r = [r, (1-r)] 5723 # Force here to choose one particular server 5724 if any(a.startswith('--source=') for a in args): 5725 source = [a[9:] for a in args if a.startswith('--source=')][-1] 5726 if source == 'uiuc': 5727 r = [1] 5728 elif source == 'ucl': 5729 r = [0] 5730 else: 5731 data_path.append(source) 5732 r = [2] 5733 else: 5734 r = random.randint(0,1) 5735 r = [r, (1-r)] 5736 5737 5738 5739 for index in r: 5740 cluster_path = data_path[index] 5741 try: 5742 data = urllib.urlopen(cluster_path) 5743 except Exception: 5744 continue 5745 break 5746 else: 5747 raise MadGraph5Error, '''Impossible to connect any of us servers. 5748 Please check your internet connection or retry later''' 5749 for line in data: 5750 split = line.split() 5751 path[split[0]] = split[1] 5752 5753 ################################################################################ 5754 # TEMPORARY HACK WHERE WE ADD ENTRIES TO WHAT WILL BE EVENTUALLY ON THE WEB 5755 ################################################################################ 5756 # path['XXX'] = 'YYY' 5757 ################################################################################ 5758 5759 if args[0] == 'Delphes': 5760 args[0] = 'Delphes3' 5761 5762 try: 5763 name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes', 5764 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs', 5765 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'madanalysis5', 5766 'MadAnalysis4':'MadAnalysis', 5767 'SysCalc':'SysCalc', 'Golem95': 'golem95', 5768 'PJFry':'PJFry','QCDLoop':'QCDLoop','MadAnalysis5':'madanalysis5' 5769 } 5770 name = name[args[0]] 5771 except KeyError: 5772 name = args[0] 5773 5774 if args[0] in self._advanced_install_opts: 5775 # Now launch the advanced installation of the tool args[0] 5776 # path['HEPToolsInstaller'] is the online adress where to downlaod 5777 # the installers if necessary. 5778 # Specify the path of the MG5_aMC_interface 5779 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \ 5780 'MG5aMC_PY8_interface' in path else 'NA' 5781 add_options.append('--mg5amc_py8_interface_tarball=%s'%\ 5782 MG5aMC_PY8_interface_path) 5783 add_options.extend(install_options['options_for_HEPToolsInstaller']) 5784 if not any(opt.startswith('--logging=') for opt in add_options): 5785 add_options.append('--logging=%d' % logger.level) 5786 5787 return self.advanced_install(name, path['HEPToolsInstaller'], 5788 additional_options = add_options) 5789 5790 if args[0] == 'PJFry' and not os.path.exists( 5791 pjoin(MG5DIR,'QCDLoop','lib','libqcdloop1.a')): 5792 logger.info("Installing PJFRY's dependence QCDLoop...") 5793 self.do_install('QCDLoop', paths=path) 5794 5795 if args[0] == 'Delphes': 5796 args[0] = 'Delphes3' 5797 if args[0] == 'MadAnalysis4': 5798 args[0] = 'MadAnalysis' 5799 try: 5800 name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes', 5801 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs', 5802 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'MadAnalysis', 5803 'SysCalc':'SysCalc', 'Golem95': 'golem95', 5804 'PJFry':'PJFry','QCDLoop':'QCDLoop', 5805 'maddm':'maddm' 5806 } 5807 name = name[args[0]] 5808 except: 5809 pass 5810 5811 #check outdated install 5812 substitution={'Delphes2':'Delphes','pythia-pgs':'pythia8'} 5813 if args[0] in substitution: 5814 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\ 5815 " You should consider installing and using %s, with:\n"%substitution[args[0]]+ 5816 " > install %s"%substitution[args[0]]) 5817 5818 try: 5819 os.system('rm -rf %s' % pjoin(MG5DIR, name)) 5820 except Exception: 5821 pass 5822 5823 # Load that path 5824 logger.info('Downloading %s' % path[args[0]]) 5825 if sys.platform == "darwin": 5826 misc.call(['curl', path[args[0]], '-o%s.tgz' % name], cwd=MG5DIR) 5827 else: 5828 misc.call(['wget', path[args[0]], '--output-document=%s.tgz'% name], cwd=MG5DIR) 5829 5830 # Untar the file 5831 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 5832 stdout=open(os.devnull, 'w')) 5833 5834 if returncode: 5835 raise MadGraph5Error, 'Fail to download correctly the File. Stop' 5836 5837 5838 # Check that the directory has the correct name 5839 if not os.path.exists(pjoin(MG5DIR, name)): 5840 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith( 5841 name.lower()) and not n.endswith('gz')] 5842 if not created_name: 5843 raise MadGraph5Error, 'The file was not loaded correctly. Stop' 5844 else: 5845 created_name = created_name[0] 5846 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name)) 5847 5848 5849 logger.info('compile %s. This might take a while.' % name) 5850 5851 # Modify Makefile for pythia-pgs on Mac 64 bit 5852 if args[0] == "pythia-pgs" and sys.maxsize > 2**32: 5853 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 5854 text = open(path).read() 5855 text = text.replace('MBITS=32','MBITS=64') 5856 open(path, 'w').writelines(text) 5857 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')): 5858 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')) 5859 5860 make_flags = [] #flags for the compilation 5861 # Compile the file 5862 # Check for F77 compiler 5863 if 'FC' not in os.environ or not os.environ['FC']: 5864 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None': 5865 compiler = self.options['fortran_compiler'] 5866 elif misc.which('gfortran'): 5867 compiler = 'gfortran' 5868 elif misc.which('g77'): 5869 compiler = 'g77' 5870 else: 5871 raise self.InvalidCmd('Require g77 or Gfortran compiler') 5872 5873 path = None 5874 base_compiler= ['FC=g77','FC=gfortran'] 5875 if args[0] == "pythia-pgs": 5876 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 5877 elif args[0] == 'MadAnalysis': 5878 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile') 5879 if path: 5880 text = open(path).read() 5881 for base in base_compiler: 5882 text = text.replace(base,'FC=%s' % compiler) 5883 open(path, 'w').writelines(text) 5884 os.environ['FC'] = compiler 5885 5886 # For Golem95, use autotools. 5887 if name == 'golem95': 5888 # Run the configure script 5889 ld_path = misc.Popen(['./configure', 5890 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']], 5891 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0] 5892 5893 # For PJFry, use autotools. 5894 if name == 'PJFry': 5895 # Run the configure script 5896 ld_path = misc.Popen(['./configure', 5897 '--prefix=%s'%str(pjoin(MG5DIR, name)), 5898 '--enable-golem-mode', '--with-integrals=qcdloop1', 5899 'LDFLAGS=-L%s'%str(pjoin(MG5DIR,'QCDLoop','lib')), 5900 'FC=%s'%os.environ['FC'], 5901 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 5902 stdout=subprocess.PIPE).communicate()[0] 5903 5904 # For QCDLoop, use autotools. 5905 if name == 'QCDLoop': 5906 # Run the configure script 5907 ld_path = misc.Popen(['./configure', 5908 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'], 5909 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 5910 stdout=subprocess.PIPE).communicate()[0] 5911 5912 # For Delphes edit the makefile to add the proper link to correct library 5913 if args[0] == 'Delphes3': 5914 #change in the makefile 5915 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) 5916 # to 5917 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,/Applications/root_v6.04.08/lib/ 5918 rootsys = os.environ['ROOTSYS'] 5919 text = open(pjoin(MG5DIR, 'Delphes','Makefile')).read() 5920 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)', 5921 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys) 5922 open(pjoin(MG5DIR, 'Delphes','Makefile'),'w').write(text) 5923 5924 # For SysCalc link to lhapdf 5925 if name == 'SysCalc': 5926 if self.options['lhapdf']: 5927 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'], 5928 stdout=subprocess.PIPE).communicate()[0] 5929 ld_path = ld_path.replace('\n','') 5930 if 'LD_LIBRARY_PATH' not in os.environ: 5931 os.environ['LD_LIBRARY_PATH'] = ld_path 5932 elif not os.environ['LD_LIBRARY_PATH']: 5933 os.environ['LD_LIBRARY_PATH'] = ld_path 5934 elif ld_path not in os.environ['LD_LIBRARY_PATH']: 5935 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path 5936 if self.options['lhapdf'] != 'lhapdf-config': 5937 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']): 5938 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH']) 5939 else: 5940 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6') 5941 if self.options['cpp_compiler']: 5942 make_flags.append('CXX=%s' % self.options['cpp_compiler']) 5943 5944 5945 if name in plugin: 5946 logger.info('no compilation needed for plugin. Loading plugin information') 5947 try: 5948 shutil.rmtree(pjoin(MG5DIR, 'PLUGIN', name)) 5949 except Exception: 5950 pass 5951 shutil.move(pjoin(os.path.join(MG5DIR, name)), os.path.join(MG5DIR, 'PLUGIN', name)) 5952 # read the __init__.py to check if we need to add a new executable 5953 try: 5954 __import__('PLUGIN.%s' % name, globals(), locals(), [], -1) 5955 plugin = sys.modules['PLUGIN.%s' % name] 5956 new_interface = plugin.new_interface 5957 new_output = plugin.new_output 5958 latest_validated_version = plugin.latest_validated_version 5959 minimal_mg5amcnlo_version = plugin.minimal_mg5amcnlo_version 5960 maximal_mg5amcnlo_version = plugin.maximal_mg5amcnlo_version 5961 except Exception, error: 5962 raise Exception, 'Plugin %s fail to be loaded. Please contact the author of the PLUGIN\n Error %s' % (name, error) 5963 5964 logger.info('Plugin %s correctly interfaced. Latest official validition for MG5aMC version %s.' % (name, '.'.join(`i` for i in latest_validated_version))) 5965 if new_interface: 5966 ff = open(pjoin(MG5DIR, 'bin', '%s.py' % name) , 'w') 5967 if __debug__: 5968 text = '''#! /usr/bin/env python 5969 import os 5970 import sys 5971 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 5972 exe_path = os.path.join(root_path,'bin','mg5_aMC') 5973 sys.argv.pop(0) 5974 os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 5975 '''.format(name) 5976 else: 5977 text = '''#! /usr/bin/env python 5978 import os 5979 import sys 5980 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 5981 exe_path = os.path.join(root_path,'bin','mg5_aMC') 5982 sys.argv.pop(0) 5983 os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 5984 '''.format(name) 5985 ff.write(text) 5986 ff.close() 5987 import stat 5988 os.chmod(pjoin(MG5DIR, 'bin', '%s.py' % name), stat.S_IRWXU) 5989 logger.info('To use this module, you need to quite MG5aMC and run the executable bin/%s.py' % name) 5990 status=0 5991 5992 elif logger.level <= logging.INFO: 5993 devnull = open(os.devnull,'w') 5994 try: 5995 misc.call(['make', 'clean'], stdout=devnull, stderr=-2) 5996 except Exception: 5997 pass 5998 if name == 'pythia-pgs': 5999 #SLC6 needs to have this first (don't ask why) 6000 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6001 if name in ['golem95','QCDLoop','PJFry']: 6002 status = misc.call(['make','install'], 6003 cwd = os.path.join(MG5DIR, name)) 6004 else: 6005 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name)) 6006 else: 6007 try: 6008 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6009 except Exception: 6010 pass 6011 if name == 'pythia-pgs': 6012 #SLC6 needs to have this first (don't ask why) 6013 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6014 if name in ['golem95','QCDLoop','PJFry']: 6015 status = misc.compile(['install'], mode='', 6016 cwd = os.path.join(MG5DIR, name)) 6017 else: 6018 status = self.compile(make_flags, mode='', 6019 cwd = os.path.join(MG5DIR, name)) 6020 6021 if not status: 6022 logger.info('Installation succeeded') 6023 else: 6024 # For pythia-pgs check when removing the "-fno-second-underscore" flag 6025 if name == 'pythia-pgs': 6026 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio', 6027 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch'] 6028 for f in to_comment: 6029 f = pjoin(MG5DIR, name, *f.split('/')) 6030 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l) 6031 fsock = open(f,'w').write(text) 6032 try: 6033 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6034 except Exception: 6035 pass 6036 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name)) 6037 if not status: 6038 logger.info('Compilation succeeded') 6039 else: 6040 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.') 6041 6042 6043 # Special treatment for TD/Ghostscript program (require by MadAnalysis) 6044 if args[0] == 'MadAnalysis': 6045 try: 6046 os.system('rm -rf td') 6047 os.mkdir(pjoin(MG5DIR, 'td')) 6048 except Exception, error: 6049 print error 6050 pass 6051 6052 if sys.platform == "darwin": 6053 logger.info('Downloading TD for Mac') 6054 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td_mac_intel.tar.gz' 6055 misc.call(['curl', target, '-otd.tgz'], 6056 cwd=pjoin(MG5DIR,'td')) 6057 misc.call(['tar', '-xzpvf', 'td.tgz'], 6058 cwd=pjoin(MG5DIR,'td')) 6059 files.mv(MG5DIR + '/td/td_mac_intel',MG5DIR+'/td/td') 6060 else: 6061 if sys.maxsize > 2**32: 6062 logger.info('Downloading TD for Linux 64 bit') 6063 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td64/td' 6064 logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer. 6065 In 99% of the case, this is perfectly fine. If you do not have plot, please follow 6066 instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''') 6067 else: 6068 logger.info('Downloading TD for Linux 32 bit') 6069 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td' 6070 misc.call(['wget', target], cwd=pjoin(MG5DIR,'td')) 6071 os.chmod(pjoin(MG5DIR,'td','td'), 0775) 6072 self.options['td_path'] = pjoin(MG5DIR,'td') 6073 6074 if not misc.which('gs'): 6075 logger.warning('''gosthscript not install on your system. This is not required to run MA. 6076 but this prevent to create jpg files and therefore to have the plots in the html output.''') 6077 if sys.platform == "darwin": 6078 logger.warning('''You can download this program at the following link: 6079 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''') 6080 6081 if args[0] == 'Delphes2': 6082 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read() 6083 data = data.replace('data/', 'DELPHESDIR/data/') 6084 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w') 6085 out.write(data) 6086 if args[0] == 'Delphes3': 6087 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')): 6088 card_dir = pjoin(MG5DIR, 'Delphes','cards') 6089 else: 6090 card_dir = pjoin(MG5DIR, 'Delphes','examples') 6091 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6092 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat')) 6093 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6094 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat')) 6095 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'), 6096 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat')) 6097 6098 6099 #reset the position of the executable 6100 options_name = {'Delphes': 'delphes_path', 6101 'Delphes2': 'delphes_path', 6102 'Delphes3': 'delphes_path', 6103 'ExRootAnalysis': 'exrootanalysis_path', 6104 'MadAnalysis': 'madanalysis_path', 6105 'SysCalc': 'syscalc_path', 6106 'pythia-pgs':'pythia-pgs_path', 6107 'Golem95': 'golem', 6108 'PJFry': 'pjfry'} 6109 6110 if args[0] in options_name: 6111 opt = options_name[args[0]] 6112 if opt=='golem': 6113 self.options[opt] = pjoin(MG5DIR,name,'lib') 6114 self.exec_cmd('save options', printcmd=False) 6115 elif opt=='pjfry': 6116 self.options[opt] = pjoin(MG5DIR,'PJFry','lib') 6117 self.exec_cmd('save options', printcmd=False) 6118 elif self.options[opt] != self.options_configuration[opt]: 6119 self.options[opt] = self.options_configuration[opt] 6120 self.exec_cmd('save options',printcmd=False)
6121 6122 6123
6124 - def install_update(self, args, wget):
6125 """ check if the current version of mg5 is up-to-date. 6126 and allow user to install the latest version of MG5 """ 6127 6128 def apply_patch(filetext): 6129 """function to apply the patch""" 6130 text = filetext.read() 6131 pattern = re.compile(r'''=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6132 #=== renamed directory 'Template' => 'Template/LO' 6133 for orig, new in pattern.findall(text): 6134 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP')) 6135 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6136 for i, name in enumerate(full_path): 6137 path = os.path.sep.join(full_path[:i+1]) 6138 if path and not os.path.isdir(path): 6139 os.mkdir(path) 6140 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new)) 6141 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP')) 6142 # track rename since patch fail to apply those correctly. 6143 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6144 #=== renamed file 'Template/SubProcesses/addmothers.f' => 'madgraph/iolibs/template_files/addmothers.f' 6145 for orig, new in pattern.findall(text): 6146 print 'move %s to %s' % (orig, new) 6147 try: 6148 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6149 except IOError: 6150 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6151 for i, name in enumerate(full_path): 6152 path = os.path.sep.join(full_path[:i+1]) 6153 if path and not os.path.isdir(path): 6154 os.mkdir(path) 6155 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6156 # track remove/re-added file: 6157 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M) 6158 all_add = pattern.findall(text) 6159 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6160 #all_rm = pattern.findall(text) 6161 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S) 6162 print 'this step can take a few minuts. please be patient' 6163 all_rm_add = pattern.findall(text) 6164 #=== added file 'tests/input_files/full_sm/interactions.dat' 6165 for new in all_add: 6166 if new in all_rm_add: 6167 continue 6168 if os.path.isfile(pjoin(MG5DIR, new)): 6169 os.remove(pjoin(MG5DIR, new)) 6170 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6171 #=== removed file 'tests/input_files/full_sm/interactions.dat' 6172 #for old in pattern.findall(text): 6173 # if not os.path.isfile(pjoin(MG5DIR, old)): 6174 # full_path = os.path.dirname(pjoin(MG5DIR, old)).split('/') 6175 # for i, _ in enumerate(full_path): 6176 # path = os.path.sep.join(full_path[:i+1]) 6177 # if path and not os.path.isdir(path): 6178 # os.mkdir(path) 6179 # subprocess.call(['touch', pjoin(MG5DIR, old)]) 6180 6181 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE, 6182 cwd=MG5DIR) 6183 p.communicate(text) 6184 6185 # check file which are not move 6186 #=== modified file 'Template/LO/Cards/run_card.dat' 6187 #--- old/Template/Cards/run_card.dat 2012-12-06 10:01:04 +0000 6188 #+++ new/Template/LO/Cards/run_card.dat 2013-12-09 02:35:59 +0000 6189 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6190 for match in pattern.findall(text): 6191 new = pjoin(MG5DIR, match[0]) 6192 old = pjoin(MG5DIR, match[1]) 6193 if new == old: 6194 continue 6195 elif os.path.exists(old): 6196 if not os.path.exists(os.path.dirname(new)): 6197 split = new.split('/') 6198 for i in range(1,len(split)): 6199 path = '/'.join(split[:i]) 6200 if not os.path.exists(path): 6201 print 'mkdir', path 6202 os.mkdir(path) 6203 files.cp(old,new) 6204 #=== renamed file 'Template/bin/internal/run_delphes' => 'Template/Common/bin/internal/run_delphes' 6205 #--- old/Template/bin/internal/run_delphes 2011-12-09 07:28:10 +0000 6206 #+++ new/Template/Common/bin/internal/run_delphes 2012-10-23 02:41:37 +0000 6207 #pattern=re.compile('''=== renamed file \'(?P<old>[^\']*)\' => \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P=old)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6208 #for match in pattern.findall(text): 6209 # old = pjoin(MG5DIR, match[0]) 6210 # new = pjoin(MG5DIR, match[1]) 6211 # if new == old: 6212 # continue 6213 # elif os.path.exists(old): 6214 # if not os.path.exists(os.path.dirname(new)): 6215 # split = new.split('/') 6216 # for i in range(1,len(split)): 6217 # path = '/'.join(split[:i]) 6218 # if not os.path.exists(path): 6219 # print 'mkdir', path 6220 # os.mkdir(path) 6221 # files.cp(old,new) 6222 6223 # check that all files in bin directory are executable 6224 for path in misc.glob('*', pjoin(MG5DIR, 'bin')): 6225 misc.call(['chmod', '+x', path]) 6226 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')): 6227 misc.call(['chmod', '+x', path]) 6228 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')): 6229 misc.call(['chmod', '+x', path]) 6230 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')): 6231 misc.call(['chmod', '+x', path]) 6232 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')): 6233 misc.call(['chmod', '+x', path]) 6234 6235 #add empty files/directory 6236 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M) 6237 for match in pattern.findall(text): 6238 if match[0] == 'file': 6239 new = os.path.dirname(pjoin(MG5DIR, match[1])) 6240 else: 6241 new = pjoin(MG5DIR, match[1]) 6242 if not os.path.exists(new): 6243 split = new.split('/') 6244 for i in range(1,len(split)+1): 6245 path = '/'.join(split[:i]) 6246 if path and not os.path.exists(path): 6247 print 'mkdir', path 6248 os.mkdir(path) 6249 if match[0] == 'file': 6250 print 'touch ', pjoin(MG5DIR, match[1]) 6251 misc.call(['touch', pjoin(MG5DIR, match[1])]) 6252 # add new symlink 6253 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M) 6254 for new, old in pattern.findall(text): 6255 if not os.path.exists(pjoin(MG5DIR, new)): 6256 files.ln(old, os.path.dirname(new), os.path.basename(new)) 6257 6258 # Re-compile CutTools and IREGI 6259 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')): 6260 misc.compile(arg=['-j1'],cwd=pjoin(MG5DIR,'vendor','CutTools'),nb_core=1) 6261 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')): 6262 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src')) 6263 6264 # check if it need to download binary: 6265 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M) 6266 if pattern.search(text): 6267 return True 6268 else: 6269 return False
6270 6271 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')] 6272 if mode: 6273 mode = mode[-1] 6274 else: 6275 mode = "userrequest" 6276 force = any([arg=='-f' for arg in args]) 6277 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')] 6278 if timeout: 6279 try: 6280 timeout = int(timeout[-1]) 6281 except ValueError: 6282 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1]) 6283 else: 6284 timeout = self.options['timeout'] 6285 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')] 6286 6287 if input_path: 6288 fsock = open(input_path[0]) 6289 need_binary = apply_patch(fsock) 6290 logger.info('manual patch apply. Please test your version.') 6291 if need_binary: 6292 logger.warning('Note that some files need to be loaded separately!') 6293 sys.exit(0) 6294 6295 options = ['y','n','on_exit'] 6296 if mode == 'mg5_start': 6297 timeout = 2 6298 default = 'n' 6299 update_delay = self.options['auto_update'] * 24 * 3600 6300 if update_delay == 0: 6301 return 6302 elif mode == 'mg5_end': 6303 timeout = 5 6304 default = 'n' 6305 update_delay = self.options['auto_update'] * 24 * 3600 6306 if update_delay == 0: 6307 return 6308 options.remove('on_exit') 6309 elif mode == "userrequest": 6310 default = 'y' 6311 update_delay = 0 6312 else: 6313 raise self.InvalidCmd('Unknown mode for command install update') 6314 6315 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')) or \ 6316 os.path.exists(os.path.join(MG5DIR,'.bzr')): 6317 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are: 6318 1) This version was loaded via bazaar (use bzr pull to update instead). 6319 2) This version is a beta release of MG5.""" 6320 if mode == 'userrequest': 6321 raise self.ConfigurationError(error_text) 6322 return 6323 6324 if not misc.which('patch'): 6325 error_text = """Not able to find program \'patch\'. Please reload a clean version 6326 or install that program and retry.""" 6327 if mode == 'userrequest': 6328 raise self.ConfigurationError(error_text) 6329 return 6330 6331 # read the data present in .autoupdate 6332 data = {} 6333 for line in open(os.path.join(MG5DIR,'input','.autoupdate')): 6334 if not line.strip(): 6335 continue 6336 sline = line.split() 6337 data[sline[0]] = int(sline[1]) 6338 6339 #check validity of the file 6340 if 'version_nb' not in data: 6341 if mode == 'userrequest': 6342 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)' 6343 raise self.ConfigurationError(error_text) 6344 return 6345 elif 'last_check' not in data: 6346 data['last_check'] = time.time() 6347 6348 #check if we need to update. 6349 if time.time() - data['last_check'] < update_delay: 6350 return 6351 6352 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout) 6353 class TimeOutError(Exception): pass 6354 6355 def handle_alarm(signum, frame): 6356 raise TimeOutError 6357 6358 signal.signal(signal.SIGALRM, handle_alarm) 6359 signal.alarm(timeout) 6360 to_update = 0 6361 try: 6362 filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/mg5amc_build_nb') 6363 signal.alarm(0) 6364 web_version = int(filetext.read().strip()) 6365 except (TimeOutError, ValueError, IOError): 6366 signal.alarm(0) 6367 print 'failed to connect server' 6368 if mode == 'mg5_end': 6369 # wait 24h before next check 6370 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6371 fsock.write("version_nb %s\n" % data['version_nb']) 6372 fsock.write("last_check %s\n" % \ 6373 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1)) 6374 fsock.close() 6375 return 6376 6377 if web_version == data['version_nb']: 6378 logger.info('No new version of MG5 available') 6379 # update .autoupdate to prevent a too close check 6380 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6381 fsock.write("version_nb %s\n" % data['version_nb']) 6382 fsock.write("last_check %s\n" % int(time.time())) 6383 fsock.close() 6384 return 6385 elif data['version_nb'] > web_version: 6386 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version)) 6387 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6388 fsock.write("version_nb %s\n" % data['version_nb']) 6389 fsock.write("last_check %s\n" % int(time.time())) 6390 fsock.close() 6391 return 6392 else: 6393 if not force: 6394 answer = self.ask('New Version of MG5 available! Do you want to update your current version?', 6395 default, options) 6396 else: 6397 answer = default 6398 6399 6400 if answer == 'y': 6401 logger.info('start updating code') 6402 fail = 0 6403 for i in range(data['version_nb'], web_version): 6404 try: 6405 filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1)) 6406 # filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/patch_test/build%s.patch' %(i+1)) 6407 except Exception: 6408 print 'fail to load patch to build #%s' % (i+1) 6409 fail = i 6410 break 6411 need_binary = apply_patch(filetext) 6412 if need_binary: 6413 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1) 6414 name = "extra_file%i" % (i+1) 6415 if sys.platform == "darwin": 6416 misc.call(['curl', path, '-o%s.tgz' % name], cwd=MG5DIR) 6417 else: 6418 misc.call(['wget', path, '--output-document=%s.tgz'% name], cwd=MG5DIR) 6419 # Untar the file 6420 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6421 stdout=open(os.devnull, 'w')) 6422 6423 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6424 if not fail: 6425 fsock.write("version_nb %s\n" % web_version) 6426 else: 6427 fsock.write("version_nb %s\n" % fail) 6428 fsock.write("last_check %s\n" % int(time.time())) 6429 fsock.close() 6430 logger.info('Refreshing installation of MG5aMC_PY8_interface.') 6431 self.do_install('mg5amc_py8_interface',additional_options=['--force']) 6432 logger.info('Checking current version. (type ctrl-c to bypass the check)') 6433 subprocess.call([os.path.join('tests','test_manager.py')], 6434 cwd=MG5DIR) 6435 print 'new version installed, please relaunch mg5' 6436 try: 6437 os.remove(pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6438 shutil.copy(pjoin(MG5DIR, 'Template','LO','Source','.make_opts'), 6439 pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6440 except: 6441 pass 6442 sys.exit(0) 6443 elif answer == 'n': 6444 # prevent for a future check 6445 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6446 fsock.write("version_nb %s\n" % data['version_nb']) 6447 fsock.write("last_check %s\n" % int(time.time())) 6448 fsock.close() 6449 logger.info('Update bypassed.') 6450 logger.info('The next check for a new version will be performed in %s days' \ 6451 % abs(self.options['auto_update'])) 6452 logger.info('In order to change this delay. Enter the command:') 6453 logger.info('set auto_update X') 6454 logger.info('Putting X to zero will prevent this check at anytime.') 6455 logger.info('You can upgrade your version at any time by typing:') 6456 logger.info('install update') 6457 else: #answer is on_exit 6458 #ensure that the test will be done on exit 6459 #Do not use the set command here!! 6460 self.options['auto_update'] = -1 * self.options['auto_update'] 6461 6462 6463
6464 - def set_configuration(self, config_path=None, final=True):
6465 """ assign all configuration variable from file 6466 ./input/mg5_configuration.txt. assign to default if not define """ 6467 6468 if not self.options: 6469 self.options = dict(self.options_configuration) 6470 self.options.update(self.options_madgraph) 6471 self.options.update(self.options_madevent) 6472 6473 if not config_path: 6474 if os.environ.has_key('MADGRAPH_BASE'): 6475 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 6476 self.set_configuration(config_path, final=False) 6477 if 'HOME' in os.environ: 6478 config_path = pjoin(os.environ['HOME'],'.mg5', 6479 'mg5_configuration.txt') 6480 if os.path.exists(config_path): 6481 self.set_configuration(config_path, final=False) 6482 config_path = os.path.relpath(pjoin(MG5DIR,'input', 6483 'mg5_configuration.txt')) 6484 return self.set_configuration(config_path, final) 6485 6486 if not os.path.exists(config_path): 6487 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path) 6488 config_file = open(config_path) 6489 6490 # read the file and extract information 6491 logger.info('load MG5 configuration from %s ' % config_file.name) 6492 for line in config_file: 6493 if '#' in line: 6494 line = line.split('#',1)[0] 6495 line = line.replace('\n','').replace('\r\n','') 6496 try: 6497 name, value = line.split('=') 6498 except ValueError: 6499 pass 6500 else: 6501 name = name.strip() 6502 value = value.strip() 6503 if name != 'mg5_path': 6504 self.options[name] = value 6505 if value.lower() == "none" or value=="": 6506 self.options[name] = None 6507 config_file.close() 6508 self.options['stdout_level'] = logging.getLogger('madgraph').level 6509 if not final: 6510 return self.options # the return is usefull for unittest 6511 6512 # Treat each expected input 6513 # 1: Pythia8_path and hewrig++ paths 6514 # try absolute and relative path 6515 for key in self.options: 6516 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path', 6517 'mg5amc_py8_interface_path','madanalysis5_path']: 6518 if self.options[key] in ['None', None]: 6519 self.options[key] = None 6520 continue 6521 path = self.options[key] 6522 #this is for pythia8 6523 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')): 6524 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')): 6525 self.options['pythia8_path'] = None 6526 else: 6527 continue 6528 #this is for mg5amc_py8_interface_path 6529 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')): 6530 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')): 6531 self.options['mg5amc_py8_interface_path'] = None 6532 else: 6533 continue 6534 #this is for madanalysis5 6535 if key == 'madanalysis5_path' and not os.path.isfile(pjoin(MG5DIR, path,'bin','ma5')): 6536 if not os.path.isfile(pjoin(path,'bin','ma5')): 6537 self.options['madanalysis5_path'] = None 6538 else: 6539 continue 6540 #this is for hw++ 6541 if key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 6542 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 6543 self.options['hwpp_path'] = None 6544 else: 6545 continue 6546 # this is for thepeg 6547 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 6548 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 6549 self.options['thepeg_path'] = None 6550 else: 6551 continue 6552 # this is for hepmc 6553 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 6554 if not os.path.isfile(pjoin(path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 6555 self.options['hepmc_path'] = None 6556 else: 6557 continue 6558 6559 elif key in ['pjfry','golem','samurai']: 6560 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto': 6561 # try to find it automatically on the system 6562 program = misc.which_lib('lib%s.a'%key) 6563 if program != None: 6564 fpath, _ = os.path.split(program) 6565 logger.info('Using %s library in %s' % (key,fpath)) 6566 self.options[key]=fpath 6567 else: 6568 # Try to look for it locally 6569 local_install = {'pjfry':'PJFRY', 'golem':'golem95', 6570 'samurai':'samurai'} 6571 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)): 6572 self.options[key]=pjoin(MG5DIR,local_install[key],'lib') 6573 else: 6574 self.options[key]=None 6575 # Make sure that samurai version is recent enough 6576 if key=='samurai' and \ 6577 isinstance(self.options[key],str) and \ 6578 self.options[key].lower() != 'auto': 6579 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')): 6580 try: 6581 version = open(pjoin(self.options[key],os.pardir, 6582 'VERSION'),'r').read() 6583 except IOError: 6584 version = None 6585 if version is None: 6586 self.options[key] = None 6587 logger.info('--------') 6588 logger.info( 6589 """The version of 'samurai' automatically detected seems too old to be compatible 6590 with MG5aMC and it will be turned off. Ask the authors for the latest version if 6591 you want to use samurai. 6592 If you want to enforce its use as-it-is, then specify directly its library folder 6593 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""") 6594 logger.info('--------') 6595 6596 elif key.endswith('path'): 6597 pass 6598 elif key in ['run_mode', 'auto_update']: 6599 self.options[key] = int(self.options[key]) 6600 elif key in ['cluster_type','automatic_html_opening']: 6601 pass 6602 elif key in ['notification_center']: 6603 if self.options[key] in ['False', 'True']: 6604 self.allow_notification_center = eval(self.options[key]) 6605 self.options[key] = self.allow_notification_center 6606 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']: 6607 # Default: try to set parameter 6608 try: 6609 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 6610 except MadGraph5Error, error: 6611 print error 6612 logger.warning("Option %s from config file not understood" \ 6613 % key) 6614 else: 6615 if key in self.options_madgraph: 6616 self.history.append('set %s %s' % (key, self.options[key])) 6617 6618 warnings = madevent_interface.MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options) 6619 if warnings: 6620 logger.warning(warnings) 6621 6622 # Configure the way to open a file: 6623 launch_ext.open_file.configure(self.options) 6624 return self.options
6625
6626 - def check_for_export_dir(self, filepath):
6627 """Check if the files is in a valid export directory and assign it to 6628 export path if if is""" 6629 6630 # keep previous if a previous one is defined 6631 if self._export_dir: 6632 return 6633 6634 if os.path.exists(pjoin(os.getcwd(), 'Cards')): 6635 self._export_dir = os.getcwd() 6636 return 6637 6638 path_split = filepath.split(os.path.sep) 6639 if len(path_split) > 2 and path_split[-2] == 'Cards': 6640 self._export_dir = os.path.sep.join(path_split[:-2]) 6641 return
6642
6643 - def do_launch(self, line):
6644 """Main commands: Ask for editing the parameter and then 6645 Execute the code (madevent/standalone/...) 6646 """ 6647 6648 #ensure that MG option are not modified by the launch routine 6649 current_options = dict([(name, self.options[name]) for name in self.options_madgraph]) 6650 start_cwd = os.getcwd() 6651 6652 args = self.split_arg(line) 6653 # check argument validity and normalise argument 6654 (options, args) = _launch_parser.parse_args(args) 6655 self.check_launch(args, options) 6656 options = options.__dict__ 6657 # args is now MODE PATH 6658 6659 if args[0].startswith('standalone'): 6660 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\ 6661 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\ 6662 os.getcwd(),args[1],'SubProcesses','check_poles.f')): 6663 ext_program = launch_ext.MadLoopLauncher(self, args[1], \ 6664 options=self.options, **options) 6665 else: 6666 ext_program = launch_ext.SALauncher(self, args[1], \ 6667 options=self.options, **options) 6668 elif args[0] == 'madevent': 6669 if options['interactive']: 6670 6671 if isinstance(self, cmd.CmdShell): 6672 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options) 6673 else: 6674 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options) 6675 ME.pass_in_web_mode() 6676 stop = self.define_child_cmd_interface(ME) 6677 return stop 6678 6679 #check if this is a cross-section 6680 if not self._generate_info: 6681 # This relaunch an old run -> need to check if this is a 6682 # cross-section or a width 6683 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read() 6684 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1] 6685 generate_info = generate_info.split('#')[0] 6686 else: 6687 generate_info = self._generate_info 6688 6689 if len(generate_info.split('>')[0].strip().split())>1: 6690 ext_program = launch_ext.MELauncher(args[1], self, 6691 shell = isinstance(self, cmd.CmdShell), 6692 options=self.options,**options) 6693 else: 6694 # This is a width computation 6695 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV', 6696 shell = isinstance(self, cmd.CmdShell), 6697 options=self.options,**options) 6698 6699 elif args[0] == 'pythia8': 6700 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options) 6701 6702 elif args[0] == 'aMC@NLO': 6703 if options['interactive']: 6704 if isinstance(self, cmd.CmdShell): 6705 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options) 6706 else: 6707 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options) 6708 ME.pass_in_web_mode() 6709 # transfer interactive configuration 6710 config_line = [l for l in self.history if l.strip().startswith('set')] 6711 for line in config_line: 6712 ME.exec_cmd(line) 6713 stop = self.define_child_cmd_interface(ME) 6714 return stop 6715 ext_program = launch_ext.aMCatNLOLauncher( args[1], self, 6716 shell = isinstance(self, cmd.CmdShell), 6717 **options) 6718 elif args[0] == 'madweight': 6719 import madgraph.interface.madweight_interface as madweight_interface 6720 if options['interactive']: 6721 if isinstance(self, cmd.CmdShell): 6722 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options) 6723 else: 6724 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options) 6725 # transfer interactive configuration 6726 config_line = [l for l in self.history if l.strip().startswith('set')] 6727 for line in config_line: 6728 MW.exec_cmd(line) 6729 stop = self.define_child_cmd_interface(MW) 6730 return stop 6731 ext_program = launch_ext.MWLauncher( self, args[1], 6732 shell = isinstance(self, cmd.CmdShell), 6733 options=self.options,**options) 6734 else: 6735 os.chdir(start_cwd) #ensure to go to the initial path 6736 raise self.InvalidCmd , '%s cannot be run from MG5 interface' % args[0] 6737 6738 6739 ext_program.run() 6740 os.chdir(start_cwd) #ensure to go to the initial path 6741 # ensure that MG options are not changed! 6742 for key, value in current_options.items(): 6743 self.options[key] = value
6744
6745 - def do_load(self, line):
6746 """Not in help: Load information from file""" 6747 6748 args = self.split_arg(line) 6749 # check argument validity 6750 self.check_load(args) 6751 6752 cpu_time1 = time.time() 6753 if args[0] == 'model': 6754 self._curr_model = save_load_object.load_from_file(args[1]) 6755 if self._curr_model.get('parameters'): 6756 # This is a UFO model 6757 self._model_v4_path = None 6758 else: 6759 # This is a v4 model 6760 self._model_v4_path = import_v4.find_model_path(\ 6761 self._curr_model.get('name').replace("_v4", ""), 6762 self._mgme_dir) 6763 6764 # Do post-processing of model 6765 self.process_model() 6766 6767 #save_model.save_model(args[1], self._curr_model) 6768 if isinstance(self._curr_model, base_objects.Model): 6769 cpu_time2 = time.time() 6770 logger.info("Loaded model from file in %0.3f s" % \ 6771 (cpu_time2 - cpu_time1)) 6772 else: 6773 raise self.RWError('Could not load model from file %s' \ 6774 % args[1]) 6775 elif args[0] == 'processes': 6776 amps,proc_defs = save_load_object.load_from_file(args[1]) 6777 if isinstance(amps, diagram_generation.AmplitudeList): 6778 cpu_time2 = time.time() 6779 logger.info("Loaded processes from file in %0.3f s" % \ 6780 (cpu_time2 - cpu_time1)) 6781 if amps: 6782 model = amps[0].get('process').get('model') 6783 if not model.get('parameters'): 6784 # This is a v4 model. Look for path. 6785 self._model_v4_path = import_v4.find_model_path(\ 6786 model.get('name').replace("_v4", ""), 6787 self._mgme_dir) 6788 else: 6789 self._model_v4_path = None 6790 # If not exceptions from previous steps, set 6791 # _curr_amps and _curr_model 6792 self._curr_amps = amps 6793 self._curr_model = model 6794 self._curr_proc_defs = proc_defs 6795 logger.info("Model set from process.") 6796 # Do post-processing of model 6797 self.process_model() 6798 self._done_export = None 6799 else: 6800 raise self.RWError('Could not load processes from file %s' % args[1])
6801 6802
6803 - def do_customize_model(self, line):
6804 """create a restriction card in a interactive way""" 6805 6806 args = self.split_arg(line) 6807 self.check_customize_model(args) 6808 6809 model_path = self._curr_model.get('modelpath') 6810 if not os.path.exists(pjoin(model_path,'build_restrict.py')): 6811 raise self.InvalidCmd('''Model not compatible with this option.''') 6812 6813 # (re)import the full model (get rid of the default restriction) 6814 self._curr_model = import_ufo.import_model(model_path, restrict=False) 6815 6816 #1) create the full param_card 6817 out_path = StringIO.StringIO() 6818 param_writer.ParamCardWriter(self._curr_model, out_path) 6819 # and load it to a python object 6820 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 6821 6822 6823 all_categories = self.ask('','0',[], ask_class=AskforCustomize) 6824 put_to_one = [] 6825 ## Make a Temaplate for the restriction card. (card with no restrict) 6826 for block in param_card: 6827 value_dict = {} 6828 for param in param_card[block]: 6829 value = param.value 6830 if value == 0: 6831 param.value = 0.000001e-99 6832 elif value == 1: 6833 if block != 'qnumbers': 6834 put_to_one.append((block,param.lhacode)) 6835 param.value = random.random() 6836 elif abs(value) in value_dict: 6837 param.value += value_dict[abs(value)] * 1e-4 * param.value 6838 value_dict[abs(value)] += 1 6839 else: 6840 value_dict[abs(value)] = 1 6841 6842 for category in all_categories: 6843 for options in category: 6844 if not options.status: 6845 continue 6846 param = param_card[options.lhablock].get(options.lhaid) 6847 param.value = options.value 6848 6849 logger.info('Loading the resulting model') 6850 # Applying the restriction 6851 self._curr_model = import_ufo.RestrictModel(self._curr_model) 6852 model_name = self._curr_model.get('name') 6853 if model_name == 'mssm': 6854 keep_external=True 6855 else: 6856 keep_external=False 6857 self._curr_model.restrict_model(param_card,keep_external=keep_external) 6858 6859 if args: 6860 name = args[0].split('=',1)[1] 6861 path = pjoin(model_path,'restrict_%s.dat' % name) 6862 logger.info('Save restriction file as %s' % path) 6863 param_card.write(path) 6864 self._curr_model['name'] += '-%s' % name 6865 6866 # if some need to put on one 6867 if put_to_one: 6868 out_path = StringIO.StringIO() 6869 param_writer.ParamCardWriter(self._curr_model, out_path) 6870 # and load it to a python object 6871 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 6872 6873 for (block, lhacode) in put_to_one: 6874 misc.sprint(block, lhacode) 6875 try: 6876 param_card[block].get(lhacode).value = 1 6877 except: 6878 pass # was removed of the model! 6879 self._curr_model.set_parameters_and_couplings(param_card) 6880 6881 if args: 6882 name = args[0].split('=',1)[1] 6883 path = pjoin(model_path,'paramcard_%s.dat' % name) 6884 logger.info('Save default card file as %s' % path) 6885 param_card.write(path)
6886
6887 - def do_save(self, line, check=True, to_keep={}, log=True):
6888 """Not in help: Save information to file""" 6889 6890 args = self.split_arg(line) 6891 # Check argument validity 6892 if check: 6893 self.check_save(args) 6894 6895 if args[0] == 'model': 6896 if self._curr_model: 6897 #save_model.save_model(args[1], self._curr_model) 6898 if save_load_object.save_to_file(args[1], self._curr_model): 6899 logger.info('Saved model to file %s' % args[1]) 6900 else: 6901 raise self.InvalidCmd('No model to save!') 6902 elif args[0] == 'processes': 6903 if self._curr_amps: 6904 if save_load_object.save_to_file(args[1], (self._curr_amps,self._curr_proc_defs) ): 6905 logger.info('Saved processes to file %s' % args[1]) 6906 else: 6907 raise self.InvalidCmd('No processes to save!') 6908 6909 elif args[0] == 'options': 6910 partial_save = False 6911 to_define = {} 6912 6913 if any(not arg.startswith('--') and arg in self.options 6914 for arg in args): 6915 # store in file only those ones 6916 partial_save = True 6917 all_arg = [arg for arg in args[1:] if not arg.startswith('--') and 6918 arg in self.options] 6919 for key in all_arg: 6920 to_define[key] = self.options[key] 6921 else: 6922 # First look at options which should be put in MG5DIR/input 6923 for key, default in self.options_configuration.items(): 6924 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None: 6925 to_define[key] = self.options[key] 6926 6927 if not '--auto' in args: 6928 for key, default in self.options_madevent.items(): 6929 if self.options_madevent[key] != self.options[key] != None: 6930 if '_path' in key and os.path.basename(self.options[key]) == 'None': 6931 continue 6932 to_define[key] = self.options[key] 6933 elif key == 'cluster_queue' and self.options[key] is None: 6934 to_define[key] = self.options[key] 6935 6936 if '--all' in args: 6937 for key, default in self.options_madgraph.items(): 6938 if self.options_madgraph[key] != self.options[key] != None and \ 6939 key != 'stdout_level': 6940 to_define[key] = self.options[key] 6941 elif not '--auto' in args: 6942 for key, default in self.options_madgraph.items(): 6943 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level': 6944 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 6945 % (key,self.options_madgraph[key]) ) 6946 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 6947 6948 if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options: 6949 filepath = args[1] 6950 else: 6951 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 6952 6953 basedir = MG5DIR 6954 if partial_save: 6955 basefile = filepath 6956 else: 6957 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt') 6958 6959 6960 6961 if to_keep: 6962 to_define = to_keep 6963 self.write_configuration(filepath, basefile, basedir, to_define)
6964 6965 # Set an option
6966 - def do_set(self, line, log=True, model_reload=True):
6967 """Set an option, which will be default for coming generations/outputs. 6968 """ 6969 6970 # Be careful: 6971 # This command is associated to a post_cmd: post_set. 6972 args = self.split_arg(line) 6973 6974 # Check the validity of the arguments 6975 self.check_set(args) 6976 6977 if args[0] == 'ignore_six_quark_processes': 6978 if args[1] == 'False': 6979 self.options[args[0]] = False 6980 return 6981 self.options[args[0]] = list(set([abs(p) for p in \ 6982 self._multiparticles[args[1]]\ 6983 if self._curr_model.get_particle(p).\ 6984 is_fermion() and \ 6985 self._curr_model.get_particle(abs(p)).\ 6986 get('color') == 3])) 6987 if log: 6988 logger.info('Ignore processes with >= 6 quarks (%s)' % \ 6989 ",".join([\ 6990 self._curr_model.get_particle(q).get('name') \ 6991 for q in self.options[args[0]]])) 6992 6993 elif args[0] == 'group_subprocesses': 6994 if args[1] not in ['Auto', 'NLO']: 6995 self.options[args[0]] = eval(args[1]) 6996 else: 6997 self.options[args[0]] = args[1] 6998 if log: 6999 logger.info('Set group_subprocesses to %s' % \ 7000 str(self.options[args[0]])) 7001 logger.info('Note that you need to regenerate all processes') 7002 self._curr_amps = diagram_generation.AmplitudeList() 7003 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7004 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7005 7006 elif args[0] == "stdout_level": 7007 if args[1].isdigit(): 7008 level = int(args[1]) 7009 else: 7010 level = eval('logging.' + args[1]) 7011 logging.root.setLevel(level) 7012 logging.getLogger('madgraph').setLevel(level) 7013 logging.getLogger('madevent').setLevel(level) 7014 self.options[args[0]] = level 7015 if log: 7016 logger.info('set output information to level: %s' % level) 7017 elif args[0].lower() == "ewscheme": 7018 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." %\ 7019 (self._curr_model.get('name'), args[1])) 7020 logger.info("Importing a model will restore the default scheme") 7021 self._curr_model.change_electroweak_mode(args[1]) 7022 elif args[0] == "complex_mass_scheme": 7023 old = self.options[args[0]] 7024 self.options[args[0]] = eval(args[1]) 7025 aloha.complex_mass = eval(args[1]) 7026 aloha_lib.KERNEL.clean() 7027 if self.options[args[0]]: 7028 if old: 7029 if log: 7030 logger.info('Complex mass already activated.') 7031 return 7032 if log: 7033 logger.info('Activate complex mass scheme.') 7034 else: 7035 if not old: 7036 if log: 7037 logger.info('Complex mass already desactivated.') 7038 return 7039 if log: 7040 logger.info('Desactivate complex mass scheme.') 7041 if not self._curr_model: 7042 return 7043 self.exec_cmd('import model %s' % self._curr_model.get('name')) 7044 7045 elif args[0] == "gauge": 7046 # Treat the case where they are no model loaded 7047 if not self._curr_model: 7048 if args[1] == 'unitary': 7049 aloha.unitary_gauge = True 7050 else: 7051 aloha.unitary_gauge = False 7052 aloha_lib.KERNEL.clean() 7053 self.options[args[0]] = args[1] 7054 if log: logger.info('Passing to gauge %s.' % args[1]) 7055 return 7056 7057 # They are a valid model 7058 able_to_mod = True 7059 if args[1] == 'unitary': 7060 if 0 in self._curr_model.get('gauge'): 7061 aloha.unitary_gauge = True 7062 else: 7063 able_to_mod = False 7064 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \ 7065 % self._curr_model.get('name')) 7066 else: 7067 if 1 in self._curr_model.get('gauge'): 7068 aloha.unitary_gauge = False 7069 else: 7070 able_to_mod = False 7071 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \ 7072 % self._curr_model.get('name')) 7073 7074 if self.options['gauge'] == args[1]: 7075 return 7076 7077 7078 self.options[args[0]] = args[1] 7079 7080 if able_to_mod and log and args[0] == 'gauge' and \ 7081 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \ 7082 isinstance(self._curr_model,loop_base_objects.LoopModel) and \ 7083 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 7084 logger.warning('You will only be able to do tree level'+\ 7085 ' and QCD corrections in the unitary gauge.') 7086 7087 7088 7089 #re-init all variable 7090 model_name = self._curr_model.get('modelpath+restriction') 7091 self._curr_model = None 7092 self._curr_amps = diagram_generation.AmplitudeList() 7093 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7094 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7095 self._curr_helas_model = None 7096 self._curr_exporter = None 7097 self._done_export = False 7098 import_ufo._import_once = [] 7099 logger.info('Passing to gauge %s.' % args[1]) 7100 7101 if able_to_mod: 7102 # We don't want to go through the MasterCommand again 7103 # because it messes with the interface switching when 7104 # importing a loop model from MG5 7105 MadGraphCmd.do_import(self,'model %s' %model_name, force=True) 7106 elif log: 7107 logger.info('Note that you have to reload the model') 7108 7109 elif args[0] == 'fortran_compiler': 7110 if args[1] != 'None': 7111 if log: 7112 logger.info('set fortran compiler to %s' % args[1]) 7113 self.options['fortran_compiler'] = args[1] 7114 else: 7115 self.options['fortran_compiler'] = None 7116 elif args[0] == 'f2py_compiler': 7117 if args[1] != 'None': 7118 if log: 7119 logger.info('set f2py compiler to %s' % args[1]) 7120 self.options['f2py_compiler'] = args[1] 7121 else: 7122 self.options['f2py_compiler'] = None 7123 7124 elif args[0] == 'loop_optimized_output': 7125 if log: 7126 logger.info('set loop optimized output to %s' % args[1]) 7127 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7128 self.options[args[0]] = args[1] 7129 if not self.options['loop_optimized_output'] and \ 7130 self.options['loop_color_flows']: 7131 logger.warning("Turning off option 'loop_color_flows'"+\ 7132 " since it is not available for non-optimized loop output.") 7133 self.do_set('loop_color_flows False',log=False) 7134 elif args[0] == 'loop_color_flows': 7135 if log: 7136 logger.info('set loop color flows to %s' % args[1]) 7137 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7138 self.options[args[0]] = args[1] 7139 if self.options['loop_color_flows'] and \ 7140 not self.options['loop_optimized_output']: 7141 logger.warning("Turning on option 'loop_optimized'"+\ 7142 " needed for loop color flow computation.") 7143 self.do_set('loop_optimized_output True',False) 7144 7145 elif args[0] == 'fastjet': 7146 try: 7147 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE, 7148 stderr=subprocess.PIPE) 7149 output, error = p.communicate() 7150 res = 0 7151 except Exception: 7152 res = 1 7153 7154 if res != 0 or error: 7155 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \ 7156 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \ 7157 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' + 7158 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n') 7159 self.options[args[0]] = None 7160 self.history.pop() 7161 elif int(output.split('.')[0]) < 3: 7162 logger.warning('%s is not ' % args[1] + \ 7163 'v3 or greater. Please install FastJet v3+.') 7164 self.options[args[0]] = None 7165 self.history.pop() 7166 else: #everything is fine 7167 logger.info('set fastjet to %s' % args[1]) 7168 self.options[args[0]] = args[1] 7169 7170 elif args[0] in ['pjfry','golem','samurai','ninja','collier'] and \ 7171 not (args[0] in ['ninja','collier'] and args[1]=='./HEPTools/lib'): 7172 if args[1] in ['None',"''",'""']: 7173 self.options[args[0]] = None 7174 else: 7175 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0])) 7176 if program!=None: 7177 res = 0 7178 logger.info('set %s to %s' % (args[0],args[1])) 7179 self.options[args[0]] = args[1] 7180 else: 7181 res = 1 7182 7183 if res != 0 : 7184 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \ 7185 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \ 7186 'You will NOT be able to run %s otherwise.\n'%args[0]) 7187 7188 elif args[0] == 'lhapdf': 7189 try: 7190 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE, 7191 stderr=subprocess.PIPE) 7192 logger.info('set lhapdf to %s' % args[1]) 7193 self.options[args[0]] = args[1] 7194 except Exception: 7195 res = 1 7196 if res != 0: 7197 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \ 7198 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \ 7199 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \ 7200 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \ 7201 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n') 7202 7203 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry', 7204 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']: 7205 self.options[args[0]] = int(args[1]) 7206 7207 elif args[0] in ['cluster_local_path']: 7208 self.options[args[0]] = args[1].strip() 7209 7210 elif args[0] == 'cluster_status_update': 7211 if '(' in args[1]: 7212 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 7213 data = data.replace('(','').replace(')','').replace(',',' ').split() 7214 first, second = data[:2] 7215 else: 7216 first, second = args[1:3] 7217 7218 self.options[args[0]] = (int(first), int(second)) 7219 7220 elif args[0] == 'OLP': 7221 # Reset the amplitudes, MatrixElements and exporter as they might 7222 # depend on this option 7223 self._curr_amps = diagram_generation.AmplitudeList() 7224 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7225 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7226 self._curr_exporter = None 7227 self.options[args[0]] = args[1] 7228 7229 elif args[0] =='output_dependencies': 7230 self.options[args[0]] = args[1] 7231 elif args[0] =='notification_center': 7232 if args[1] in ['None','True','False']: 7233 self.options[args[0]] = eval(args[1]) 7234 self.allow_notification_center = self.options[args[0]] 7235 else: 7236 raise self.InvalidCmd('expected bool for notification_center') 7237 elif args[0] in ['cluster_queue']: 7238 self.options[args[0]] = args[1].strip() 7239 elif args[0] in self.options: 7240 if args[1] in ['None','True','False']: 7241 self.options[args[0]] = eval(args[1]) 7242 else: 7243 self.options[args[0]] = args[1]
7244
7245 - def post_set(self, stop, line):
7246 """Check if we need to save this in the option file""" 7247 7248 args = self.split_arg(line) 7249 # Check the validity of the arguments 7250 try: 7251 self.check_set(args, log=False) 7252 except Exception: 7253 return stop 7254 7255 if args[0] in self.options_configuration and '--no_save' not in args: 7256 self.exec_cmd('save options --auto', log=False) 7257 elif args[0] in self.options_madevent: 7258 if not '--no_save' in line: 7259 logger.info('This option will be the default in any output that you are going to create in this session.') 7260 logger.info('In order to keep this changes permanent please run \'save options\'') 7261 else: 7262 #MadGraph5_aMC@NLO configuration 7263 if not self.history or self.history[-1].split() != line.split(): 7264 self.history.append('set %s' % line) 7265 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set']) 7266 return stop
7267
7268 - def do_open(self, line):
7269 """Open a text file/ eps file / html file""" 7270 7271 args = self.split_arg(line) 7272 # Check Argument validity and modify argument to be the real path 7273 self.check_open(args) 7274 file_path = args[0] 7275 7276 launch_ext.open_file(file_path)
7277
7278 - def do_output(self, line):
7279 """Main commands: Initialize a new Template or reinitialize one""" 7280 7281 args = self.split_arg(line) 7282 # Check Argument validity 7283 self.check_output(args) 7284 7285 7286 noclean = '-noclean' in args 7287 force = '-f' in args 7288 nojpeg = '-nojpeg' in args 7289 flaglist = [] 7290 7291 if '--postpone_model' in args: 7292 flaglist.append('store_model') 7293 7294 main_file_name = "" 7295 try: 7296 main_file_name = args[args.index('-name') + 1] 7297 except Exception: 7298 pass 7299 7300 7301 ################ 7302 # ALOHA OUTPUT # 7303 ################ 7304 if self._export_format == 'aloha': 7305 # catch format 7306 format = [d[9:] for d in args if d.startswith('--format=')] 7307 if not format: 7308 format = 'Fortran' 7309 else: 7310 format = format[-1] 7311 # catch output dir 7312 output = [d for d in args if d.startswith('--output=')] 7313 if not output: 7314 output = import_ufo.find_ufo_path(self._curr_model['name']) 7315 output = pjoin(output, format) 7316 if not os.path.isdir(output): 7317 os.mkdir(output) 7318 else: 7319 output = output[-1] 7320 if not os.path.isdir(output): 7321 raise self.InvalidCmd('%s is not a valid directory' % output) 7322 logger.info('creating routines in directory %s ' % output) 7323 # build the calling list for aloha 7324 names = [d for d in args if not d.startswith('-')] 7325 wanted_lorentz = aloha_fct.guess_routine_from_name(names) 7326 # Create and write ALOHA Routine 7327 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name')) 7328 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz')) 7329 if wanted_lorentz: 7330 aloha_model.compute_subset(wanted_lorentz) 7331 else: 7332 aloha_model.compute_all(save=False) 7333 aloha_model.write(output, format) 7334 return 7335 7336 ################# 7337 ## Other Output # 7338 ################# 7339 # Configuration of what to do: 7340 # check: check status of the directory 7341 # exporter: which exporter to use (v4/cpp/...) 7342 # output: [Template/dir/None] copy the Template, just create dir or do nothing 7343 config = {} 7344 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7345 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'} 7346 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7347 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7348 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7349 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7350 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'} 7351 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'} 7352 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} 7353 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'} 7354 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7355 7356 if self._export_format == 'plugin': 7357 options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output} 7358 else: 7359 options = config[self._export_format] 7360 7361 # check 7362 if os.path.realpath(self._export_dir) == os.getcwd(): 7363 if len(args) == 0: 7364 i=0 7365 while 1: 7366 if os.path.exists('Pythia8_proc_%i' %i): 7367 i+=1 7368 else: 7369 break 7370 os.mkdir('Pythia8_proc_%i' %i) 7371 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i) 7372 logger.info('Create output in %s' % self._export_dir) 7373 elif not args[0] in ['.', '-f']: 7374 raise self.InvalidCmd, 'Wrong path directory to create in local directory use \'.\'' 7375 elif not noclean and os.path.isdir(self._export_dir) and options['check']: 7376 if not force: 7377 # Don't ask if user already specified force or noclean 7378 logger.info('INFO: directory %s already exists.' % self._export_dir) 7379 logger.info('If you continue this directory will be deleted and replaced.') 7380 answer = self.ask('Do you want to continue?', 'y', ['y','n']) 7381 else: 7382 answer = 'y' 7383 if answer != 'y': 7384 raise self.InvalidCmd('Stopped by user request') 7385 else: 7386 shutil.rmtree(self._export_dir) 7387 7388 # Choose here whether to group subprocesses or not, if the option was 7389 # set to 'Auto' and propagate this choice down the line: 7390 if self.options['group_subprocesses'] in [True, False]: 7391 group_processes = self.options['group_subprocesses'] 7392 elif self.options['group_subprocesses'] == 'Auto': 7393 # By default we set it to True 7394 group_processes = True 7395 # But we turn if off for decay processes which 7396 # have been defined with multiparticle labels, because then 7397 # branching ratios necessitates to keep subprocesses independent. 7398 # That applies only if there is more than one subprocess of course. 7399 if self._curr_amps[0].get_ninitial() == 1 and \ 7400 len(self._curr_amps)>1: 7401 processes = [amp.get('process') for amp in self._curr_amps] 7402 if len(set(proc.get('id') for proc in processes))!=len(processes): 7403 # Special warning for loop-induced 7404 if any(proc['perturbation_couplings'] != [] for proc in 7405 processes) and self._export_format == 'madevent': 7406 logger.warning(""" 7407 || The loop-induced decay process you have specified contains several 7408 || subprocesses and, in order to be able to compute individual branching ratios, 7409 || MG5_aMC will *not* group them. Integration channels will also be considered 7410 || for each diagrams and as a result integration will be inefficient. 7411 || It is therefore recommended to perform this simulation by setting the MG5_aMC 7412 || option 'group_subprocesses' to 'True' (before the output of the process). 7413 || Notice that when doing so, processes for which one still wishes to compute 7414 || branching ratios independently can be specified using the syntax: 7415 || -> add process <proc_def> 7416 """) 7417 group_processes = False 7418 7419 #Exporter + Template 7420 if options['exporter'] == 'v4': 7421 self._curr_exporter = export_v4.ExportV4Factory(self, noclean, 7422 group_subprocesses=group_processes) 7423 elif options['exporter'] == 'cpp': 7424 self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes) 7425 7426 self._curr_exporter.pass_information_from_cmd(self) 7427 7428 if options['output'] == 'Template': 7429 self._curr_exporter.copy_template(self._curr_model) 7430 elif options['output'] == 'dir' and not os.path.isdir(self._export_dir): 7431 os.makedirs(self._export_dir) 7432 7433 # Reset _done_export, since we have new directory 7434 self._done_export = False 7435 7436 if self._export_format == "madevent": 7437 # for MadEvent with MadLoop decide if we keep the box as channel of 7438 #integration or not. Forbid them for matching and for h+j 7439 if self.options['max_npoint_for_channel']: 7440 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel'] 7441 else: 7442 base_objects.Vertex.max_n_loop_for_multichanneling = 3 7443 7444 # Perform export and finalize right away 7445 self.export(nojpeg, main_file_name, group_processes, args) 7446 7447 # Automatically run finalize 7448 self.finalize(nojpeg, flaglist=flaglist) 7449 7450 # Remember that we have done export 7451 self._done_export = (self._export_dir, self._export_format) 7452 7453 # Reset _export_dir, so we don't overwrite by mistake later 7454 self._export_dir = None
7455 7456 # Export a matrix element
7457 - def export(self, nojpeg = False, main_file_name = "", group_processes=True, 7458 args=[]):
7459 """Export a generated amplitude to file.""" 7460 7461 # Define the helas call writer 7462 if self._curr_exporter.exporter == 'cpp': 7463 self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model) 7464 elif self._model_v4_path: 7465 assert self._curr_exporter.exporter == 'v4' 7466 self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model) 7467 else: 7468 assert self._curr_exporter.exporter == 'v4' 7469 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 7470 7471 version = [arg[10:] for arg in args if arg.startswith('--version=')] 7472 if version: 7473 version = version[-1] 7474 else: 7475 version = '8.2' 7476 7477 def generate_matrix_elements(self, group_processes=True): 7478 """Helper function to generate the matrix elements before 7479 exporting. Uses the main function argument 'group_processes' to decide 7480 whether to use group_subprocess or not. (it has been set in do_output to 7481 the appropriate value if the MG5 option 'group_subprocesses' was set 7482 to 'Auto'.""" 7483 7484 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']: 7485 to_distinguish = [] 7486 for part in self._curr_model.get('particles'): 7487 if part.get('name') in args and part.get('antiname') in args and\ 7488 part.get('name') != part.get('antiname'): 7489 to_distinguish.append(abs(part.get('pdg_code'))) 7490 # Sort amplitudes according to number of diagrams, 7491 # to get most efficient multichannel output 7492 self._curr_amps.sort(lambda a1, a2: a2.get_number_of_diagrams() - \ 7493 a1.get_number_of_diagrams()) 7494 7495 cpu_time1 = time.time() 7496 ndiags = 0 7497 if not self._curr_matrix_elements.get_matrix_elements(): 7498 if group_processes: 7499 cpu_time1 = time.time() 7500 dc_amps = diagram_generation.DecayChainAmplitudeList(\ 7501 [amp for amp in self._curr_amps if isinstance(amp, \ 7502 diagram_generation.DecayChainAmplitude)]) 7503 non_dc_amps = diagram_generation.AmplitudeList(\ 7504 [amp for amp in self._curr_amps if not \ 7505 isinstance(amp, \ 7506 diagram_generation.DecayChainAmplitude)]) 7507 subproc_groups = group_subprocs.SubProcessGroupList() 7508 matrix_elements_opts = {'optimized_output': 7509 self.options['loop_optimized_output']} 7510 7511 grouping_criteria = self._curr_exporter.grouped_mode 7512 if non_dc_amps: 7513 subproc_groups.extend(\ 7514 group_subprocs.SubProcessGroup.group_amplitudes(\ 7515 non_dc_amps,grouping_criteria, 7516 matrix_elements_opts=matrix_elements_opts)) 7517 7518 if dc_amps: 7519 dc_subproc_group = \ 7520 group_subprocs.DecayChainSubProcessGroup.\ 7521 group_amplitudes(dc_amps, grouping_criteria, 7522 matrix_elements_opts=matrix_elements_opts) 7523 subproc_groups.extend(dc_subproc_group.\ 7524 generate_helas_decay_chain_subproc_groups()) 7525 7526 ndiags = sum([len(m.get('diagrams')) for m in \ 7527 subproc_groups.get_matrix_elements()]) 7528 self._curr_matrix_elements = subproc_groups 7529 # assign a unique id number to all groups 7530 uid = 0 7531 for group in subproc_groups: 7532 uid += 1 # update the identification number 7533 for me in group.get('matrix_elements'): 7534 me.get('processes')[0].set('uid', uid) 7535 else: # Not grouped subprocesses 7536 mode = {} 7537 if self._export_format in [ 'standalone_msP' , 7538 'standalone_msF', 'standalone_rw']: 7539 mode['mode'] = 'MadSpin' 7540 # The conditional statement tests whether we are dealing 7541 # with a loop induced process. 7542 if isinstance(self._curr_amps[0], 7543 loop_diagram_generation.LoopAmplitude): 7544 mode['optimized_output']=self.options['loop_optimized_output'] 7545 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess 7546 compute_loop_nc = True 7547 else: 7548 HelasMultiProcessClass = helas_objects.HelasMultiProcess 7549 compute_loop_nc = False 7550 7551 self._curr_matrix_elements = HelasMultiProcessClass( 7552 self._curr_amps, compute_loop_nc=compute_loop_nc, 7553 matrix_element_opts=mode) 7554 7555 ndiags = sum([len(me.get('diagrams')) for \ 7556 me in self._curr_matrix_elements.\ 7557 get_matrix_elements()]) 7558 # assign a unique id number to all process 7559 uid = 0 7560 for me in self._curr_matrix_elements.get_matrix_elements()[:]: 7561 uid += 1 # update the identification number 7562 me.get('processes')[0].set('uid', uid) 7563 7564 cpu_time2 = time.time() 7565 7566 7567 return ndiags, cpu_time2 - cpu_time1
7568 7569 # Start of the actual routine 7570 7571 ndiags, cpu_time = generate_matrix_elements(self,group_processes) 7572 7573 calls = 0 7574 7575 path = self._export_dir 7576 7577 cpu_time1 = time.time() 7578 7579 # First treat madevent and pythia8 exports, where we need to 7580 # distinguish between grouped and ungrouped subprocesses 7581 7582 # MadEvent 7583 if self._export_format == 'madevent': 7584 path = pjoin(path, 'SubProcesses') 7585 calls += self._curr_exporter.export_processes(self._curr_matrix_elements, 7586 self._curr_helas_model) 7587 7588 # Write the procdef_mg5.dat file with process info 7589 card_path = pjoin(path, os.path.pardir, 'SubProcesses', \ 7590 'procdef_mg5.dat') 7591 if self._generate_info: 7592 self._curr_exporter.write_procdef_mg5(card_path, 7593 self._curr_model['name'], 7594 self._generate_info) 7595 try: 7596 cmd.Cmd.onecmd(self, 'history .') 7597 except Exception: 7598 misc.sprint('command history fails.', 10) 7599 pass 7600 7601 # Pythia 8 7602 elif self._export_format == 'pythia8': 7603 # Output the process files 7604 process_names = [] 7605 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList): 7606 for (group_number, me_group) in enumerate(self._curr_matrix_elements): 7607 exporter = self._curr_exporter.generate_process_directory(\ 7608 me_group.get('matrix_elements'), self._curr_helas_model, 7609 process_string = me_group.get('name'), 7610 process_number = group_number, 7611 version = version) 7612 process_names.append(exporter.process_name) 7613 else: 7614 exporter = self._curr_exporter.generate_process_directory(\ 7615 self._curr_matrix_elements, self._curr_helas_model, 7616 process_string = self._generate_info, version = version) 7617 process_names.append(exporter.process_file_name) 7618 7619 # Output the model parameter and ALOHA files 7620 model_name, model_path = exporter.convert_model_to_pythia8(\ 7621 self._curr_model, self._export_dir) 7622 7623 # Generate the main program file 7624 filename, make_filename = \ 7625 self._curr_exporter.generate_example_file_pythia8(path, 7626 model_path, 7627 process_names, 7628 exporter, 7629 main_file_name) 7630 7631 7632 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 7633 # Just the matrix.f files 7634 if self._export_format == 'matrix': 7635 for me in matrix_elements: 7636 filename = pjoin(path, 'matrix_' + \ 7637 me.get('processes')[0].shell_string() + ".f") 7638 if os.path.isfile(filename): 7639 logger.warning("Overwriting existing file %s" % filename) 7640 else: 7641 logger.info("Creating new file %s" % filename) 7642 calls = calls + self._curr_exporter.write_matrix_element_v4(\ 7643 writers.FortranWriter(filename),\ 7644 me, self._curr_helas_model) 7645 elif self._export_format in ['madevent', 'pythia8']: 7646 pass 7647 # grouping mode 7648 elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\ 7649 self._curr_exporter.grouped_mode: 7650 modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements) 7651 if modify: 7652 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 7653 7654 for me_number, me in enumerate(self._curr_matrix_elements): 7655 calls = calls + \ 7656 self._curr_exporter.generate_subprocess_directory(\ 7657 me, self._curr_helas_model, me_number) 7658 7659 # ungroup mode 7660 else: 7661 for nb,me in enumerate(matrix_elements[:]): 7662 new_calls = self._curr_exporter.generate_subprocess_directory(\ 7663 me, self._curr_helas_model, nb) 7664 if isinstance(new_calls, int): 7665 if new_calls ==0: 7666 matrix_elements.remove(me) 7667 else: 7668 calls = calls + new_calls 7669 7670 cpu_time2 = time.time() - cpu_time1 7671 7672 logger.info(("Generated helas calls for %d subprocesses " + \ 7673 "(%d diagrams) in %0.3f s") % \ 7674 (len(matrix_elements), 7675 ndiags, cpu_time)) 7676 7677 if calls: 7678 if "cpu_time2" in locals(): 7679 logger.info("Wrote files for %d helas calls in %0.3f s" % \ 7680 (calls, cpu_time2)) 7681 else: 7682 logger.info("Wrote files for %d helas calls" % \ 7683 (calls)) 7684 7685 if self._export_format == 'pythia8': 7686 logger.info("- All necessary files for Pythia 8 generated.") 7687 logger.info("- Run \"launch\" and select %s.cc," % filename) 7688 logger.info(" or go to %s/examples and run" % path) 7689 logger.info(" make -f %s" % make_filename) 7690 logger.info(" (with process_name replaced by process name).") 7691 logger.info(" You can then run ./%s to produce events for the process" % \ 7692 filename) 7693 7694 # Replace the amplitudes with the actual amplitudes from the 7695 # matrix elements, which allows proper diagram drawing also of 7696 # decay chain processes 7697 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 7698 self._curr_amps = diagram_generation.AmplitudeList(\ 7699 [me.get('base_amplitude') for me in \ 7700 matrix_elements]) 7701
7702 - def finalize(self, nojpeg, online = False, flaglist=[]):
7703 """Make the html output, write proc_card_mg5.dat and create 7704 madevent.tar.gz for a MadEvent directory""" 7705 7706 compiler_dict = {'fortran': self.options['fortran_compiler'], 7707 'cpp': self.options['cpp_compiler'], 7708 'f2py': self.options['f2py_compiler']} 7709 7710 # Handling of the model. 7711 if self._model_v4_path: 7712 logger.info('Copy %s model files to directory %s' % \ 7713 (os.path.basename(self._model_v4_path), self._export_dir)) 7714 self._curr_exporter.export_model_files(self._model_v4_path) 7715 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS')) 7716 else: 7717 # wanted_lorentz are the lorentz structures which are 7718 # actually used in the wavefunctions and amplitudes in 7719 # these processes 7720 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 7721 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 7722 # For a unique output of multiple type of exporter need to store this 7723 # information. 7724 if hasattr(self, 'previous_lorentz'): 7725 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz)) 7726 wanted_couplings = list(set(self.previous_couplings + wanted_couplings)) 7727 del self.previous_lorentz 7728 del self.previous_couplings 7729 if 'store_model' in flaglist: 7730 self.previous_lorentz = wanted_lorentz 7731 self.previous_couplings = wanted_couplings 7732 else: 7733 self._curr_exporter.convert_model(self._curr_model, 7734 wanted_lorentz, 7735 wanted_couplings) 7736 7737 # move the old options to the flaglist system. 7738 if nojpeg: 7739 flaglist.append('nojpeg') 7740 if online: 7741 flaglist.append('online') 7742 7743 7744 7745 if self._export_format in ['NLO']: 7746 ## write fj_lhapdf_opts file 7747 # Create configuration file [path to executable] for amcatnlo 7748 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt') 7749 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path', 7750 'hepmc_path'] 7751 to_keep = {} 7752 for opt in opts_to_keep: 7753 if self.options[opt]: 7754 to_keep[opt] = self.options[opt] 7755 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \ 7756 to_keep = to_keep) 7757 7758 elif self._export_format in ['madevent', 'madweight']: 7759 # Create configuration file [path to executable] for madevent 7760 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt') 7761 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, 7762 to_keep={'mg5_path':MG5DIR}) 7763 7764 # Dedicated finalize function. 7765 self._curr_exporter.finalize(self._curr_matrix_elements, 7766 self.history, 7767 self.options, 7768 flaglist) 7769 7770 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']: 7771 logger.info('Output to directory ' + self._export_dir + ' done.') 7772 7773 if self._export_format in ['madevent', 'NLO']: 7774 logger.info('Type \"launch\" to generate events from this process, or see') 7775 logger.info(self._export_dir + '/README') 7776 logger.info('Run \"open index.html\" to see more information about this process.')
7777
7778 - def do_help(self, line):
7779 """ propose some usefull possible action """ 7780 7781 super(MadGraphCmd,self).do_help(line) 7782 7783 if line: 7784 return 7785 7786 if len(self.history) == 0: 7787 last_action_2 = 'mg5_start' 7788 last_action = 'mg5_start' 7789 else: 7790 args = self.history[-1].split() 7791 last_action = args[0] 7792 if len(args)>1: 7793 last_action_2 = '%s %s' % (last_action, args[1]) 7794 else: 7795 last_action_2 = 'none'
7796 7797 7798 7799 # Calculate decay width
7800 - def do_compute_widths(self, line, model=None, do2body=True, decaymodel=None):
7801 """Documented commands:Generate amplitudes for decay width calculation, with fixed 7802 number of final particles (called level) 7803 syntax; compute_widths particle [other particles] [--options=] 7804 7805 - particle/other particles can also be multiparticle name (can also be 7806 pid of the particle) 7807 7808 --body_decay=X [default=4.0025] allow to choose the precision. 7809 if X is an integer: compute all X body decay 7810 if X is a float <1: compute up to the time that total error < X 7811 if X is a float >1: stops at the first condition. 7812 7813 --path=X. Use a given file for the param_card. (default UFO built-in) 7814 7815 special argument: 7816 - skip_2body: allow to not consider those decay (use FR) 7817 - model: use the model pass in argument. 7818 7819 """ 7820 7821 7822 7823 self.change_principal_cmd('MadGraph') 7824 if '--nlo' not in line: 7825 warning_text = """Please note that the automatic computation of the width is 7826 only valid in narrow-width approximation and at tree-level.""" 7827 logger.warning(warning_text) 7828 7829 if not model: 7830 modelname = self._curr_model.get('modelpath+restriction') 7831 with misc.MuteLogger(['madgraph'], ['INFO']): 7832 model = import_ufo.import_model(modelname, decay=True) 7833 self._curr_model = model 7834 7835 if not isinstance(model, model_reader.ModelReader): 7836 model = model_reader.ModelReader(model) 7837 7838 if '--nlo' in line: 7839 # call SMWidth to calculate NLO Width 7840 self.compute_widths_SMWidth(line, model=model) 7841 return 7842 7843 # check the argument and return those in a dictionary format 7844 particles, opts = self.check_compute_widths(self.split_arg(line)) 7845 7846 if opts['path']: 7847 correct = True 7848 param_card = check_param_card.ParamCard(opts['path']) 7849 for param in param_card['decay']: 7850 if param.value == "auto": 7851 param.value = 1 7852 param.format = 'float' 7853 correct = False 7854 if not correct: 7855 if opts['output']: 7856 param_card.write(opts['output']) 7857 opts['path'] = opts['output'] 7858 else: 7859 param_card.write(opts['path']) 7860 7861 data = model.set_parameters_and_couplings(opts['path']) 7862 7863 # find UFO particles linked to the require names. 7864 if do2body: 7865 skip_2body = True 7866 decay_info = {} 7867 for pid in particles: 7868 particle = model.get_particle(pid) 7869 if not hasattr(particle, 'partial_widths'): 7870 skip_2body = False 7871 break 7872 elif not decay_info: 7873 logger_mg.info('Get two body decay from FeynRules formula') 7874 decay_info[pid] = [] 7875 mass = abs(eval(str(particle.get('mass')), data).real) 7876 data = model.set_parameters_and_couplings(opts['path'], scale= mass) 7877 total = 0 7878 7879 for mode, expr in particle.partial_widths.items(): 7880 tmp_mass = mass 7881 for p in mode: 7882 try: 7883 value_mass = eval(str(p.mass), data) 7884 except Exception: 7885 # the p object can still be UFO reference. since the 7886 # mass name might hve change load back the MG5 one. 7887 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data) 7888 tmp_mass -= abs(value_mass) 7889 if tmp_mass <=0: 7890 continue 7891 7892 decay_to = [p.get('pdg_code') for p in mode] 7893 value = eval(expr,{'cmath':cmath},data).real 7894 if -1e-10 < value < 0: 7895 value = 0 7896 if -1e-5 < value < 0: 7897 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' % 7898 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 7899 value = 0 7900 elif value < 0: 7901 raise Exception, 'Partial width for %s > %s negative: %s' % \ 7902 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value) 7903 elif 0 < value < 0.1 and particle['color'] !=1: 7904 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 7905 % (particle.get('name'), value, decay_to)) 7906 value = 0 7907 7908 decay_info[particle.get('pdg_code')].append([decay_to, value]) 7909 total += value 7910 else: 7911 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 7912 opts['path'], opts['output']) 7913 if float(opts['body_decay']) == 2: 7914 return 7915 else: 7916 skip_2body = True 7917 7918 # 7919 # add info from decay module 7920 # 7921 self.do_decay_diagram('%s %s' % (' '.join([`id` for id in particles]), 7922 ' '.join('--%s=%s' % (key,value) 7923 for key,value in opts.items() 7924 if key not in ['precision_channel']) 7925 ), skip_2body=skip_2body, model=decaymodel) 7926 7927 if self._curr_amps: 7928 logger.info('Pass to numerical integration for computing the widths:') 7929 else: 7930 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output']) 7931 7932 7933 7934 return 7935 7936 # Do the MadEvent integration!! 7937 with misc.TMP_directory(dir=os.getcwd()) as path: 7938 decay_dir = pjoin(path,'temp_decay') 7939 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir)) 7940 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]): 7941 self.exec_cmd('output %s -f' % decay_dir,child=False) 7942 # Need to write the correct param_card in the correct place !!! 7943 if os.path.exists(opts['output']): 7944 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 7945 else: 7946 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 7947 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 7948 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat')) 7949 # call a ME interface and define as it as child for correct error handling 7950 me_cmd = madevent_interface.MadEventCmd(decay_dir) 7951 #self.define_child_cmd_interface(me_cmd, interface=False) 7952 me_cmd.model_name = self._curr_model['name'] #needed for mssm 7953 me_cmd.options['automatic_html_opening'] = False 7954 7955 me_opts=[('accuracy', opts['precision_channel']), # default 0.01 7956 ('points', 1000), 7957 ('iterations',9)] 7958 me_cmd.exec_cmd('survey decay -f %s' % ( 7959 " ".join(['--%s=%s' % val for val in me_opts])), 7960 postcmd=False) 7961 me_cmd.exec_cmd('combine_events', postcmd=False) 7962 #me_cmd.exec_cmd('store_events', postcmd=False) 7963 me_cmd.collect_decay_widths() 7964 me_cmd.do_quit('') 7965 # cleaning 7966 del me_cmd 7967 7968 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat')) 7969 7970 for pid in particles: 7971 width = param['decay'].get((pid,)).value 7972 particle = self._curr_model.get_particle(pid) 7973 #if particle['color'] !=1 and 0 < width.real < 0.1: 7974 # logger.warning("width of colored particle \"%s(%s)\" lower than QCD scale: %s. Set width to zero " 7975 # % (particle.get('name'), pid, width.real)) 7976 # width = 0 7977 7978 7979 if not pid in param['decay'].decay_table: 7980 continue 7981 if pid not in decay_info: 7982 decay_info[pid] = [] 7983 for BR in param['decay'].decay_table[pid]: 7984 if len(BR.lhacode) == 3 and skip_2body: 7985 continue 7986 if 0 < BR.value * width <0.1 and particle['color'] !=1: 7987 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 7988 % (particle.get('name'), BR.value * width, BR.lhacode[1:])) 7989 7990 continue 7991 7992 decay_info[pid].append([BR.lhacode[1:], BR.value * width]) 7993 7994 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 7995 opts['path'], opts['output']) 7996 7997 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 7998 check_param_card.convert_to_slha1(opts['output']) 7999 return
8000 8001 8002 8003 # Calculate decay width with SMWidth
8004 - def compute_widths_SMWidth(self, line, model=None):
8005 """Compute widths with SMWidth. 8006 """ 8007 8008 # check the argument and return those in a dictionary format 8009 particles, opts = self.check_compute_widths(self.split_arg(line)) 8010 8011 if opts['path']: 8012 correct = True 8013 param_card = check_param_card.ParamCard(opts['path']) 8014 for param in param_card['decay']: 8015 if param.value == "auto": 8016 param.value = 1 8017 param.format = 'float' 8018 correct = False 8019 if not correct: 8020 if opts['output']: 8021 param_card.write(opts['output']) 8022 opts['path'] = opts['output'] 8023 else: 8024 param_card.write(opts['path']) 8025 8026 if not model: 8027 model_path = self._curr_model.get('modelpath') 8028 model_name = self._curr_model.get('name') 8029 currmodel = self._curr_model 8030 else: 8031 model_path = model.get('modelpath') 8032 model_name = model.get('name') 8033 currmodel = model 8034 8035 if not os.path.exists(pjoin(model_path, 'SMWidth')): 8036 raise self.InvalidCmd, "Model %s is not valid for computing NLO width with SMWidth"%model_name 8037 8038 # determine the EW scheme 8039 externparam = [(param.lhablock.lower(),param.name.lower()) for param \ 8040 in currmodel.get('parameters')[('external',)]] 8041 8042 if ('sminputs','aewm1') in externparam: 8043 # alpha(MZ) scheme 8044 arg2 = "1" 8045 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam: 8046 # Gmu scheme 8047 arg2 = "2" 8048 else: 8049 raise Exception, "Do not know the EW scheme in the model %s"%model_name 8050 8051 #compile the code 8052 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')): 8053 logger.info('Compiling SMWidth. This has to be done only once and'+\ 8054 ' can take a couple of minutes.','$MG:color:BLACK') 8055 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth', 8056 'makefile_MW5')) 8057 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \ 8058 self.options_configuration['fortran_compiler'] 8059 if current != new: 8060 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current) 8061 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current) 8062 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current) 8063 misc.compile(cwd=pjoin(model_path, 'SMWidth')) 8064 8065 # look for the ident_card.dat 8066 identpath=" " 8067 carddir=os.path.dirname(opts['path']) 8068 if 'ident_card.dat' in os.listdir(carddir): 8069 identpath=pjoin(carddir,'ident_card.dat') 8070 #run the code 8071 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2], 8072 stdout=subprocess.PIPE, 8073 stdin=subprocess.PIPE, 8074 cwd=pjoin(model_path, 'SMWidth')).communicate() 8075 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I) 8076 width_list = pattern.findall(output) 8077 width_dict = {} 8078 for pid,width in width_list: 8079 width_dict[int(pid)] = float(width) 8080 8081 for pid in particles: 8082 if not pid in width_dict: 8083 width = 0 8084 else: 8085 width = width_dict[pid] 8086 param = param_card['decay'].get((pid,)) 8087 param.value = width 8088 param.format = 'float' 8089 if pid not in param_card['decay'].decay_table: 8090 continue 8091 del param_card['decay'].decay_table[pid] # reset the BR 8092 # write the output file. (the new param_card) 8093 if opts['output']: 8094 param_card.write(opts['output']) 8095 logger.info('Results are written in %s' % opts['output']) 8096 else: 8097 param_card.write(opts['path']) 8098 logger.info('Results are written in %s' % opts['path']) 8099 return
8100 8101 # Calculate decay width
8102 - def do_decay_diagram(self, line, skip_2body=False, model=None):
8103 """Not in help: Generate amplitudes for decay width calculation, with fixed 8104 number of final particles (called level) 8105 syntax; decay_diagram part_name level param_path 8106 args; part_name level param_path 8107 part_name = name of the particle you want to calculate width 8108 level = a.) when level is int, 8109 it means the max number of decay products 8110 b.) when level is float, 8111 it means the required precision for width. 8112 param_path = path for param_card 8113 (this is necessary to determine whether a channel is onshell or not) 8114 e.g. calculate width for higgs up to 2-body decays. 8115 calculate_width h 2 [path] 8116 N.B. param_card must be given so that the program knows which channel 8117 is on shell and which is not. 8118 8119 special argument: 8120 - skip_2body: allow to not consider those decay (use FR) 8121 - model: use the model pass in argument. 8122 """ 8123 8124 if model: 8125 self._curr_decaymodel = model 8126 8127 8128 args = self.split_arg(line) 8129 #check the validity of the arguments 8130 particles, args = self.check_decay_diagram(args) 8131 #print args 8132 pids = particles 8133 level = float(args['body_decay']) 8134 param_card_path = args['path'] 8135 min_br = float(args['min_br']) 8136 8137 # Reset amplitudes 8138 self._curr_amps = diagram_generation.AmplitudeList() 8139 self._curr_proc_defs = base_objects.ProcessDefinitionList() 8140 # Reset Helas matrix elements 8141 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 8142 # Reset _done_export, since we have new process 8143 self._done_export = False 8144 # Also reset _export_format and _export_dir 8145 self._export_format = None 8146 8147 8148 # Setup before find_channels 8149 if not model: 8150 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model, 8151 True) 8152 self._curr_decaymodel.read_param_card(param_card_path) 8153 else: 8154 self._curr_decaymodel = model 8155 model = self._curr_decaymodel 8156 8157 if isinstance(pids, int): 8158 pids = [pids] 8159 8160 first =True 8161 for part_nb,pid in enumerate(pids): 8162 part = self._curr_decaymodel.get_particle(pid) 8163 if part.get('width').lower() == 'zero': 8164 continue 8165 logger_mg.info('get decay diagram for %s' % part['name']) 8166 # Find channels as requested 8167 if level // 1 == level and level >1: 8168 level = int(level) 8169 self._curr_decaymodel.find_channels(part, level, min_br) 8170 if not skip_2body: 8171 amp = part.get_amplitudes(2) 8172 if amp: 8173 self._curr_amps.extend(amp) 8174 8175 for l in range(3, level+1): 8176 amp = part.get_amplitudes(l) 8177 if amp: 8178 self._curr_amps.extend(amp) 8179 else: 8180 max_level = level // 1 8181 if max_level < 2: 8182 max_level = 999 8183 precision = level % 1 8184 if first: 8185 model.find_all_channels(2,generate_abstract=False) 8186 first = False 8187 if not skip_2body: 8188 amp = part.get_amplitudes(2) 8189 if amp: 8190 self._curr_amps.extend(amp) 8191 clevel = 2 8192 while part.get('apx_decaywidth_err').real > precision: 8193 clevel += 1 8194 if clevel > max_level: 8195 logger_mg.info(' stop to %s body-decay. approximate error: %s' % 8196 (max_level, part.get('apx_decaywidth_err')) ) 8197 break 8198 if clevel > 3: 8199 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\ 8200 (part.get('apx_decaywidth_err'), clevel)) 8201 part.find_channels_nextlevel(model, min_br) 8202 #part.group_channels_2_amplitudes(clevel, model, min_br) 8203 amp = part.get_amplitudes(clevel) 8204 if amp: 8205 self._curr_amps.extend(amp) 8206 part.update_decay_attributes(False, True, True, model) 8207 8208 8209 # Set _generate_info 8210 if len(self._curr_amps) > 0: 8211 process = self._curr_amps[0]['process'].nice_string() 8212 #print process 8213 self._generate_info = process[9:] 8214 #print self._generate_info 8215 else: 8216 logger.info("No decay is found")
8217
8218 -class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd):
8219 """Temporary parser"""
8220 8221 #=============================================================================== 8222 # Command Parser 8223 #=============================================================================== 8224 # DRAW 8225 _draw_usage = "draw FILEPATH [options]\n" + \ 8226 "-- draw the diagrams in eps format\n" + \ 8227 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \ 8228 " Example: draw plot_dir . \n" 8229 _draw_parser = misc.OptionParser(usage=_draw_usage) 8230 _draw_parser.add_option("", "--horizontal", default=False, 8231 action='store_true', help="force S-channel to be horizontal") 8232 _draw_parser.add_option("", "--external", default=0, type='float', 8233 help="authorizes external particles to end at top or " + \ 8234 "bottom of diagram. If bigger than zero this tune the " + \ 8235 "length of those line.") 8236 _draw_parser.add_option("", "--max_size", default=1.5, type='float', 8237 help="this forbids external line bigger than max_size") 8238 _draw_parser.add_option("", "--non_propagating", default=True, \ 8239 dest="contract_non_propagating", action='store_false', 8240 help="avoid contractions of non propagating lines") 8241 _draw_parser.add_option("", "--add_gap", default=0, type='float', \ 8242 help="set the x-distance between external particles") 8243 8244 # LAUNCH PROGRAM 8245 _launch_usage = "launch [DIRPATH] [options]\n" + \ 8246 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \ 8247 " By default DIRPATH is the latest created directory \n" + \ 8248 " (for pythia8, it should be the Pythia 8 main directory) \n" + \ 8249 " Example: launch PROC_sm_1 --name=run2 \n" + \ 8250 " Example: launch ../pythia8 \n" 8251 _launch_parser = misc.OptionParser(usage=_launch_usage) 8252 _launch_parser.add_option("-f", "--force", default=False, action='store_true', 8253 help="Use the card present in the directory in order to launch the different program") 8254 _launch_parser.add_option("-n", "--name", default='', type='str', 8255 help="Provide a name to the run (for madevent run)") 8256 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true', 8257 help="submit the job on the cluster") 8258 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true', 8259 help="submit the job on multicore core") 8260 8261 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true', 8262 help="Use Interactive Console [if available]") 8263 _launch_parser.add_option("-s", "--laststep", default='', 8264 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]") 8265 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true', 8266 help="Run the reweight module (reweighting by different model parameter") 8267 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', 8268 help="Run the madspin package")
8269 8270 #=============================================================================== 8271 # Interface for customize question. 8272 #=============================================================================== 8273 -class AskforCustomize(cmd.SmartQuestion):
8274 """A class for asking a question where in addition you can have the 8275 set command define and modifying the param_card/run_card correctly""" 8276
8277 - def __init__(self, question, allow_arg=[], default=None, 8278 mother_interface=None, *arg, **opt):
8279 8280 model_path = mother_interface._curr_model.get('modelpath') 8281 #2) Import the option available in the model 8282 ufo_model = ufomodels.load_model(model_path) 8283 self.all_categories = ufo_model.build_restrict.all_categories 8284 8285 question = self.get_question() 8286 # determine the possible value and how they are linked to the restriction 8287 #options. 8288 allow_arg = ['0'] 8289 self.name2options = {} 8290 for category in self.all_categories: 8291 for options in category: 8292 if not options.first: 8293 continue 8294 self.name2options[str(len(allow_arg))] = options 8295 self.name2options[options.name.replace(' ','')] = options 8296 allow_arg.append(len(allow_arg)) 8297 allow_arg.append('done') 8298 8299 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8300 8301 8302
8303 - def default(self, line):
8304 """Default action if line is not recognized""" 8305 8306 line = line.strip() 8307 args = line.split() 8308 if line == '' and self.default_value is not None: 8309 self.value = self.default_value 8310 # check if input is a file 8311 elif hasattr(self, 'do_%s' % args[0]): 8312 self.do_set(' '.join(args[1:])) 8313 elif line.strip() != '0' and line.strip() != 'done' and \ 8314 str(line) != 'EOF' and line.strip() in self.allow_arg: 8315 option = self.name2options[line.strip()] 8316 option.status = not option.status 8317 self.value = 'repeat' 8318 else: 8319 self.value = line 8320 8321 return self.all_categories
8322
8323 - def reask(self, reprint_opt=True):
8324 """ """ 8325 reprint_opt = True 8326 self.question = self.get_question() 8327 cmd.SmartQuestion.reask(self, reprint_opt)
8328
8329 - def do_set(self, line):
8330 """ """ 8331 self.value = 'repeat' 8332 8333 args = line.split() 8334 if args[0] not in self.name2options: 8335 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' % 8336 (args[0], ', '.join(self.name2options.keys()) )) 8337 return 8338 elif len(args) != 2: 8339 logger.warning('Invalid set command. Not correct number of argument') 8340 return 8341 8342 8343 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']: 8344 self.name2options[args[0]].status = True 8345 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']: 8346 self.name2options[args[0]].status = False 8347 else: 8348 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8349 8350 8351
8352 - def get_question(self):
8353 """define the current question.""" 8354 question = '' 8355 i=0 8356 for category in self.all_categories: 8357 question += category.name + ':\n' 8358 for options in category: 8359 if not options.first: 8360 continue 8361 i+=1 8362 question += ' %s: %s [%s]\n' % (i, options.name, 8363 options.display(options.status)) 8364 question += 'Enter a number to change it\'s status or press enter to validate.\n' 8365 question += 'For scripting this function, please type: \'help\'' 8366 return question
8367 8368
8369 - def complete_set(self, text, line, begidx, endidx):
8370 """ Complete the set command""" 8371 signal.alarm(0) # avoid timer if any 8372 args = self.split_arg(line[0:begidx]) 8373 8374 if len(args) == 1: 8375 possibilities = [x for x in self.name2options if not x.isdigit()] 8376 return self.list_completion(text, possibilities, line) 8377 else: 8378 return self.list_completion(text,['True', 'False'], line)
8379 8380
8381 - def do_help(self, line):
8382 '''help message''' 8383 8384 print 'This allows you to optimize your model to your needs.' 8385 print 'Enter the number associate to the possible restriction/add-on' 8386 print ' to change the status of this restriction/add-on.' 8387 print '' 8388 print 'In order to allow scripting of this function you can use the ' 8389 print 'function \'set\'. This function takes two argument:' 8390 print 'set NAME VALUE' 8391 print ' NAME is the description of the option where you remove all spaces' 8392 print ' VALUE is either True or False' 8393 print ' Example: For the question' 8394 print ''' sm customization: 8395 1: diagonal ckm [True] 8396 2: c mass = 0 [True] 8397 3: b mass = 0 [False] 8398 4: tau mass = 0 [False] 8399 5: muon mass = 0 [True] 8400 6: electron mass = 0 [True] 8401 Enter a number to change it's status or press enter to validate.''' 8402 print ''' you can answer by''' 8403 print ' set diagonalckm False' 8404 print ' set taumass=0 True'
8405
8406 - def cmdloop(self, intro=None):
8407 cmd.SmartQuestion.cmdloop(self, intro) 8408 return self.all_categories
8409 8410 8411 8412 #=============================================================================== 8413 # __main__ 8414 #=============================================================================== 8415 8416 if __name__ == '__main__': 8417 8418 run_option = sys.argv 8419 if len(run_option) > 1: 8420 # The first argument of sys.argv is the name of the program 8421 input_file = open(run_option[1], 'rU') 8422 cmd_line = MadGraphCmd(stdin=input_file) 8423 cmd_line.use_rawinput = False #put it in non interactive mode 8424 cmd_line.cmdloop() 8425 else: 8426 # Interactive mode 8427 MadGraphCmd().cmdloop() 8428