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