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