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

Source Code for Module madgraph.interface.madgraph_interface

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