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