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