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