Package madgraph :: Package interface :: Module madgraph_interface
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.madgraph_interface

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