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

Source Code for Module madgraph.interface.madgraph_interface

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