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