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