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