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