Package madgraph :: Package interface :: Module madgraph_interface
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.madgraph_interface

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