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