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