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