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

Source Code for Module madgraph.interface.madgraph_interface

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