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