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