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+'^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 2455 # select the possibility according to the current line 2456 all_name = [name+' ' for name in all_name if name.startswith(text) 2457 and name.strip() != text] 2458 2459 2460 if all_name: 2461 completion_categories['Restricted model'] = all_name 2462 2463 # Path continuation 2464 if os.path.sep in args[-1]: 2465 if mode.startswith('model') or mode == 'all': 2466 # Directory continuation 2467 try: 2468 cur_path = pjoin(*[a for a in args \ 2469 if a.endswith(os.path.sep)]) 2470 except Exception: 2471 pass 2472 else: 2473 all_dir = self.path_completion(text, cur_path, only_dirs = True) 2474 if mode in ['model_v4','all']: 2475 completion_categories['Path Completion'] = all_dir 2476 # Only UFO model here 2477 new = [] 2478 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path)) 2479 for name in all_dir] 2480 if data: 2481 completion_categories['Path Completion'] = all_dir + new 2482 else: 2483 try: 2484 cur_path = pjoin(*[a for a in args \ 2485 if a.endswith(os.path.sep)]) 2486 except Exception: 2487 pass 2488 else: 2489 all_path = self.path_completion(text, cur_path) 2490 if mode == 'all': 2491 new = [] 2492 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path)) 2493 for name in all_path] 2494 if data: 2495 completion_categories['Path Completion'] = data[0] 2496 else: 2497 completion_categories['Path Completion'] = all_path 2498 2499 # Model directory name if directory is not given 2500 if (len(args) == 2): 2501 is_model = True 2502 if mode == 'model': 2503 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) 2504 mod_name = lambda name: name 2505 elif mode == 'model_v4': 2506 file_cond = lambda p : (os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) 2507 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat'))) 2508 mod_name = lambda name :(name[-3:] != '_v4' and name or name[:-3]) 2509 elif mode == 'all': 2510 mod_name = lambda name: name 2511 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) \ 2512 or os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) \ 2513 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat')) 2514 else: 2515 cur_path = pjoin(*[a for a in args \ 2516 if a.endswith(os.path.sep)]) 2517 all_path = self.path_completion(text, cur_path) 2518 completion_categories['model name'] = all_path 2519 is_model = False 2520 2521 if is_model: 2522 model_list = [mod_name(name) for name in \ 2523 self.path_completion(text, 2524 pjoin(MG5DIR,'models'), 2525 only_dirs = True) \ 2526 if file_cond(name)] 2527 2528 if mode == 'model_v4': 2529 completion_categories['model name'] = model_list 2530 elif allow_restrict: 2531 # need to update the list with the possible restriction 2532 all_name = [] 2533 for model_name in model_list: 2534 all_name += self.find_restrict_card(model_name, 2535 base_dir=pjoin(MG5DIR,'models')) 2536 else: 2537 all_name = model_list 2538 2539 if mode == 'all': 2540 cur_path = pjoin(*[a for a in args \ 2541 if a.endswith(os.path.sep)]) 2542 all_path = self.path_completion(text, cur_path) 2543 completion_categories['model name'] = all_path + all_name 2544 elif mode == 'model': 2545 completion_categories['model name'] = all_name 2546 2547 # Options 2548 if mode == 'all' and len(args)>1: 2549 mode = self.find_import_type(args[2]) 2550 2551 if len(args) >= 3 and mode.startswith('model') and not '-modelname' in line: 2552 if not text and not completion_categories: 2553 return ['--modelname'] 2554 elif not (os.path.sep in args[-1] and line[-1] != ' '): 2555 completion_categories['options'] = self.list_completion(text, ['--modelname','-modelname','--noprefix']) 2556 if len(args) >= 3 and mode.startswith('banner') and not '--no_launch' in line: 2557 completion_categories['options'] = self.list_completion(text, ['--no_launch']) 2558 2559 if treat_completion: 2560 return self.deal_multiple_categories(completion_categories) 2561 else: 2562 #this means this function is called as a subgroup of another completion 2563 return completion_categories
2564 2565
2566 - def find_restrict_card(self, model_name, base_dir='./', no_restrict=True):
2567 """find the restriction file associate to a given model""" 2568 2569 # check if the model_name should be keeped as a possibility 2570 if no_restrict: 2571 output = [model_name] 2572 else: 2573 output = [] 2574 2575 # check that the model is a valid model 2576 if not os.path.exists(pjoin(base_dir, model_name, 'couplings.py')): 2577 # not valid UFO model 2578 return output 2579 2580 if model_name.endswith(os.path.sep): 2581 model_name = model_name[:-1] 2582 2583 # look for _default and treat this case 2584 if os.path.exists(pjoin(base_dir, model_name, 'restrict_default.dat')): 2585 output.append('%s-full' % model_name) 2586 2587 # look for other restrict_file 2588 for name in os.listdir(pjoin(base_dir, model_name)): 2589 if name.startswith('restrict_') and not name.endswith('default.dat') \ 2590 and name.endswith('.dat'): 2591 tag = name[9:-4] #remove restrict and .dat 2592 while model_name.endswith(os.path.sep): 2593 model_name = model_name[:-1] 2594 output.append('%s-%s' % (model_name, tag)) 2595 2596 # return 2597 return output
2598
2599 - def complete_install(self, text, line, begidx, endidx):
2600 "Complete the import command" 2601 2602 args = self.split_arg(line[0:begidx]) 2603 2604 # Format 2605 if len(args) == 1: 2606 return self.list_completion(text, self._install_opts) 2607 elif len(args) and args[0] == 'update': 2608 return self.list_completion(text, ['-f','--timeout='])
2609
2610 #=============================================================================== 2611 # MadGraphCmd 2612 #=============================================================================== 2613 -class MadGraphCmd(HelpToCmd, CheckValidForCmd, CompleteForCmd, CmdExtended):
2614 """The command line processor of MadGraph""" 2615 2616 writing_dir = '.' 2617 2618 # Options and formats available 2619 _display_opts = ['particles', 'interactions', 'processes', 'diagrams', 2620 'diagrams_text', 'multiparticles', 'couplings', 'lorentz', 2621 'checks', 'parameters', 'options', 'coupling_order','variable'] 2622 _add_opts = ['process', 'model'] 2623 _save_opts = ['model', 'processes', 'options'] 2624 _tutorial_opts = ['aMCatNLO', 'stop', 'MadLoop', 'MadGraph5'] 2625 _switch_opts = ['mg5','aMC@NLO','ML5'] 2626 _check_opts = ['full', 'timing', 'stability', 'profile', 'permutation', 2627 'gauge','lorentz', 'brs', 'cms'] 2628 _import_formats = ['model_v4', 'model', 'proc_v4', 'command', 'banner'] 2629 _install_opts = ['pythia-pgs', 'Delphes', 'MadAnalysis', 'ExRootAnalysis', 2630 'update', 'Delphes2', 'SysCalc', 'Golem95', 'PJFry', 2631 'QCDLoop'] 2632 # The targets below are installed using the HEPToolsInstaller.py script 2633 _advanced_install_opts = ['ninja'] 2634 2635 # The options below are commented for now but already available 2636 # _advanced_install_opts += ['pythia8','zlib','boost','lhapdf6','lhapdf5','hepmc','mg5amc_py8_interface','oneloop'] 2637 2638 _install_opts.extend(_advanced_install_opts) 2639 2640 _v4_export_formats = ['madevent', 'standalone', 'standalone_msP','standalone_msF', 2641 'matrix', 'standalone_rw', 'madweight'] 2642 _export_formats = _v4_export_formats + ['standalone_cpp', 'pythia8', 'aloha', 2643 'matchbox_cpp', 'matchbox'] 2644 _set_options = ['group_subprocesses', 2645 'ignore_six_quark_processes', 2646 'stdout_level', 2647 'fortran_compiler', 2648 'cpp_compiler', 2649 'loop_optimized_output', 2650 'complex_mass_scheme', 2651 'gauge', 2652 'EWscheme', 2653 'max_npoint_for_channel'] 2654 _valid_nlo_modes = ['all','real','virt','sqrvirt','tree','noborn','LOonly'] 2655 _valid_sqso_types = ['==','<=','=','>'] 2656 _valid_amp_so_types = ['=','<=', '==', '>'] 2657 _OLP_supported = ['MadLoop', 'GoSam'] 2658 _output_dependencies_supported = ['external', 'internal','environment_paths'] 2659 2660 # The three options categories are treated on a different footage when a 2661 # set/save configuration occur. current value are kept in self.options 2662 options_configuration = {'pythia8_path': './pythia8', 2663 'hwpp_path': './herwigPP', 2664 'thepeg_path': './thepeg', 2665 'hepmc_path': './hepmc', 2666 'madanalysis_path': './MadAnalysis', 2667 'pythia-pgs_path':'./pythia-pgs', 2668 'td_path':'./td', 2669 'delphes_path':'./Delphes', 2670 'exrootanalysis_path':'./ExRootAnalysis', 2671 'syscalc_path': './SysCalc', 2672 'timeout': 60, 2673 'web_browser':None, 2674 'eps_viewer':None, 2675 'text_editor':None, 2676 'fortran_compiler':None, 2677 'f2py_compiler':None, 2678 'cpp_compiler':None, 2679 'auto_update':7, 2680 'cluster_type': 'condor', 2681 'cluster_queue': None, 2682 'cluster_status_update': (600, 30), 2683 'fastjet':'fastjet-config', 2684 'pjfry':'auto', 2685 'golem':'auto', 2686 'samurai':None, 2687 'ninja':'./HEPTools/lib', 2688 'lhapdf':'lhapdf-config', 2689 'applgrid':'applgrid-config', 2690 'amcfast':'amcfast-config', 2691 'cluster_temp_path':None, 2692 'cluster_local_path': None, 2693 # 'mg5amc_py8_interface_path': './HEPTools/MG5aMC_PY8_interface', 2694 'OLP': 'MadLoop', 2695 'cluster_nb_retry':1, 2696 'cluster_retry_wait':300, 2697 'cluster_size':100, 2698 'output_dependencies':'external' 2699 } 2700 2701 options_madgraph= {'group_subprocesses': 'Auto', 2702 'ignore_six_quark_processes': False, 2703 'low_mem_multicore_nlo_generation': False, 2704 'complex_mass_scheme': False, 2705 'gauge':'unitary', 2706 'stdout_level':None, 2707 'loop_optimized_output':True, 2708 'loop_color_flows':False, 2709 'max_npoint_for_channel': 0 # 0 means automaticly adapted 2710 } 2711 2712 options_madevent = {'automatic_html_opening':True, 2713 'run_mode':2, 2714 'nb_core': None, 2715 'notification_center': True 2716 } 2717 2718 2719 # Variables to store object information 2720 _curr_model = None #base_objects.Model() 2721 _curr_amps = diagram_generation.AmplitudeList() 2722 _curr_matrix_elements = helas_objects.HelasMultiProcess() 2723 _curr_fortran_model = None 2724 _curr_cpp_model = None 2725 _curr_exporter = None 2726 _done_export = False 2727 _curr_decaymodel = None 2728 2729 helporder = ['Main commands', 'Documented commands'] 2730 2731
2732 - def preloop(self):
2733 """Initializing before starting the main loop""" 2734 2735 self.prompt = 'MG5_aMC>' 2736 if madgraph.ReadWrite: # prevent on read-only disk 2737 self.do_install('update --mode=mg5_start') 2738 2739 # By default, load the UFO Standard Model 2740 logger.info("Loading default model: sm") 2741 self.exec_cmd('import model sm', printcmd=False, precmd=True) 2742 2743 # preloop mother 2744 CmdExtended.preloop(self)
2745 2746
2747 - def __init__(self, mgme_dir = '', *completekey, **stdin):
2748 """ add a tracker of the history """ 2749 2750 CmdExtended.__init__(self, *completekey, **stdin) 2751 2752 # Set MG/ME directory path 2753 if mgme_dir: 2754 if os.path.isdir(pjoin(mgme_dir, 'Template')): 2755 self._mgme_dir = mgme_dir 2756 logger.info('Setting MG/ME directory to %s' % mgme_dir) 2757 else: 2758 logger.warning('Warning: Directory %s not valid MG/ME directory' % \ 2759 mgme_dir) 2760 self._mgme_dir = MG4DIR 2761 2762 # Variables to store state information 2763 self._multiparticles = {} 2764 self.options = {} 2765 self._generate_info = "" # store the first generated process 2766 self._model_v4_path = None 2767 self._export_dir = None 2768 self._export_format = 'madevent' 2769 self._mgme_dir = MG4DIR 2770 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools')) 2771 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src')) 2772 self._comparisons = None 2773 self._cms_checks = [] 2774 self._nlo_modes_for_completion = ['all','virt','real','LOonly'] 2775 2776 # Load the configuration file,i.e.mg5_configuration.txt 2777 self.set_configuration()
2778
2779 - def setup(self):
2780 """ Actions to carry when switching to this interface """ 2781 2782 # Refresh all the interface stored value as things like generated 2783 # processes and amplitudes are not to be reused in between different 2784 # interfaces 2785 # Clear history, amplitudes and matrix elements when a model is imported 2786 # Remove previous imports, generations and outputs from history 2787 self.history.clean(remove_bef_last='import',keep_switch=True) 2788 # Reset amplitudes and matrix elements 2789 self._done_export=False 2790 self._curr_amps = diagram_generation.AmplitudeList() 2791 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 2792 2793 self._v4_export_formats = ['madevent', 'standalone','standalone_msP','standalone_msF', 2794 'matrix', 'standalone_rw'] 2795 self._export_formats = self._v4_export_formats + ['standalone_cpp', 'pythia8'] 2796 self._nlo_modes_for_completion = ['all','virt','real']
2797
2798 - def do_quit(self, line):
2799 """Not in help: Do quit""" 2800 2801 if self._done_export and \ 2802 os.path.exists(pjoin(self._done_export[0],'RunWeb')): 2803 os.remove(pjoin(self._done_export[0],'RunWeb')) 2804 2805 value = super(MadGraphCmd, self).do_quit(line) 2806 if madgraph.ReadWrite: #prevent to run on Read Only disk 2807 self.do_install('update --mode=mg5_end') 2808 print 2809 2810 return value
2811 2812 # Add a process to the existing multiprocess definition 2813 # Generate a new amplitude
2814 - def do_add(self, line):
2815 """Generate an amplitude for a given process and add to 2816 existing amplitudes 2817 or merge two model 2818 """ 2819 2820 args = self.split_arg(line) 2821 2822 2823 warning_duplicate = True 2824 if '--no_warning=duplicate' in args: 2825 warning_duplicate = False 2826 args.remove('--no_warning=duplicate') 2827 2828 # Check the validity of the arguments 2829 self.check_add(args) 2830 2831 if args[0] == 'model': 2832 return self.add_model(args[1:]) 2833 2834 # special option for 1->N to avoid generation of kinematically forbidden 2835 #decay. 2836 if args[-1].startswith('--optimize'): 2837 optimize = True 2838 args.pop() 2839 else: 2840 optimize = False 2841 2842 if args[0] == 'process': 2843 # Rejoin line 2844 line = ' '.join(args[1:]) 2845 2846 # store the first process (for the perl script) 2847 if not self._generate_info: 2848 self._generate_info = line 2849 2850 # Reset Helas matrix elements 2851 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 2852 2853 # Extract process from process definition 2854 if ',' in line: 2855 if ']' in line or '[' in line: 2856 error_msg=\ 2857 """The '[' and ']' syntax cannot be used in cunjunction with decay chains. 2858 This implies that with decay chains: 2859 > Squared coupling order limitations are not available. 2860 > Loop corrections cannot be considered.""" 2861 raise MadGraph5Error(error_msg) 2862 else: 2863 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 2864 myprocdef, line = self.extract_decay_chain_process(line, proc_number=nb_proc) 2865 # Redundant with above, but not completely as in the future 2866 # one might think of allowing the core process to be 2867 # corrected by loops. 2868 if myprocdef.are_decays_perturbed(): 2869 raise MadGraph5Error("Decay processes cannot be perturbed.") 2870 # The two limitations below have some redundancy, but once 2871 # again, they might be relieved (one at a time or together) 2872 # int he future. 2873 if myprocdef.decays_have_squared_orders() or \ 2874 myprocdef['squared_orders']!={}: 2875 raise MadGraph5Error("Decay processes cannot specify "+\ 2876 "squared orders constraints.") 2877 if myprocdef.are_negative_orders_present(): 2878 raise MadGraph5Error("Decay processes cannot include negative"+\ 2879 " coupling orders constraints.") 2880 else: 2881 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 2882 myprocdef = self.extract_process(line, proc_number=nb_proc) 2883 2884 2885 2886 # Check that we have something 2887 if not myprocdef: 2888 raise self.InvalidCmd("Empty or wrong format process, please try again.") 2889 # Check that we have the same number of initial states as 2890 # existing processes 2891 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 2892 myprocdef.get_ninitial(): 2893 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 2894 2895 # Negative coupling order contraints can be given on at most one 2896 # coupling order (and either in squared orders or orders, not both) 2897 if len([1 for val in myprocdef.get('orders').values()+\ 2898 myprocdef.get('squared_orders').values() if val<0])>1: 2899 raise MadGraph5Error("Negative coupling order constraints"+\ 2900 " can only be given on one type of coupling and either on"+\ 2901 " squared orders or amplitude orders, not both.") 2902 2903 cpu_time1 = time.time() 2904 2905 # Generate processes 2906 if self.options['group_subprocesses'] == 'Auto': 2907 collect_mirror_procs = True 2908 else: 2909 collect_mirror_procs = self.options['group_subprocesses'] 2910 ignore_six_quark_processes = \ 2911 self.options['ignore_six_quark_processes'] if \ 2912 "ignore_six_quark_processes" in self.options \ 2913 else [] 2914 2915 myproc = diagram_generation.MultiProcess(myprocdef, 2916 collect_mirror_procs = collect_mirror_procs, 2917 ignore_six_quark_processes = ignore_six_quark_processes, 2918 optimize=optimize) 2919 2920 2921 for amp in myproc.get('amplitudes'): 2922 if amp not in self._curr_amps: 2923 self._curr_amps.append(amp) 2924 elif warning_duplicate: 2925 raise self.InvalidCmd, "Duplicate process %s found. Please check your processes." % \ 2926 amp.nice_string_processes() 2927 2928 # Reset _done_export, since we have new process 2929 self._done_export = False 2930 2931 cpu_time2 = time.time() 2932 2933 nprocs = len(myproc.get('amplitudes')) 2934 ndiags = sum([amp.get_number_of_diagrams() for \ 2935 amp in myproc.get('amplitudes')]) 2936 2937 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 2938 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 2939 ndiags = sum([amp.get_number_of_diagrams() for \ 2940 amp in self._curr_amps]) 2941 logger.info("Total: %i processes with %i diagrams" % \ 2942 (len(self._curr_amps), ndiags))
2943
2944 - def add_model(self, args):
2945 """merge two model""" 2946 2947 model_path = args[0] 2948 recreate = ('--recreate' in args) 2949 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')] 2950 if output_dir: 2951 output_dir = output_dir[0] 2952 recreate = True 2953 restrict_name = '' 2954 else: 2955 name = os.path.basename(self._curr_model.get('modelpath')) 2956 restrict_name = self._curr_model.get('restrict_name') 2957 output_dir = pjoin(MG5DIR, 'models', '%s__%s' % (name, 2958 os.path.basename(model_path))) 2959 2960 if os.path.exists(output_dir): 2961 if recreate: 2962 shutil.rmtree(output_dir) 2963 else: 2964 logger.info('Model already created! Loading it from %s' % output_dir) 2965 oldmodel = self._curr_model.get('modelpath') 2966 new_model_name = output_dir 2967 if restrict_name: 2968 new_model_name = '%s-%s' % (output_dir, restrict_name) 2969 try: 2970 self.exec_cmd('import model %s' % new_model_name, errorhandling=False, 2971 printcmd=False, precmd=True, postcmd=True) 2972 except Exception, error: 2973 logger.debug('fail to load model %s with error:\n %s' % (output_dir, error)) 2974 logger.warning('Fail to load the model. Restore previous model') 2975 self.exec_cmd('import model %s' % oldmodel, errorhandling=False, 2976 printcmd=False, precmd=True, postcmd=True) 2977 raise Exception('Invalid Model! Please retry with the option \'--recreate\'.') 2978 else: 2979 return 2980 2981 #Need to do the work!!! 2982 import models.usermod as usermod 2983 base_model = usermod.UFOModel(self._curr_model.get('modelpath')) 2984 2985 identify = dict(tuple(a.split('=')) for a in args if '=' in a) 2986 base_model.add_model(path=model_path, identify_particles=identify) 2987 base_model.write(output_dir) 2988 2989 new_model_name = output_dir 2990 if restrict_name: 2991 new_model_name = '%s-%s' % (output_dir, restrict_name) 2992 2993 if 'modelname' in self.history.get('full_model_line'): 2994 opts = '--modelname' 2995 else: 2996 opts='' 2997 self.exec_cmd('import model %s %s' % (new_model_name, opts), errorhandling=False, 2998 printcmd=False, precmd=True, postcmd=True)
2999 3000 3001 # Define a multiparticle label
3002 - def do_define(self, line, log=True):
3003 """Define a multiparticle""" 3004 3005 self.avoid_history_duplicate('define %s' % line, ['define']) 3006 if not self._curr_model: 3007 self.do_import('model sm') 3008 self.history.append('define %s' % line) 3009 if not self._curr_model['case_sensitive']: 3010 # Particle names lowercase 3011 line = line.lower() 3012 # Make sure there are spaces around =, | and / 3013 line = line.replace("=", " = ") 3014 line = line.replace("|", " | ") 3015 line = line.replace("/", " / ") 3016 args = self.split_arg(line) 3017 # check the validity of the arguments 3018 self.check_define(args) 3019 3020 label = args[0] 3021 remove_ids = [] 3022 try: 3023 remove_index = args.index("/") 3024 except ValueError: 3025 pass 3026 else: 3027 remove_ids = args[remove_index + 1:] 3028 args = args[:remove_index] 3029 3030 pdg_list = self.extract_particle_ids(args[1:]) 3031 remove_list = self.extract_particle_ids(remove_ids) 3032 pdg_list = [p for p in pdg_list if p not in remove_list] 3033 3034 self.optimize_order(pdg_list) 3035 self._multiparticles[label] = pdg_list 3036 if log: 3037 logger.info("Defined multiparticle %s" % \ 3038 self.multiparticle_string(label))
3039 3040 # Display
3041 - def do_display(self, line, output=sys.stdout):
3042 """Display current internal status""" 3043 3044 args = self.split_arg(line) 3045 #check the validity of the arguments 3046 self.check_display(args) 3047 3048 if args[0] == 'diagrams': 3049 self.draw(' '.join(args[1:])) 3050 3051 if args[0] == 'particles' and len(args) == 1: 3052 propagating_particle = [] 3053 nb_unpropagating = 0 3054 for particle in self._curr_model['particles']: 3055 if particle.get('propagating'): 3056 propagating_particle.append(particle) 3057 else: 3058 nb_unpropagating += 1 3059 3060 print "Current model contains %i particles:" % \ 3061 len(propagating_particle) 3062 part_antipart = [part for part in propagating_particle \ 3063 if not part['self_antipart']] 3064 part_self = [part for part in propagating_particle \ 3065 if part['self_antipart']] 3066 for part in part_antipart: 3067 print part['name'] + '/' + part['antiname'], 3068 print '' 3069 for part in part_self: 3070 print part['name'], 3071 print '' 3072 if nb_unpropagating: 3073 print 'In addition of %s un-physical particle mediating new interactions.' \ 3074 % nb_unpropagating 3075 3076 elif args[0] == 'particles': 3077 for arg in args[1:]: 3078 if arg.isdigit() or (arg[0] == '-' and arg[1:].isdigit()): 3079 particle = self._curr_model.get_particle(abs(int(arg))) 3080 else: 3081 particle = self._curr_model['particles'].find_name(arg) 3082 if not particle: 3083 raise self.InvalidCmd, 'no particle %s in current model' % arg 3084 3085 print "Particle %s has the following properties:" % particle.get_name() 3086 print str(particle) 3087 3088 elif args[0] == 'interactions' and len(args) == 1: 3089 text = "Current model contains %i interactions\n" % \ 3090 len(self._curr_model['interactions']) 3091 for i, inter in enumerate(self._curr_model['interactions']): 3092 text += str(i+1) + ':' 3093 for part in inter['particles']: 3094 if part['is_part']: 3095 text += part['name'] 3096 else: 3097 text += part['antiname'] 3098 text += " " 3099 text += " ".join(order + '=' + str(inter['orders'][order]) \ 3100 for order in inter['orders']) 3101 text += '\n' 3102 pydoc.pager(text) 3103 3104 elif args[0] == 'interactions' and len(args)==2 and args[1].isdigit(): 3105 for arg in args[1:]: 3106 if int(arg) > len(self._curr_model['interactions']): 3107 raise self.InvalidCmd, 'no interaction %s in current model' % arg 3108 if int(arg) == 0: 3109 print 'Special interactions which identify two particles' 3110 else: 3111 print "Interactions %s has the following property:" % arg 3112 print self._curr_model['interactions'][int(arg)-1] 3113 3114 elif args[0] == 'interactions': 3115 request_part = args[1:] 3116 text = '' 3117 for i, inter in enumerate(self._curr_model['interactions']): 3118 present_part = [part['is_part'] and part['name'] or part['antiname'] 3119 for part in inter['particles'] 3120 if (part['is_part'] and part['name'] in request_part) or 3121 (not part['is_part'] and part['antiname'] in request_part)] 3122 if len(present_part) < len(request_part): 3123 continue 3124 # check that all particles are selected at least once 3125 if set(present_part) != set(request_part): 3126 continue 3127 # check if a particle is asked more than once 3128 if len(request_part) > len(set(request_part)): 3129 for p in request_part: 3130 if request_part.count(p) > present_part.count(p): 3131 continue 3132 3133 name = str(i+1) + ' : ' 3134 for part in inter['particles']: 3135 if part['is_part']: 3136 name += part['name'] 3137 else: 3138 name += part['antiname'] 3139 name += " " 3140 text += "\nInteractions %s has the following property:\n" % name 3141 text += str(self._curr_model['interactions'][i]) 3142 3143 text += '\n' 3144 print name 3145 if text =='': 3146 text += 'No matching for any interactions' 3147 pydoc.pager(text) 3148 3149 3150 elif args[0] == 'parameters' and len(args) == 1: 3151 text = "Current model contains %i parameters\n" % \ 3152 sum([len(part) for part in 3153 self._curr_model['parameters'].values()]) 3154 keys = self._curr_model['parameters'].keys() 3155 def key_sort(x, y): 3156 if ('external',) == x: 3157 return -1 3158 elif ('external',) == y: 3159 return +1 3160 elif len(x) < len(y): 3161 return -1 3162 else: 3163 return 1
3164 keys.sort(key_sort) 3165 for key in keys: 3166 item = self._curr_model['parameters'][key] 3167 text += '\nparameter type: %s\n' % str(key) 3168 for value in item: 3169 if hasattr(value, 'expr'): 3170 if value.value is not None: 3171 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3172 else: 3173 text+= ' %s = %s\n' % (value.name, value.expr) 3174 else: 3175 if value.value is not None: 3176 text+= ' %s = %s\n' % (value.name, value.value) 3177 else: 3178 text+= ' %s \n' % (value.name) 3179 pydoc.pager(text) 3180 3181 elif args[0] == 'processes': 3182 for amp in self._curr_amps: 3183 print amp.nice_string_processes() 3184 3185 elif args[0] == 'diagrams_text': 3186 text = "\n".join([amp.nice_string() for amp in self._curr_amps]) 3187 pydoc.pager(text) 3188 3189 elif args[0] == 'multiparticles': 3190 print 'Multiparticle labels:' 3191 for key in self._multiparticles: 3192 print self.multiparticle_string(key) 3193 3194 elif args[0] == 'coupling_order': 3195 hierarchy = self._curr_model['order_hierarchy'].items() 3196 #self._curr_model.get_order_hierarchy().items() 3197 def order(first, second): 3198 if first[1] < second[1]: 3199 return -1 3200 else: 3201 return 1
3202 hierarchy.sort(order) 3203 for order in hierarchy: 3204 print ' %s : weight = %s' % order 3205 3206 elif args[0] == 'couplings' and len(args) == 1: 3207 if self._model_v4_path: 3208 print 'No couplings information available in V4 model' 3209 return 3210 text = '' 3211 text = "Current model contains %i couplings\n" % \ 3212 sum([len(part) for part in 3213 self._curr_model['couplings'].values()]) 3214 keys = self._curr_model['couplings'].keys() 3215 def key_sort(x, y): 3216 if ('external',) == x: 3217 return -1 3218 elif ('external',) == y: 3219 return +1 3220 elif len(x) < len(y): 3221 return -1 3222 else: 3223 return 1 3224 keys.sort(key_sort) 3225 for key in keys: 3226 item = self._curr_model['couplings'][key] 3227 text += '\ncouplings type: %s\n' % str(key) 3228 for value in item: 3229 if value.value is not None: 3230 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3231 else: 3232 text+= ' %s = %s\n' % (value.name, value.expr) 3233 3234 pydoc.pager(text) 3235 3236 elif args[0] == 'couplings': 3237 if self._model_v4_path: 3238 print 'No couplings information available in V4 model' 3239 return 3240 3241 try: 3242 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3243 print 'Note that this is the UFO informations.' 3244 print ' "display couplings" present the actual definition' 3245 print 'prints the current states of mode' 3246 print eval('ufomodel.couplings.%s.nice_string()'%args[1]) 3247 except Exception: 3248 raise self.InvalidCmd, 'no couplings %s in current model' % args[1] 3249 3250 elif args[0] == 'lorentz': 3251 if self._model_v4_path: 3252 print 'No lorentz information available in V4 model' 3253 return 3254 elif len(args) == 1: 3255 raise self.InvalidCmd,\ 3256 'display lorentz require an argument: the name of the lorentz structure.' 3257 return 3258 try: 3259 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3260 print eval('ufomodel.lorentz.%s.nice_string()'%args[1]) 3261 except Exception: 3262 raise self.InvalidCmd, 'no lorentz %s in current model' % args[1] 3263 3264 elif args[0] == 'checks': 3265 outstr = '' 3266 if self._comparisons: 3267 comparisons = self._comparisons[0] 3268 if len(args) > 1 and args[1] == 'failed': 3269 comparisons = [c for c in comparisons if not c['passed']] 3270 outstr += "Process check results:" 3271 for comp in comparisons: 3272 outstr += "\n%s:" % comp['process'].nice_string() 3273 outstr += "\n Phase space point: (px py pz E)" 3274 for i, p in enumerate(comp['momenta']): 3275 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p) 3276 outstr += "\n Permutation values:" 3277 outstr += "\n " + str(comp['values']) 3278 if comp['passed']: 3279 outstr += "\n Process passed (rel. difference %.9e)" % \ 3280 comp['difference'] 3281 else: 3282 outstr += "\n Process failed (rel. difference %.9e)" % \ 3283 comp['difference'] 3284 3285 used_aloha = sorted(self._comparisons[1]) 3286 if used_aloha: 3287 outstr += "\nChecked ALOHA routines:" 3288 for aloha in used_aloha: 3289 aloha_str = aloha[0] 3290 if aloha[1]: 3291 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]]) 3292 aloha_str += "_%d" % aloha[2] 3293 outstr += "\n" + aloha_str 3294 3295 outstr += '\n' 3296 for cms_check in self._cms_checks: 3297 outstr += '*'*102+'\n' 3298 outstr += 'Complex Mass Scheme check:\n' 3299 outstr += ' -> check %s\n'%cms_check['line'] 3300 outstr += '*'*102+'\n' 3301 tmp_options = copy.copy(cms_check['options']) 3302 tmp_options['show_plot']=False 3303 outstr += process_checks.output_complex_mass_scheme( 3304 cms_check['cms_result'], cms_check['output_path'], 3305 tmp_options, self._curr_model) + '\n' 3306 outstr += '*'*102+'\n\n' 3307 pydoc.pager(outstr) 3308 3309 elif args[0] == 'options': 3310 if len(args) == 1: 3311 to_print = lambda name: True 3312 else: 3313 to_print = lambda name: any(poss in name for poss in args[1:]) 3314 3315 outstr = " MadGraph5_aMC@NLO Options \n" 3316 outstr += " ---------------- \n" 3317 keys = self.options_madgraph.keys() 3318 keys.sort() 3319 for key in keys: 3320 if not to_print(key): 3321 continue 3322 default = self.options_madgraph[key] 3323 value = self.options[key] 3324 if value == default: 3325 outstr += " %25s \t:\t%s\n" % (key,value) 3326 else: 3327 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3328 outstr += "\n" 3329 outstr += " MadEvent Options \n" 3330 outstr += " ---------------- \n" 3331 keys = self.options_madevent.keys() 3332 keys.sort() 3333 for key in keys: 3334 if not to_print(key): 3335 continue 3336 default = self.options_madevent[key] 3337 value = self.options[key] 3338 if value == default: 3339 outstr += " %25s \t:\t%s\n" % (key,value) 3340 else: 3341 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3342 outstr += "\n" 3343 outstr += " Configuration Options \n" 3344 outstr += " --------------------- \n" 3345 keys = self.options_configuration.keys() 3346 keys.sort() 3347 for key in keys: 3348 if not to_print(key): 3349 continue 3350 default = self.options_configuration[key] 3351 value = self.options[key] 3352 if value == default: 3353 outstr += " %25s \t:\t%s\n" % (key,value) 3354 else: 3355 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3356 3357 output.write(outstr) 3358 elif args[0] in ["variable"]: 3359 super(MadGraphCmd, self).do_display(line, output) 3360 3361
3362 - def multiparticle_string(self, key):
3363 """Returns a nicely formatted string for the multiparticle""" 3364 3365 if self._multiparticles[key] and \ 3366 isinstance(self._multiparticles[key][0], list): 3367 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\ 3368 get('particle_dict')[part_id].get_name() \ 3369 for part_id in id_list]) \ 3370 for id_list in self._multiparticles[key]])) 3371 else: 3372 return "%s = %s" % (key, " ".join([self._curr_model.\ 3373 get('particle_dict')[part_id].get_name() \ 3374 for part_id in self._multiparticles[key]]))
3375
3376 - def do_tutorial(self, line):
3377 """Activate/deactivate the tutorial mode.""" 3378 3379 args = self.split_arg(line) 3380 self.check_tutorial(args) 3381 tutorials = {'MadGraph5': logger_tuto, 3382 'aMCatNLO': logger_tuto_nlo, 3383 'MadLoop': logger_tuto_madloop} 3384 try: 3385 tutorials[args[0]].setLevel(logging.INFO) 3386 for mode in [m for m in tutorials.keys() if m != args[0]]: 3387 tutorials[mode].setLevel(logging.ERROR) 3388 except KeyError: 3389 logger_tuto.info("\n\tThanks for using the tutorial!") 3390 logger_tuto.setLevel(logging.ERROR) 3391 logger_tuto_nlo.info("\n\tThanks for using the aMC@NLO tutorial!") 3392 logger_tuto_nlo.setLevel(logging.ERROR) 3393 logger_tuto_madloop.info("\n\tThanks for using MadLoop tutorial!") 3394 logger_tuto_madloop.setLevel(logging.ERROR) 3395 3396 if not self._mgme_dir: 3397 logger_tuto.info(\ 3398 "\n\tWarning: To use all features in this tutorial, " + \ 3399 "please run from a" + \ 3400 "\n\t valid MG_ME directory.")
3401 3402 3403
3404 - def draw(self, line,selection='all',type=''):
3405 """ draw the Feynman diagram for the given process. 3406 Type refers to born, real or loop""" 3407 3408 args = self.split_arg(line) 3409 # Check the validity of the arguments 3410 self.check_draw(args) 3411 3412 # Check if we plot a decay chain 3413 if any([isinstance(a, diagram_generation.DecayChainAmplitude) for \ 3414 a in self._curr_amps]) and not self._done_export: 3415 warn = 'WARNING: You try to draw decay chain diagrams without first running output.\n' 3416 warn += '\t The decay processes will be drawn separately' 3417 logger.warning(warn) 3418 3419 (options, args) = _draw_parser.parse_args(args) 3420 options = draw_lib.DrawOption(options) 3421 start = time.time() 3422 3423 # Collect amplitudes 3424 amplitudes = diagram_generation.AmplitudeList() 3425 3426 for amp in self._curr_amps: 3427 amplitudes.extend(amp.get_amplitudes()) 3428 3429 for amp in amplitudes: 3430 filename = pjoin(args[0], 'diagrams_' + \ 3431 amp.get('process').shell_string() + ".eps") 3432 3433 if selection=='all' and type != 'loop': 3434 diags=amp.get('diagrams') 3435 elif selection=='born': 3436 diags=amp.get('born_diagrams') 3437 elif selection=='loop' or type == 'loop': 3438 diags=base_objects.DiagramList([d for d in 3439 amp.get('loop_diagrams') if d.get('type')>0]) 3440 if len(diags) > 5000: 3441 logger.warning('Displaying only the first 5000 diagrams') 3442 diags = base_objects.DiagramList(diags[:5000]) 3443 3444 plot = draw.MultiEpsDiagramDrawer(diags, 3445 filename, 3446 model=self._curr_model, 3447 amplitude=amp, 3448 legend=amp.get('process').input_string(), 3449 diagram_type=type) 3450 3451 3452 logger.info("Drawing " + \ 3453 amp.get('process').nice_string()) 3454 plot.draw(opt=options) 3455 logger.info("Wrote file " + filename) 3456 self.exec_cmd('open %s' % filename) 3457 3458 stop = time.time() 3459 logger.info('time to draw %s' % (stop - start))
3460 3461 # Perform checks
3462 - def do_check(self, line):
3463 """Check a given process or set of processes""" 3464 3465 def create_lambda_values_list(lower_bound, N): 3466 """ Returns a list of values spanning the range [1.0, lower_bound] with 3467 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered 3468 by N values uniformly distributed. For example, lower_bound=1e-2 3469 and N=5 returns: 3470 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]""" 3471 3472 lCMS_values = [1] 3473 exp = 0 3474 n = 0 3475 while lCMS_values[-1]>=lower_bound: 3476 n = (n+1) 3477 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N))) 3478 if lCMS_values[-1]==lCMS_values[-2]: 3479 lCMS_values.pop() 3480 exp = (n+1)//N 3481 3482 lCMS_values = lCMS_values[:-1] 3483 if lCMS_values[-1]!=lower_bound: 3484 lCMS_values.append(lower_bound) 3485 3486 return lCMS_values
3487 3488 ###### BEGIN do_check 3489 3490 args = self.split_arg(line) 3491 # Check args validity 3492 param_card = self.check_check(args) 3493 3494 options= {'events':None} # If the momentum needs to be picked from a event file 3495 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card): 3496 logger_check.info("Will use the param_card contained in the banner and the events associated") 3497 import madgraph.various.banner as banner 3498 options['events'] = param_card 3499 mybanner = banner.Banner(param_card) 3500 param_card = mybanner.charge_card('param_card') 3501 3502 aloha_lib.KERNEL.clean() 3503 # Back up the gauge for later 3504 gauge = str(self.options['gauge']) 3505 options['reuse'] = args[1]=="-reuse" 3506 args = args[:1]+args[2:] 3507 # For the stability check the user can specify the statistics (i.e 3508 # number of trial PS points) as a second argument 3509 if args[0] in ['stability', 'profile']: 3510 options['npoints'] = int(args[1]) 3511 args = args[:1]+args[2:] 3512 3513 MLoptions={} 3514 i=-1 3515 CMS_options = {} 3516 while args[i].startswith('--'): 3517 option = args[i].split('=') 3518 if option[0] =='--energy': 3519 options['energy']=float(option[1]) 3520 elif option[0]=='--split_orders': 3521 options['split_orders']=int(option[1]) 3522 elif option[0]=='--helicity': 3523 try: 3524 options['helicity']=int(option[1]) 3525 except ValueError: 3526 raise self.InvalidCmd("The value of the 'helicity' option"+\ 3527 " must be an integer, not %s."%option[1]) 3528 elif option[0]=='--reduction': 3529 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')] 3530 elif option[0]=='--CTModeRun': 3531 try: 3532 MLoptions['CTModeRun']=int(option[1]) 3533 except ValueError: 3534 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\ 3535 " must be an integer, not %s."%option[1]) 3536 elif option[0]=='--offshellness': 3537 CMS_options['offshellness'] = float(option[1]) 3538 if CMS_options['offshellness']<=-1.0: 3539 raise self.InvalidCmd('Offshellness must be number larger or'+ 3540 ' equal to -1.0, not %f'%CMS_options['offshellness']) 3541 elif option[0]=='--analyze': 3542 options['analyze'] = option[1] 3543 elif option[0]=='--show_plot': 3544 options['show_plot'] = 'true' in option[1].lower() 3545 elif option[0]=='--report': 3546 options['report'] = option[1].lower() 3547 elif option[0]=='--seed': 3548 options['seed'] = int(option[1]) 3549 elif option[0]=='--name': 3550 if '.' in option[1]: 3551 raise self.InvalidCmd("Do not specify the extension in the"+ 3552 " name of the run") 3553 CMS_options['name'] = option[1] 3554 elif option[0]=='--resonances': 3555 if option[1]=='all': 3556 CMS_options['resonances'] = 'all' 3557 else: 3558 try: 3559 resonances=eval(option[1]) 3560 except: 3561 raise self.InvalidCmd("Could not evaluate 'resonances'"+ 3562 " option '%s'"%option[1]) 3563 if isinstance(resonances,int) and resonances>0: 3564 CMS_options['resonances'] = resonances 3565 elif isinstance(resonances,list) and all(len(res)==2 and 3566 isinstance(res[0],int) and all(isinstance(i, int) for i in 3567 res[1]) for res in resonances): 3568 CMS_options['resonances'] = resonances 3569 else: 3570 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+ 3571 " or and integer or a list of tuples of the form "+ 3572 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1]) 3573 elif option[0]=='--tweak': 3574 # Lists the sets of custom and widths modifications to apply 3575 value = option[1] 3576 # Set a shortcuts for applying all relevant tweaks 3577 if value=='alltweaks': 3578 value=str(['default','seed667(seed667)','seed668(seed668)', 3579 'allwidths->0.9*allwidths(widths_x_0.9)', 3580 'allwidths->0.99*allwidths(widths_x_0.99)', 3581 'allwidths->1.01*allwidths(widths_x_1.01)', 3582 'allwidths->1.1*allwidths(widths_x_1.1)', 3583 'logp->logm(logp2logm)','logm->logp(logm2logp)']) 3584 try: 3585 tweaks = eval(value) 3586 if isinstance(tweaks, str): 3587 tweaks = [value] 3588 elif not isinstance(tweaks,list): 3589 tweaks = [value] 3590 except: 3591 tweaks = [value] 3592 if not all(isinstance(t,str) for t in tweaks): 3593 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value) 3594 CMS_options['tweak'] = [] 3595 for tweakID, tweakset in enumerate(tweaks): 3596 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset) 3597 if specs: 3598 tweakset = specs.group('tweakset') 3599 name = specs.group('name') 3600 else: 3601 if tweakset!='default': 3602 name = 'tweak_%d'%(tweakID+1) 3603 else: 3604 name = '' 3605 new_tweak_set = {'custom':[],'params':{},'name':name} 3606 for tweak in tweakset.split('&'): 3607 if tweak=='default': 3608 continue 3609 if tweak.startswith('seed'): 3610 new_tweak_set['custom'].append(tweak) 3611 continue 3612 try: 3613 param, replacement = tweak.split('->') 3614 except ValueError: 3615 raise self.InvalidCmd("Tweak specification '%s'"%\ 3616 tweak+" is incorrect. It should be of"+\ 3617 " the form a->_any_function_of_(a,lambdaCMS).") 3618 if param in ['logp','logm','log'] and \ 3619 replacement in ['logp','logm','log']: 3620 new_tweak_set['custom'].append(tweak) 3621 continue 3622 try: 3623 # for safety prefix parameters, because 'as' for alphas 3624 # is a python reserved name for example 3625 orig_param, orig_replacement = param, replacement 3626 replacement = replacement.replace(param, 3627 '__tmpprefix__%s'%param) 3628 param = '__tmpprefix__%s'%param 3629 res = float(eval(replacement.lower(), 3630 {'lambdacms':1.0,param.lower():98.85})) 3631 except: 3632 raise self.InvalidCmd("The substitution expression "+ 3633 "'%s' for the tweaked parameter"%orig_replacement+ 3634 " '%s' could not be evaluated. It must be an "%orig_param+ 3635 "expression of the parameter and 'lambdaCMS'.") 3636 new_tweak_set['params'][param.lower()] = replacement.lower() 3637 CMS_options['tweak'].append(new_tweak_set) 3638 3639 elif option[0]=='--recompute_width': 3640 if option[1].lower() not in ['never','always','first_time','auto']: 3641 raise self.InvalidCmd("The option 'recompute_width' can "+\ 3642 "only be 'never','always', 'first_time' or 'auto' (default).") 3643 CMS_options['recompute_width'] = option[1] 3644 elif option[0]=='--loop_filter': 3645 # Specify a loop, filter. See functions get_loop_filter and 3646 # user_filter in loop_diagram_generation.LoopAmplitude for 3647 # information on usage. 3648 CMS_options['loop_filter'] = '='.join(option[1:]) 3649 elif option[0]=='--diff_lambda_power': 3650 #'secret' option to chose by which lambda power one should divide 3651 # the nwa-cms difference. Useful to set to 2 when doing the Born check 3652 # to see whether the NLO check will have sensitivity to the CMS 3653 # implementation 3654 try: 3655 CMS_options['diff_lambda_power']=float(option[1]) 3656 except ValueError: 3657 raise self.InvalidCmd("the '--diff_lambda_power' option"+\ 3658 " must be an integer or float, not '%s'."%option[1]) 3659 elif option[0]=='--lambda_plot_range': 3660 try: 3661 plot_range=eval(option[1]) 3662 except Exception as e: 3663 raise self.InvalidCmd("The plot range specified %s"%option[1]+\ 3664 " is not a valid syntax. Error:\n%s"%str(e)) 3665 if not isinstance(plot_range,(list,tuple)) or \ 3666 len(plot_range)!=2 or any(not isinstance(p,(float,int)) 3667 for p in plot_range): 3668 raise self.InvalidCmd("The plot range specified %s"\ 3669 %option[1]+" is invalid") 3670 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range]) 3671 elif option[0]=='--lambdaCMS': 3672 try: 3673 lambda_values = eval(option[1]) 3674 except SyntaxError: 3675 raise self.InvalidCmd("'%s' is not a correct"%option[1]+ 3676 " python expression for lambdaCMS values.") 3677 if isinstance(lambda_values,list): 3678 if lambda_values[0]!=1.0: 3679 raise self.InvalidCmd("The first value of the lambdaCMS values"+ 3680 " specified must be 1.0, not %s"%str(lambda_values)) 3681 for l in lambda_values: 3682 if not isinstance(l,float): 3683 raise self.InvalidCmd("All lambda CMS values must be"+ 3684 " float, not '%s'"%str(l)) 3685 elif isinstance(lambda_values,(tuple,float)): 3686 # Format here is then (lower_bound, N) were lower_bound is 3687 # the minimum lambdaCMS value that must be probed and the 3688 # integer N is the number of such values that must be 3689 # uniformly distributed in each intervale [1.0e-i,1.0e-(i+1)] 3690 if isinstance(lambda_values, float): 3691 # Use default of 10 for the number of lambda values 3692 lower_bound = lambda_values 3693 N = 10 3694 else: 3695 if isinstance(lambda_values[0],float) and \ 3696 isinstance(lambda_values[1],int): 3697 lower_bound = lambda_values[0] 3698 N = lambda_values[1] 3699 else: 3700 raise self.InvalidCmd("'%s' must be a "%option[1]+ 3701 "tuple with types (float, int).") 3702 lambda_values = create_lambda_values_list(lower_bound,N) 3703 else: 3704 raise self.InvalidCmd("'%s' must be an expression"%option[1]+ 3705 " for either a float, tuple or list.") 3706 lower_bound = lambda_values[-1] 3707 # and finally add 5 points for stability test on the last values 3708 # Depending on how the stab test will behave at NLO, we can 3709 # consider automatically adding the values below 3710 # for stab in range(1,6): 3711 # lambda_values.append((1.0+(stab/100.0))*lower_bound) 3712 3713 CMS_options['lambdaCMS'] = lambda_values 3714 elif option[0]=='--cms': 3715 try: 3716 CMS_expansion_orders, CMS_expansion_parameters = \ 3717 option[1].split(',') 3718 except ValueError: 3719 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 3720 args[i]+" is incorrect.") 3721 CMS_options['expansion_orders'] = [expansion_order for 3722 expansion_order in CMS_expansion_orders.split('&')] 3723 CMS_options['expansion_parameters'] = {} 3724 for expansion_parameter in CMS_expansion_parameters.split('&'): 3725 try: 3726 param, replacement = expansion_parameter.split('->') 3727 except ValueError: 3728 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 3729 expansion_parameter+" is incorrect. It should be of"+\ 3730 " the form a->_any_function_of_(a,lambdaCMS).") 3731 try: 3732 # for safety prefix parameters, because 'as' for alphas 3733 # is a python reserved name for example 3734 orig_param, orig_replacement = param, replacement 3735 replacement = replacement.replace(param, 3736 '__tmpprefix__%s'%param) 3737 param = '__tmpprefix__%s'%param 3738 res = float(eval(replacement.lower(), 3739 {'lambdacms':1.0,param.lower():98.85})) 3740 except: 3741 raise self.InvalidCmd("The substitution expression "+ 3742 "'%s' for CMS expansion parameter"%orig_replacement+ 3743 " '%s' could not be evaluated. It must be an "%orig_param+ 3744 "expression of the parameter and 'lambdaCMS'.") 3745 # Put everything lower case as it will be done when 3746 # accessing model variables 3747 CMS_options['expansion_parameters'][param.lower()]=\ 3748 replacement.lower() 3749 else: 3750 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0]) 3751 3752 i=i-1 3753 args = args[:i+1] 3754 3755 if args[0]=='options': 3756 # Simple printout of the check command options 3757 logger_check.info("Options for the command 'check' are:") 3758 logger_check.info("{:<20} {}".format(' name','default value')) 3759 logger_check.info("-"*40) 3760 for key, value in options.items(): 3761 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 3762 return 3763 3764 if args[0].lower()=='cmsoptions': 3765 # Simple printout of the special check cms options 3766 logger_check.info("Special options for the command 'check cms' are:") 3767 logger_check.info("{:<20} {}".format(' name','default value')) 3768 logger_check.info("-"*40) 3769 for key, value in CMS_options.items(): 3770 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 3771 return 3772 3773 # Set the seed here if not in cms check and if specified 3774 if args[0]!='cms' and options['seed']!=-1: 3775 # Not necessarily optimal as there could be additional call to 3776 # random() as the code develops, but at least it will encompass 3777 # everything in this way. 3778 logger_check.info('Setting random seed to %d.'%options['seed']) 3779 random.seed(options['seed']) 3780 3781 proc_line = " ".join(args[1:]) 3782 # Don't try to extract the process if just re-analyzing a saved run 3783 if not (args[0]=='cms' and options['analyze']!='None'): 3784 myprocdef = self.extract_process(proc_line) 3785 3786 # Check that we have something 3787 if not myprocdef: 3788 raise self.InvalidCmd("Empty or wrong format process, please try again.") 3789 # For the check command, only the mode 'virt' make sense. 3790 if myprocdef.get('NLO_mode')=='all': 3791 myprocdef.set('NLO_mode','virt') 3792 else: 3793 myprocdef = None 3794 3795 # If the test has to write out on disk, it should do so at the location 3796 # specified below where the user must be sure to have writing access. 3797 output_path = os.getcwd() 3798 3799 if args[0] in ['timing','stability', 'profile'] and not \ 3800 myprocdef.get('perturbation_couplings'): 3801 raise self.InvalidCmd("Only loop processes can have their "+ 3802 " timings or stability checked.") 3803 3804 if args[0]=='gauge' and \ 3805 not myprocdef.get('perturbation_couplings') in [[],['QCD']]: 3806 raise self.InvalidCmd( 3807 """Feynman vs unitary gauge comparisons can only be done if there are no loop 3808 propagators affected by this gauge. Typically, either processes at tree level 3809 or including only QCD perturbations can be considered here.""") 3810 3811 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2: 3812 raise self.InvalidCmd("The current model does not allow for both "+\ 3813 "Feynman and unitary gauge.") 3814 3815 # Disable some loggers 3816 loggers = [logging.getLogger('madgraph.diagram_generation'), 3817 logging.getLogger('madgraph.loop_diagram_generation'), 3818 logging.getLogger('ALOHA'), 3819 logging.getLogger('madgraph.helas_objects'), 3820 logging.getLogger('madgraph.loop_exporter'), 3821 logging.getLogger('madgraph.export_v4'), 3822 logging.getLogger('cmdprint'), 3823 logging.getLogger('madgraph.model'), 3824 logging.getLogger('madgraph.base_objects')] 3825 old_levels = [log.level for log in loggers] 3826 for log in loggers: 3827 log.setLevel(logging.WARNING) 3828 3829 # run the check 3830 cpu_time1 = time.time() 3831 # Run matrix element generation check on processes 3832 3833 # The aloha python output has trouble when doing (tree level of course) 3834 # python output and that loop_mode is True at the beginning. 3835 # So as a temporary fix for the problem that after doing a check at NLO 3836 # then a check at LO will fail, I make sure I set it to False if the 3837 # process is a tree-level one 3838 if myprocdef: 3839 if myprocdef.get('perturbation_couplings')==[]: 3840 aloha.loop_mode = False 3841 3842 comparisons = [] 3843 gauge_result = [] 3844 gauge_result_no_brs = [] 3845 lorentz_result =[] 3846 nb_processes = 0 3847 timings = [] 3848 stability = [] 3849 profile_time = [] 3850 profile_stab = [] 3851 cms_results = [] 3852 3853 if "_cuttools_dir" in dir(self): 3854 CT_dir = self._cuttools_dir 3855 else: 3856 CT_dir ="" 3857 if "MLReductionLib" in MLoptions: 3858 if 1 in MLoptions["MLReductionLib"]: 3859 MLoptions["MLReductionLib"].remove(1) 3860 # directories for TIR 3861 TIR_dir={} 3862 if "_iregi_dir" in dir(self): 3863 TIR_dir['iregi_dir']=self._iregi_dir 3864 else: 3865 if "MLReductionLib" in MLoptions: 3866 if 3 in MLoptions["MLReductionLib"]: 3867 logger_check.warning('IREGI not available on your system; it will be skipped.') 3868 MLoptions["MLReductionLib"].remove(3) 3869 3870 if 'pjfry' in self.options and isinstance(self.options['pjfry'],str): 3871 TIR_dir['pjfry_dir']=self.options['pjfry'] 3872 else: 3873 if "MLReductionLib" in MLoptions: 3874 if 2 in MLoptions["MLReductionLib"]: 3875 logger_check.warning('PJFRY not available on your system; it will be skipped.') 3876 MLoptions["MLReductionLib"].remove(2) 3877 3878 if 'golem' in self.options and isinstance(self.options['golem'],str): 3879 TIR_dir['golem_dir']=self.options['golem'] 3880 else: 3881 if "MLReductionLib" in MLoptions: 3882 if 4 in MLoptions["MLReductionLib"]: 3883 logger_check.warning('GOLEM not available on your system; it will be skipped.') 3884 MLoptions["MLReductionLib"].remove(4) 3885 3886 if 'samurai' in self.options and isinstance(self.options['samurai'],str): 3887 TIR_dir['samurai_dir']=self.options['samurai'] 3888 else: 3889 if "MLReductionLib" in MLoptions: 3890 if 5 in MLoptions["MLReductionLib"]: 3891 logger_check.warning('Samurai not available on your system; it will be skipped.') 3892 MLoptions["MLReductionLib"].remove(5) 3893 3894 if 'ninja' in self.options and isinstance(self.options['ninja'],str): 3895 TIR_dir['ninja_dir']=self.options['ninja'] 3896 else: 3897 if "MLReductionLib" in MLoptions: 3898 if 6 in MLoptions["MLReductionLib"]: 3899 logger_check.warning('Ninja not available on your system; it will be skipped.') 3900 MLoptions["MLReductionLib"].remove(6) 3901 3902 if args[0] in ['timing']: 3903 timings = process_checks.check_timing(myprocdef, 3904 param_card = param_card, 3905 cuttools=CT_dir, 3906 tir=TIR_dir, 3907 options = options, 3908 cmd = self, 3909 output_path = output_path, 3910 MLOptions = MLoptions 3911 ) 3912 3913 if args[0] in ['stability']: 3914 stability=process_checks.check_stability(myprocdef, 3915 param_card = param_card, 3916 cuttools=CT_dir, 3917 tir=TIR_dir, 3918 options = options, 3919 output_path = output_path, 3920 cmd = self, 3921 MLOptions = MLoptions) 3922 3923 if args[0] in ['profile']: 3924 # In this case timing and stability will be checked one after the 3925 # other without re-generating the process. 3926 profile_time, profile_stab = process_checks.check_profile(myprocdef, 3927 param_card = param_card, 3928 cuttools=CT_dir, 3929 tir=TIR_dir, 3930 options = options, 3931 MLOptions = MLoptions, 3932 output_path = output_path, 3933 cmd = self) 3934 3935 if args[0] in ['gauge', 'full'] and \ 3936 len(self._curr_model.get('gauge')) == 2 and\ 3937 myprocdef.get('perturbation_couplings') in [[],['QCD']]: 3938 3939 line = " ".join(args[1:]) 3940 myprocdef = self.extract_process(line) 3941 if gauge == 'unitary': 3942 myprocdef_unit = myprocdef 3943 self.do_set('gauge Feynman', log=False) 3944 myprocdef_feyn = self.extract_process(line) 3945 else: 3946 myprocdef_feyn = myprocdef 3947 self.do_set('gauge unitary', log=False) 3948 myprocdef_unit = self.extract_process(line) 3949 3950 nb_part_unit = len(myprocdef_unit.get('model').get('particles')) 3951 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles')) 3952 if nb_part_feyn == nb_part_unit: 3953 logger_check.error('No Goldstone present for this check!!') 3954 gauge_result_no_brs = process_checks.check_unitary_feynman( 3955 myprocdef_unit, myprocdef_feyn, 3956 param_card = param_card, 3957 options=options, 3958 cuttools=CT_dir, 3959 tir=TIR_dir, 3960 reuse = options['reuse'], 3961 output_path = output_path, 3962 cmd = self) 3963 3964 # restore previous settings 3965 self.do_set('gauge %s' % gauge, log=False) 3966 nb_processes += len(gauge_result_no_brs) 3967 3968 if args[0] in ['permutation', 'full']: 3969 comparisons = process_checks.check_processes(myprocdef, 3970 param_card = param_card, 3971 quick = True, 3972 cuttools=CT_dir, 3973 tir=TIR_dir, 3974 reuse = options['reuse'], 3975 cmd = self, 3976 output_path = output_path, 3977 options=options) 3978 nb_processes += len(comparisons[0]) 3979 3980 if args[0] in ['lorentz', 'full']: 3981 myprocdeff = copy.copy(myprocdef) 3982 lorentz_result = process_checks.check_lorentz(myprocdeff, 3983 param_card = param_card, 3984 cuttools=CT_dir, 3985 tir=TIR_dir, 3986 reuse = options['reuse'], 3987 cmd = self, 3988 output_path = output_path, 3989 options=options) 3990 nb_processes += len(lorentz_result) 3991 3992 if args[0] in ['brs', 'full']: 3993 gauge_result = process_checks.check_gauge(myprocdef, 3994 param_card = param_card, 3995 cuttools=CT_dir, 3996 tir=TIR_dir, 3997 reuse = options['reuse'], 3998 cmd = self, 3999 output_path = output_path, 4000 options=options) 4001 nb_processes += len(gauge_result) 4002 4003 # The CMS check is typically more complicated and slower than others 4004 # so we don't run it automatically with 'full'. 4005 if args[0] in ['cms']: 4006 4007 cms_original_setup = self.options['complex_mass_scheme'] 4008 process_line = " ".join(args[1:]) 4009 # Merge in the CMS_options to the options 4010 for key, value in CMS_options.items(): 4011 if key=='tweak': 4012 continue 4013 if key not in options: 4014 options[key] = value 4015 else: 4016 raise MadGraph5Error,"Option '%s' is both in the option"%key+\ 4017 " and CMS_option dictionary." 4018 4019 if options['analyze']=='None': 4020 cms_results = [] 4021 for tweak in CMS_options['tweak']: 4022 options['tweak']=tweak 4023 # Try to guess the save path and try to load it before running 4024 guessed_proc = myprocdef.get_process( 4025 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4026 if not leg.get('state')], 4027 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4028 if leg.get('state')]) 4029 save_path = process_checks.CMS_save_path('pkl', 4030 {'ordered_processes':[guessed_proc.base_string()], 4031 'perturbation_orders':guessed_proc.get('perturbation_couplings')}, 4032 self._curr_model, options, output_path=output_path) 4033 if os.path.isfile(save_path) and options['reuse']: 4034 cms_result = save_load_object.load_from_file(save_path) 4035 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"% 4036 (tweak['name'],save_path)) 4037 if cms_result is None: 4038 raise self.InvalidCmd('The complex mass scheme check result'+ 4039 " file below could not be read.\n %s"%save_path) 4040 else: 4041 cms_result = process_checks.check_complex_mass_scheme( 4042 process_line, 4043 param_card = param_card, 4044 cuttools=CT_dir, 4045 tir=TIR_dir, 4046 cmd = self, 4047 output_path = output_path, 4048 MLOptions = MLoptions, 4049 options=options) 4050 # Now set the correct save path 4051 save_path = process_checks.CMS_save_path('pkl', cms_result, 4052 self._curr_model, options, output_path=output_path) 4053 cms_results.append((cms_result,save_path,tweak['name'])) 4054 else: 4055 cms_result = save_load_object.load_from_file( 4056 options['analyze'].split(',')[0]) 4057 cms_results.append((cms_result,options['analyze'].split(',')[0], 4058 CMS_options['tweak'][0]['name'])) 4059 if cms_result is None: 4060 raise self.InvalidCmd('The complex mass scheme check result'+ 4061 " file below could not be read.\n %s" 4062 %options['analyze'].split(',')[0]) 4063 4064 # restore previous settings 4065 self.do_set('complex_mass_scheme %s'%str(cms_original_setup), 4066 log=False) 4067 # Use here additional key 'ordered_processes' 4068 nb_processes += len(cms_result['ordered_processes']) 4069 4070 cpu_time2 = time.time() 4071 logger_check.info("%i check performed in %s"% (nb_processes, 4072 misc.format_time(int(cpu_time2 - cpu_time1)))) 4073 4074 if args[0] in ['cms']: 4075 text = "Note that the complex mass scheme test in principle only\n" 4076 text+= "works for stable particles in final states.\n\ns" 4077 if args[0] not in ['timing','stability', 'profile', 'cms']: 4078 if self.options['complex_mass_scheme']: 4079 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n" 4080 text+= "results only for stable particles in final states.\n\ns" 4081 elif not myprocdef.get('perturbation_couplings'): 4082 text = "Note That all width have been set to zero for those checks\n\n" 4083 else: 4084 text = "\n" 4085 else: 4086 text ="\n" 4087 4088 if timings: 4089 text += 'Timing result for the '+('optimized' if \ 4090 self.options['loop_optimized_output'] else 'default')+' output:\n' 4091 4092 text += process_checks.output_timings(myprocdef, timings) 4093 if stability: 4094 text += 'Stability result for the '+('optimized' if \ 4095 self.options['loop_optimized_output'] else 'default')+' output:\n' 4096 text += process_checks.output_stability(stability,output_path) 4097 4098 if profile_time and profile_stab: 4099 text += 'Timing result '+('optimized' if \ 4100 self.options['loop_optimized_output'] else 'default')+':\n' 4101 text += process_checks.output_profile(myprocdef, profile_stab, 4102 profile_time, output_path, options['reuse']) + '\n' 4103 if lorentz_result: 4104 text += 'Lorentz invariance results:\n' 4105 text += process_checks.output_lorentz_inv(lorentz_result) + '\n' 4106 if gauge_result: 4107 text += 'Gauge results:\n' 4108 text += process_checks.output_gauge(gauge_result) + '\n' 4109 if gauge_result_no_brs: 4110 text += 'Gauge results (switching between Unitary/Feynman):\n' 4111 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n' 4112 if cms_results: 4113 text += 'Complex mass scheme results (varying width in the off-shell regions):\n' 4114 cms_result = cms_results[0][0] 4115 if len(cms_results)>1: 4116 analyze = [] 4117 for i, (cms_res, save_path, tweakname) in enumerate(cms_results): 4118 save_load_object.save_to_file(save_path, cms_res) 4119 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"% 4120 (tweakname,save_path)) 4121 if i==0: 4122 analyze.append(save_path) 4123 else: 4124 analyze.append('%s(%s)'%(save_path,tweakname)) 4125 options['analyze']=','.join(analyze) 4126 options['tweak'] = CMS_options['tweak'][0] 4127 4128 self._cms_checks.append({'line':line, 'cms_result':cms_result, 4129 'options':options, 'output_path':output_path}) 4130 text += process_checks.output_complex_mass_scheme(cms_result, 4131 output_path, options, self._curr_model, 4132 output='concise_text' if options['report']=='concise' else 'text')+'\n' 4133 4134 if comparisons and len(comparisons[0])>0: 4135 text += 'Process permutation results:\n' 4136 text += process_checks.output_comparisons(comparisons[0]) + '\n' 4137 self._comparisons = comparisons 4138 4139 # We use the reuse tag for an alternative way of skipping the pager. 4140 if len(text.split('\n'))>20 and not '-reuse' in line and text!='': 4141 if 'test_manager' not in sys.argv[0]: 4142 pydoc.pager(text) 4143 4144 # Restore diagram logger 4145 for i, log in enumerate(loggers): 4146 log.setLevel(old_levels[i]) 4147 4148 # Output the result to the interface directly if short enough or if it 4149 # was anyway not output to the pager 4150 if len(text.split('\n'))<=20 or options['reuse']: 4151 # Useful to really specify what logger is used for ML acceptance tests 4152 logging.getLogger('madgraph.check_cmd').info(text) 4153 else: 4154 logging.getLogger('madgraph.check_cmd').debug(text) 4155 4156 # clean the globals created. 4157 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL) 4158 if not options['reuse']: 4159 process_checks.clean_up(self._mgme_dir) 4160 4161 # Generate a new amplitude
4162 - def do_generate(self, line):
4163 """Main commands: Generate an amplitude for a given process""" 4164 4165 aloha_lib.KERNEL.clean() 4166 # Reset amplitudes 4167 self._curr_amps = diagram_generation.AmplitudeList() 4168 # Reset Helas matrix elements 4169 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4170 self._generate_info = line 4171 # Reset _done_export, since we have new process 4172 self._done_export = False 4173 # Also reset _export_format and _export_dir 4174 self._export_format = None 4175 4176 4177 # Call add process 4178 args = self.split_arg(line) 4179 args.insert(0, 'process') 4180 self.do_add(" ".join(args))
4181
4182 - def extract_process(self, line, proc_number = 0, overall_orders = {}):
4183 """Extract a process definition from a string. Returns 4184 a ProcessDefinition.""" 4185 4186 orig_line = line 4187 # Check basic validity of the line 4188 if not len(re.findall('>\D', line)) in [1,2]: 4189 self.do_help('generate') 4190 raise self.InvalidCmd('Wrong use of \">\" special character.') 4191 4192 4193 # Perform sanity modifications on the lines: 4194 # Add a space before and after any > , $ / | [ ] 4195 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)") 4196 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line) 4197 4198 # Use regular expressions to extract s-channel propagators, 4199 # forbidden s-channel propagators/particles, coupling orders 4200 # and process number, starting from the back 4201 4202 # Start with process number (identified by "@") 4203 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4204 proc_number_re = proc_number_pattern.match(line) 4205 if proc_number_re: 4206 proc_number = int(proc_number_re.group(2)) 4207 line = proc_number_re.group(1)+ proc_number_re.group(3) 4208 #overall_order are already handle but it is better to pass the info to each group 4209 4210 # Now check for perturbation orders, specified in between squared brackets 4211 perturbation_couplings_pattern = \ 4212 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\ 4213 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 4214 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 4215 perturbation_couplings = "" 4216 LoopOption= 'tree' 4217 HasBorn= True 4218 if perturbation_couplings_re: 4219 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 4220 option=perturbation_couplings_re.group("option") 4221 if option: 4222 if option in self._valid_nlo_modes: 4223 LoopOption=option 4224 if option=='sqrvirt': 4225 LoopOption='virt' 4226 HasBorn=False 4227 elif option=='noborn': 4228 HasBorn=False 4229 else: 4230 raise self.InvalidCmd, "NLO mode %s is not valid. "%option+\ 4231 "Valid modes are %s. "%str(self._valid_nlo_modes) 4232 else: 4233 LoopOption='all' 4234 4235 line = perturbation_couplings_re.group("proc")+\ 4236 perturbation_couplings_re.group("rest") 4237 4238 ## Now check for orders/squared orders/constrained orders 4239 order_pattern = re.compile(\ 4240 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\ 4241 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*$") 4242 order_re = order_pattern.match(line) 4243 squared_orders = {} 4244 orders = {} 4245 constrained_orders = {} 4246 ## The 'split_orders' (i.e. those for which individual matrix element 4247 ## evalutations must be provided for each corresponding order value) are 4248 ## defined from the orders specified in between [] and any order for 4249 ## which there are squared order constraints. 4250 split_orders = [] 4251 while order_re: 4252 type = order_re.group('type') 4253 if order_re.group('name').endswith('^2'): 4254 if type not in self._valid_sqso_types: 4255 raise self.InvalidCmd, "Type of squared order "+\ 4256 "constraint '%s'"% type+" is not supported." 4257 if type == '=': 4258 name = order_re.group('name') 4259 value = order_re.group('value') 4260 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4261 {'n':name, 'v': value}) 4262 type = "<=" 4263 squared_orders[order_re.group('name')[:-2]] = \ 4264 (int(order_re.group('value')),type) 4265 else: 4266 if type not in self._valid_amp_so_types: 4267 raise self.InvalidCmd, \ 4268 "Amplitude order constraints can only be of type %s"%\ 4269 (', '.join(self._valid_amp_so_types))+", not '%s'."%type 4270 name = order_re.group('name') 4271 value = int(order_re.group('value')) 4272 if type in ['=', '<=']: 4273 if type == '=' and value != 0: 4274 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4275 {'n':name, 'v': value}) 4276 orders[name] = value 4277 elif type == "==": 4278 constrained_orders[name] = (value, type) 4279 if name not in squared_orders: 4280 squared_orders[name] = (2 * value,'==') 4281 if True:#name not in orders: 4282 orders[name] = value 4283 4284 elif type == ">": 4285 constrained_orders[name] = (value, type) 4286 if name not in squared_orders: 4287 squared_orders[name] = (2 * value,'>') 4288 4289 line = order_re.group('before') 4290 order_re = order_pattern.match(line) 4291 4292 #only allow amplitue restrctions >/ == for LO/tree level 4293 if constrained_orders and LoopOption != 'tree': 4294 raise self.InvalidCmd, \ 4295 "Amplitude order constraints (for not LO processes) can only be of type %s"%\ 4296 (', '.join(['<=']))+", not '%s'."%type 4297 4298 # If the squared orders are defined but not the orders, assume 4299 # orders=sq_orders. In case the squared order has a negative value or is 4300 # defined with the '>' operato, then this order correspondingly set to 4301 # be maximal (99) since there is no way to know, during generation, if 4302 # the amplitude being contstructed will be leading or not. 4303 if orders=={} and squared_orders!={}: 4304 for order in squared_orders.keys(): 4305 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>': 4306 orders[order]=squared_orders[order][0] 4307 else: 4308 orders[order]=99 4309 4310 if not self._curr_model['case_sensitive']: 4311 # Particle names lowercase 4312 line = line.lower() 4313 4314 # Now check for forbidden particles, specified using "/" 4315 slash = line.find("/") 4316 dollar = line.find("$") 4317 forbidden_particles = "" 4318 if slash > 0: 4319 if dollar > slash: 4320 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line) 4321 else: 4322 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line) 4323 if forbidden_particles_re: 4324 forbidden_particles = forbidden_particles_re.group(2) 4325 line = forbidden_particles_re.group(1) 4326 if len(forbidden_particles_re.groups()) > 2: 4327 line = line + forbidden_particles_re.group(3) 4328 4329 # Now check for forbidden schannels, specified using "$$" 4330 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line) 4331 forbidden_schannels = "" 4332 if forbidden_schannels_re: 4333 forbidden_schannels = forbidden_schannels_re.group(2) 4334 line = forbidden_schannels_re.group(1) 4335 4336 # Now check for forbidden onshell schannels, specified using "$" 4337 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line) 4338 forbidden_onsh_schannels = "" 4339 if forbidden_onsh_schannels_re: 4340 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2) 4341 line = forbidden_onsh_schannels_re.group(1) 4342 4343 # Now check for required schannels, specified using "> >" 4344 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line) 4345 required_schannels = "" 4346 if required_schannels_re: 4347 required_schannels = required_schannels_re.group(2) 4348 line = required_schannels_re.group(1) + ">" + \ 4349 required_schannels_re.group(3) 4350 4351 args = self.split_arg(line) 4352 4353 myleglist = base_objects.MultiLegList() 4354 state = False 4355 4356 # Extract process 4357 for part_name in args: 4358 if part_name == '>': 4359 if not myleglist: 4360 raise self.InvalidCmd, "No final state particles" 4361 state = True 4362 continue 4363 4364 mylegids = [] 4365 if part_name in self._multiparticles: 4366 if isinstance(self._multiparticles[part_name][0], list): 4367 raise self.InvalidCmd,\ 4368 "Multiparticle %s is or-multiparticle" % part_name + \ 4369 " which can be used only for required s-channels" 4370 mylegids.extend(self._multiparticles[part_name]) 4371 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit(): 4372 if int(part_name) in self._curr_model.get('particle_dict'): 4373 mylegids.append(int(part_name)) 4374 else: 4375 raise self.InvalidCmd, \ 4376 "No pdg_code %s in model" % part_name 4377 else: 4378 mypart = self._curr_model['particles'].get_copy(part_name) 4379 if mypart: 4380 mylegids.append(mypart.get_pdg_code()) 4381 4382 if mylegids: 4383 myleglist.append(base_objects.MultiLeg({'ids':mylegids, 4384 'state':state})) 4385 else: 4386 raise self.InvalidCmd, "No particle %s in model" % part_name 4387 4388 # Apply the keyword 'all' for perturbed coupling orders. 4389 if perturbation_couplings.lower()=='all': 4390 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings']) 4391 4392 if filter(lambda leg: leg.get('state') == True, myleglist): 4393 # We have a valid process 4394 # Extract perturbation orders 4395 perturbation_couplings_list = perturbation_couplings.split() 4396 if perturbation_couplings_list==['']: 4397 perturbation_couplings_list=[] 4398 # Correspondingly set 'split_order' from the squared orders and the 4399 # perturbation couplings list 4400 split_orders=list(set(perturbation_couplings_list+squared_orders.keys())) 4401 try: 4402 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else 4403 self._curr_model['order_hierarchy'] 4404 [elem if not elem.endswith('.sqrt') else elem[:-5]]) 4405 except KeyError: 4406 raise self.InvalidCmd, "The loaded model does not defined a "+\ 4407 " coupling order hierarchy for these couplings: %s"%\ 4408 str([so for so in split_orders if so!='WEIGHTED' and so not 4409 in self._curr_model['order_hierarchy'].keys()]) 4410 4411 # If the loopOption is 'tree' then the user used the syntax 4412 # [tree= Orders] for the sole purpose of setting split_orders. We 4413 # then empty the perturbation_couplings_list at this stage. 4414 if LoopOption=='tree': 4415 perturbation_couplings_list = [] 4416 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']: 4417 if not isinstance(self._curr_model,loop_base_objects.LoopModel): 4418 raise self.InvalidCmd(\ 4419 "The current model does not allow for loop computations.") 4420 else: 4421 for pert_order in perturbation_couplings_list: 4422 if pert_order not in self._curr_model['perturbation_couplings']: 4423 raise self.InvalidCmd(\ 4424 "Perturbation order %s is not among" % pert_order + \ 4425 " the perturbation orders allowed for by the loop model.") 4426 if not self.options['loop_optimized_output'] and \ 4427 LoopOption not in ['tree','real'] and split_orders!=[]: 4428 logger.warning('The default output mode (loop_optimized_output'+\ 4429 ' = False) does not support evaluations for given powers of'+\ 4430 ' coupling orders. MadLoop output will therefore not be'+\ 4431 ' able to provide such quantities.') 4432 split_orders = [] 4433 4434 # Now extract restrictions 4435 forbidden_particle_ids = \ 4436 self.extract_particle_ids(forbidden_particles) 4437 if forbidden_particle_ids and \ 4438 isinstance(forbidden_particle_ids[0], list): 4439 raise self.InvalidCmd(\ 4440 "Multiparticle %s is or-multiparticle" % part_name + \ 4441 " which can be used only for required s-channels") 4442 forbidden_onsh_schannel_ids = \ 4443 self.extract_particle_ids(forbidden_onsh_schannels) 4444 forbidden_schannel_ids = \ 4445 self.extract_particle_ids(forbidden_schannels) 4446 if forbidden_onsh_schannel_ids and \ 4447 isinstance(forbidden_onsh_schannel_ids[0], list): 4448 raise self.InvalidCmd,\ 4449 "Multiparticle %s is or-multiparticle" % part_name + \ 4450 " which can be used only for required s-channels" 4451 if forbidden_schannel_ids and \ 4452 isinstance(forbidden_schannel_ids[0], list): 4453 raise self.InvalidCmd,\ 4454 "Multiparticle %s is or-multiparticle" % part_name + \ 4455 " which can be used only for required s-channels" 4456 required_schannel_ids = \ 4457 self.extract_particle_ids(required_schannels) 4458 if required_schannel_ids and not \ 4459 isinstance(required_schannel_ids[0], list): 4460 required_schannel_ids = [required_schannel_ids] 4461 4462 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()]) 4463 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1: 4464 raise self.InvalidCmd( 4465 "At most one negative squared order constraint can be specified.") 4466 4467 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()]) 4468 4469 4470 out = base_objects.ProcessDefinition({'legs': myleglist, 4471 'model': self._curr_model, 4472 'id': proc_number, 4473 'orders': orders, 4474 'squared_orders':sqorders_values, 4475 'sqorders_types':sqorders_types, 4476 'constrained_orders': constrained_orders, 4477 'forbidden_particles': forbidden_particle_ids, 4478 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids, 4479 'forbidden_s_channels': forbidden_schannel_ids, 4480 'required_s_channels': required_schannel_ids, 4481 'overall_orders': overall_orders, 4482 'perturbation_couplings': perturbation_couplings_list, 4483 'has_born':HasBorn, 4484 'NLO_mode':LoopOption, 4485 'split_orders':split_orders 4486 }) 4487 return out
4488 # 'is_decay_chain': decay_process\ 4489 4490
4491 - def create_loop_induced(self, line, myprocdef=None):
4492 """ Routine to create the MultiProcess for the loop-induced case""" 4493 4494 args = self.split_arg(line) 4495 4496 warning_duplicate = True 4497 if '--no_warning=duplicate' in args: 4498 warning_duplicate = False 4499 args.remove('--no_warning=duplicate') 4500 4501 # Check the validity of the arguments 4502 self.check_add(args) 4503 if args[0] == 'process': 4504 args = args[1:] 4505 4506 # special option for 1->N to avoid generation of kinematically forbidden 4507 #decay. 4508 if args[-1].startswith('--optimize'): 4509 optimize = True 4510 args.pop() 4511 else: 4512 optimize = False 4513 4514 4515 if not myprocdef: 4516 myprocdef = self.extract_process(' '.join(args)) 4517 4518 myprocdef.set('NLO_mode', 'noborn') 4519 4520 # store the first process (for the perl script) 4521 if not self._generate_info: 4522 self._generate_info = line 4523 4524 # Reset Helas matrix elements 4525 #self._curr_matrix_elements = helas_objects.HelasLoopInducedMultiProcess() 4526 4527 4528 # Check that we have the same number of initial states as 4529 # existing processes 4530 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 4531 myprocdef.get_ninitial(): 4532 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 4533 4534 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \ 4535 self._curr_amps[0]['has_born']): 4536 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process") 4537 4538 # Negative coupling order contraints can be given on at most one 4539 # coupling order (and either in squared orders or orders, not both) 4540 if len([1 for val in myprocdef.get('orders').values()+\ 4541 myprocdef.get('squared_orders').values() if val<0])>1: 4542 raise MadGraph5Error("Negative coupling order constraints"+\ 4543 " can only be given on one type of coupling and either on"+\ 4544 " squared orders or amplitude orders, not both.") 4545 4546 cpu_time1 = time.time() 4547 4548 # Generate processes 4549 if self.options['group_subprocesses'] == 'Auto': 4550 collect_mirror_procs = True 4551 else: 4552 collect_mirror_procs = self.options['group_subprocesses'] 4553 ignore_six_quark_processes = \ 4554 self.options['ignore_six_quark_processes'] if \ 4555 "ignore_six_quark_processes" in self.options \ 4556 else [] 4557 4558 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 4559 4560 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef, 4561 collect_mirror_procs = collect_mirror_procs, 4562 ignore_six_quark_processes = ignore_six_quark_processes, 4563 optimize=optimize) 4564 4565 for amp in myproc.get('amplitudes'): 4566 if amp not in self._curr_amps: 4567 self._curr_amps.append(amp) 4568 if amp['has_born']: 4569 raise Exception 4570 elif warning_duplicate: 4571 raise self.InvalidCmd, "Duplicate process %s found. Please check your processes." % \ 4572 amp.nice_string_processes() 4573 4574 # Reset _done_export, since we have new process 4575 self._done_export = False 4576 4577 cpu_time2 = time.time() 4578 4579 nprocs = len(myproc.get('amplitudes')) 4580 ndiags = sum([amp.get_number_of_diagrams() for \ 4581 amp in myproc.get('amplitudes')]) 4582 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 4583 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 4584 ndiags = sum([amp.get_number_of_diagrams() for \ 4585 amp in self._curr_amps]) 4586 logger.info("Total: %i processes with %i diagrams" % \ 4587 (len(self._curr_amps), ndiags))
4588 4589 @staticmethod
4590 - def split_process_line(procline):
4591 """Takes a valid process and return 4592 a tuple (core_process, options). This removes 4593 - any NLO specifications. 4594 - any options 4595 [Used by MadSpin] 4596 """ 4597 4598 # remove the tag "[*]": this tag is used in aMC@LNO , 4599 # but it is not a valid syntax for LO 4600 line=procline 4601 pos1=line.find("[") 4602 if pos1>0: 4603 pos2=line.find("]") 4604 if pos2 >pos1: 4605 line=line[:pos1]+line[pos2+1:] 4606 # 4607 # Extract the options: 4608 # 4609 # A. Remove process number (identified by "@") 4610 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4611 proc_number_re = proc_number_pattern.match(line) 4612 if proc_number_re: 4613 line = proc_number_re.group(1) + proc_number_re.group(3) 4614 4615 # B. search for the beginning of the option string 4616 pos=1000 4617 # start with order 4618 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$") 4619 order_re = order_pattern.match(line) 4620 if (order_re): 4621 pos_order=line.find(order_re.group(2)) 4622 if pos_order>0 and pos_order < pos : pos=pos_order 4623 4624 # then look for slash or dollar 4625 slash = line.find("/") 4626 if slash > 0 and slash < pos: pos=slash 4627 dollar = line.find("$") 4628 if dollar > 0 and dollar < pos: pos=dollar 4629 4630 if pos<1000: 4631 proc_option=line[pos:] 4632 line=line[:pos] 4633 else: 4634 proc_option="" 4635 4636 return line, proc_option
4637
4638 - def get_final_part(self, procline):
4639 """Takes a valid process and return 4640 a set of id of final states particles. [Used by MadSpin] 4641 """ 4642 4643 if not self._curr_model['case_sensitive']: 4644 procline = procline.lower() 4645 pids = self._curr_model.get('name2pdg') 4646 4647 # method. 4648 # 1) look for decay. 4649 # in presence of decay call this routine recursively and veto 4650 # the particles which are decayed 4651 4652 # Deal with decay chain 4653 if ',' in procline: 4654 core, decay = procline.split(',', 1) 4655 core_final = self.get_final_part(core) 4656 4657 #split the decay 4658 all_decays = decay.split(',') 4659 nb_level, tmp_decay = 0, '' 4660 decays = [] 4661 # deal with () 4662 for one_decay in all_decays: 4663 if '(' in one_decay: 4664 nb_level += 1 4665 if ')' in one_decay: 4666 nb_level -= 1 4667 4668 if nb_level: 4669 if tmp_decay: 4670 tmp_decay += ', %s' % one_decay 4671 else: 4672 tmp_decay = one_decay 4673 elif tmp_decay: 4674 final = '%s,%s' % (tmp_decay, one_decay) 4675 final = final.strip() 4676 assert final[0] == '(' and final[-1] == ')' 4677 final = final[1:-1] 4678 decays.append(final) 4679 tmp_decay = '' 4680 else: 4681 decays.append(one_decay) 4682 # remove from the final states all particles which are decayed 4683 for one_decay in decays: 4684 first = one_decay.split('>',1)[0].strip() 4685 if first in pids: 4686 pid = set([pids[first]]) 4687 elif first in self._multiparticles: 4688 pid = set(self._multiparticles[first]) 4689 else: 4690 raise Exception, 'invalid particle name: %s. ' % first 4691 core_final.difference_update(pid) 4692 core_final.update(self.get_final_part(one_decay)) 4693 4694 return core_final 4695 4696 # NO DECAY CHAIN 4697 final = set() 4698 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline) 4699 particles = final_states.groups()[0] 4700 for particle in particles.split(): 4701 if particle in pids: 4702 final.add(pids[particle]) 4703 elif particle in self._multiparticles: 4704 final.update(set(self._multiparticles[particle])) 4705 return final
4706
4707 - def extract_particle_ids(self, args):
4708 """Extract particle ids from a list of particle names. If 4709 there are | in the list, this corresponds to an or-list, which 4710 is represented as a list of id lists. An or-list is used to 4711 allow multiple required s-channel propagators to be specified 4712 (e.g. Z/gamma).""" 4713 4714 if isinstance(args, basestring): 4715 args.replace("|", " | ") 4716 args = self.split_arg(args) 4717 all_ids = [] 4718 ids=[] 4719 for part_name in args: 4720 mypart = self._curr_model['particles'].get_copy(part_name) 4721 if mypart: 4722 ids.append([mypart.get_pdg_code()]) 4723 elif part_name in self._multiparticles: 4724 ids.append(self._multiparticles[part_name]) 4725 elif part_name == "|": 4726 # This is an "or-multiparticle" 4727 if ids: 4728 all_ids.append(ids) 4729 ids = [] 4730 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()): 4731 ids.append([int(part_name)]) 4732 else: 4733 raise self.InvalidCmd("No particle %s in model" % part_name) 4734 all_ids.append(ids) 4735 # Flatten id list, to take care of multiparticles and 4736 # or-multiparticles 4737 res_lists = [] 4738 for i, id_list in enumerate(all_ids): 4739 res_lists.extend(diagram_generation.expand_list_list(id_list)) 4740 # Trick to avoid duplication while keeping ordering 4741 for ilist, idlist in enumerate(res_lists): 4742 set_dict = {} 4743 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \ 4744 if i not in set_dict] 4745 4746 if len(res_lists) == 1: 4747 res_lists = res_lists[0] 4748 4749 return res_lists
4750
4751 - def optimize_order(self, pdg_list):
4752 """Optimize the order of particles in a pdg list, so that 4753 similar particles are next to each other. Sort according to: 4754 1. pdg > 0, 2. spin, 3. color, 4. mass > 0""" 4755 4756 if not pdg_list: 4757 return 4758 if not isinstance(pdg_list[0], int): 4759 return 4760 4761 model = self._curr_model 4762 pdg_list.sort(key = lambda i: i < 0) 4763 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion()) 4764 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'), 4765 reverse = True) 4766 pdg_list.sort(key = lambda i: \ 4767 model.get_particle(i).get('mass').lower() != 'zero')
4768
4769 - def extract_decay_chain_process(self, line, level_down=False, proc_number=0):
4770 """Recursively extract a decay chain process definition from a 4771 string. Returns a ProcessDefinition.""" 4772 4773 # Start with process number (identified by "@") and overall orders 4774 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*=\s*\d+\s*)*)$") 4775 proc_number_re = proc_number_pattern.match(line) 4776 overall_orders = {} 4777 if proc_number_re: 4778 proc_number = int(proc_number_re.group(2)) 4779 line = proc_number_re.group(1) 4780 if proc_number_re.group(3): 4781 order_pattern = re.compile("^(.*?)\s*(\w+)\s*=\s*(\d+)\s*$") 4782 order_line = proc_number_re.group(3) 4783 order_re = order_pattern.match(order_line) 4784 while order_re: 4785 overall_orders[order_re.group(2)] = int(order_re.group(3)) 4786 order_line = order_re.group(1) 4787 order_re = order_pattern.match(order_line) 4788 logger.info(line) 4789 4790 4791 index_comma = line.find(",") 4792 index_par = line.find(")") 4793 min_index = index_comma 4794 if index_par > -1 and (index_par < min_index or min_index == -1): 4795 min_index = index_par 4796 4797 if min_index > -1: 4798 core_process = self.extract_process(line[:min_index], proc_number, 4799 overall_orders) 4800 else: 4801 core_process = self.extract_process(line, proc_number, 4802 overall_orders) 4803 4804 #level_down = False 4805 4806 while index_comma > -1: 4807 line = line[index_comma + 1:] 4808 if not line.strip(): 4809 break 4810 index_par = line.find(')') 4811 # special cases: parenthesis but no , => remove the paranthesis! 4812 if line.lstrip()[0] == '(' and index_par !=-1 and \ 4813 not ',' in line[:index_par]: 4814 par_start = line.find('(') 4815 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:]) 4816 index_par = line.find(')') 4817 if line.lstrip()[0] == '(': 4818 # Go down one level in process hierarchy 4819 #level_down = True 4820 line = line.lstrip()[1:] 4821 # This is where recursion happens 4822 decay_process, line = \ 4823 self.extract_decay_chain_process(line, 4824 level_down=True) 4825 index_comma = line.find(",") 4826 index_par = line.find(')') 4827 else: 4828 index_comma = line.find(",") 4829 min_index = index_comma 4830 if index_par > -1 and \ 4831 (index_par < min_index or min_index == -1): 4832 min_index = index_par 4833 if min_index > -1: 4834 decay_process = self.extract_process(line[:min_index]) 4835 else: 4836 decay_process = self.extract_process(line) 4837 4838 core_process.get('decay_chains').append(decay_process) 4839 4840 if level_down: 4841 if index_par == -1: 4842 raise self.InvalidCmd, \ 4843 "Missing ending parenthesis for decay process" 4844 4845 if index_par < index_comma: 4846 line = line[index_par + 1:] 4847 level_down = False 4848 break 4849 4850 if level_down: 4851 index_par = line.find(')') 4852 if index_par == -1: 4853 raise self.InvalidCmd, \ 4854 "Missing ending parenthesis for decay process" 4855 line = line[index_par + 1:] 4856 4857 # Return the core process (ends recursion when there are no 4858 # more decays) 4859 return core_process, line
4860 4861 4862 # Import files
4863 - def do_import(self, line, force=False):
4864 """Main commands: Import files with external formats""" 4865 4866 args = self.split_arg(line) 4867 # Check argument's validity 4868 self.check_import(args) 4869 if args[0].startswith('model'): 4870 self._model_v4_path = None 4871 # Reset amplitudes and matrix elements 4872 self._curr_amps = diagram_generation.AmplitudeList() 4873 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4874 # Import model 4875 if args[0].endswith('_v4'): 4876 self._curr_model, self._model_v4_path = \ 4877 import_v4.import_model(args[1], self._mgme_dir) 4878 self._curr_fortran_model = \ 4879 helas_call_writers.FortranHelasCallWriter(\ 4880 self._curr_model) 4881 else: 4882 # avoid loading the qcd/qed model twice 4883 if (args[1].startswith('loop_qcd_qed_sm') or\ 4884 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\ 4885 self.options['gauge']!='Feynman': 4886 logger.info('Switching to Feynman gauge because '+\ 4887 'it is the only one supported by the model %s.'%args[1]) 4888 self._curr_model = None 4889 self.do_set('gauge Feynman',log=False) 4890 prefix = not '--noprefix' in args 4891 if prefix: 4892 aloha.aloha_prefix='mdl_' 4893 else: 4894 aloha.aloha_prefix='' 4895 4896 try: 4897 self._curr_model = import_ufo.import_model(args[1], prefix=prefix, 4898 complex_mass_scheme=self.options['complex_mass_scheme']) 4899 except import_ufo.UFOImportError, error: 4900 if 'not a valid UFO model' in str(error): 4901 logger_stderr.warning('WARNING: %s' % error) 4902 logger_stderr.warning('Try to recover by running '+\ 4903 'automatically `import model_v4 %s` instead.'% args[1]) 4904 self.exec_cmd('import model_v4 %s ' % args[1], precmd=True) 4905 return 4906 if self.options['gauge']=='unitary': 4907 if not force and isinstance(self._curr_model,\ 4908 loop_base_objects.LoopModel) and \ 4909 self._curr_model.get('perturbation_couplings') not in \ 4910 [[],['QCD']]: 4911 if 1 not in self._curr_model.get('gauge') : 4912 logger_stderr.warning('This model does not allow Feynman '+\ 4913 'gauge. You will only be able to do tree level '+\ 4914 'QCD loop cmputations with it.') 4915 else: 4916 logger.info('Change to the gauge to Feynman because '+\ 4917 'this loop model allows for more than just tree level'+\ 4918 ' and QCD perturbations.') 4919 self.do_set('gauge Feynman', log=False) 4920 return 4921 if 0 not in self._curr_model.get('gauge') : 4922 logger_stderr.warning('Change the gauge to Feynman since '+\ 4923 'the model does not allow unitary gauge') 4924 self.do_set('gauge Feynman', log=False) 4925 return 4926 else: 4927 if 1 not in self._curr_model.get('gauge') : 4928 logger_stderr.warning('Change the gauge to unitary since the'+\ 4929 ' model does not allow Feynman gauge.'+\ 4930 ' Please re-import the model') 4931 self._curr_model = None 4932 self.do_set('gauge unitary', log= False) 4933 return 4934 4935 self._curr_fortran_model = \ 4936 helas_call_writers.FortranUFOHelasCallWriter(\ 4937 self._curr_model) 4938 self._curr_cpp_model = \ 4939 helas_call_writers.CPPUFOHelasCallWriter(\ 4940 self._curr_model) 4941 4942 if '-modelname' not in args: 4943 self._curr_model.pass_particles_name_in_mg_default() 4944 4945 # Do post-processing of model 4946 self.process_model() 4947 # Reset amplitudes and matrix elements and global checks 4948 self._curr_amps = diagram_generation.AmplitudeList() 4949 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4950 process_checks.store_aloha = [] 4951 4952 elif args[0] == 'command': 4953 4954 if not os.path.isfile(args[1]): 4955 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1]) 4956 else: 4957 # Check the status of export and try to use file position if no 4958 #self._export dir are define 4959 self.check_for_export_dir(args[1]) 4960 # Execute the card 4961 self.import_command_file(args[1]) 4962 4963 elif args[0] == 'banner': 4964 type = madevent_interface.MadEventCmd.detect_card_type(args[1]) 4965 if type != 'banner': 4966 raise self.InvalidCmd, 'The File should be a valid banner' 4967 ban = banner_module.Banner(args[1]) 4968 # Check that this is MG5 banner 4969 if 'mg5proccard' in ban: 4970 for line in ban['mg5proccard'].split('\n'): 4971 if line.startswith('#') or line.startswith('<'): 4972 continue 4973 self.exec_cmd(line) 4974 else: 4975 raise self.InvalidCmd, 'Only MG5 banner are supported' 4976 4977 if not self._done_export: 4978 self.exec_cmd('output . -f') 4979 4980 ban.split(self._done_export[0]) 4981 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards')) 4982 if '--no_launch' not in args: 4983 self.exec_cmd('launch') 4984 4985 elif args[0] == 'proc_v4': 4986 4987 if len(args) == 1 and self._export_dir: 4988 proc_card = pjoin(self._export_dir, 'Cards', \ 4989 'proc_card.dat') 4990 elif len(args) == 2: 4991 proc_card = args[1] 4992 # Check the status of export and try to use file position is no 4993 # self._export dir are define 4994 self.check_for_export_dir(os.path.realpath(proc_card)) 4995 else: 4996 raise MadGraph5Error('No default directory in output') 4997 4998 4999 #convert and excecute the card 5000 self.import_mg4_proc_card(proc_card)
5001
5002 - def remove_pointless_decay(self, param_card):
5003 """ For simple decay chain: remove diagram that are not in the BR. 5004 param_card should be a ParamCard instance.""" 5005 5006 assert isinstance(param_card, check_param_card.ParamCard) 5007 5008 # Collect amplitudes 5009 amplitudes = diagram_generation.AmplitudeList() 5010 for amp in self._curr_amps: 5011 amplitudes.extend(amp.get_amplitudes()) 5012 5013 decay_tables = param_card['decay'].decay_table 5014 to_remove = [] 5015 for amp in amplitudes: 5016 mother = [l.get('id') for l in amp['process'].get('legs') \ 5017 if not l.get('state')] 5018 if 1 == len(mother): 5019 try: 5020 decay_table = decay_tables[abs(mother[0])] 5021 except KeyError: 5022 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0])) 5023 continue # No BR for this particle -> accept all. 5024 # create the tuple associate to the decay mode 5025 child = [l.get('id') for l in amp['process'].get('legs') \ 5026 if l.get('state')] 5027 if not mother[0] > 0: 5028 child = [x if self._curr_model.get_particle(x)['self_antipart'] 5029 else -x for x in child] 5030 child.sort() 5031 child.insert(0, len(child)) 5032 #check if the decay is present or not: 5033 if tuple(child) not in decay_table.keys(): 5034 to_remove.append(amp) 5035 5036 def remove_amp(amps): 5037 for amp in amps[:]: 5038 if amp in to_remove: 5039 amps.remove(amp) 5040 if isinstance(amp, diagram_generation.DecayChainAmplitude): 5041 remove_amp(amp.get('decay_chains')) 5042 for decay in amp.get('decay_chains'): 5043 remove_amp(decay.get('amplitudes'))
5044 remove_amp(self._curr_amps) 5045 5046
5047 - def import_ufo_model(self, model_name):
5048 """ import the UFO model """ 5049 5050 self._curr_model = import_ufo.import_model(model_name) 5051 self._curr_fortran_model = \ 5052 helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 5053 self._curr_cpp_model = \ 5054 helas_call_writers.CPPUFOHelasCallWriter(self._curr_model)
5055
5056 - def process_model(self):
5057 """Set variables _particle_names and _couplings for tab 5058 completion, define multiparticles""" 5059 5060 # Set variables for autocomplete 5061 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\ 5062 if p.get('propagating')] + \ 5063 [p.get('antiname') for p in self._curr_model.get('particles') \ 5064 if p.get('propagating')] 5065 5066 self._couplings = list(set(sum([i.get('orders').keys() for i in \ 5067 self._curr_model.get('interactions')], []))) 5068 5069 self.add_default_multiparticles()
5070 5071
5072 - def import_mg4_proc_card(self, filepath):
5073 """ read a V4 proc card, convert it and run it in mg5""" 5074 5075 # change the status of this line in the history -> pass in comment 5076 if self.history and self.history[-1].startswith('import proc_v4'): 5077 self.history[-1] = '#%s' % self.history[-1] 5078 5079 # read the proc_card.dat 5080 reader = files.read_from_file(filepath, import_v4.read_proc_card_v4) 5081 if not reader: 5082 raise self.InvalidCmd('\"%s\" is not a valid path' % filepath) 5083 5084 if self._mgme_dir: 5085 # Add comment to history 5086 self.exec_cmd("# Import the model %s" % reader.model, precmd=True) 5087 line = self.exec_cmd('import model_v4 %s -modelname' % \ 5088 (reader.model), precmd=True) 5089 else: 5090 logging.error('No MG_ME installation detected') 5091 return 5092 5093 5094 # Now that we have the model we can split the information 5095 lines = reader.extract_command_lines(self._curr_model) 5096 for line in lines: 5097 self.exec_cmd(line, precmd=True) 5098 5099 return
5100
5101 - def add_default_multiparticles(self):
5102 """ add default particle from file interface.multiparticles_default.txt 5103 """ 5104 5105 defined_multiparticles = self._multiparticles.keys() 5106 removed_multiparticles = [] 5107 # First check if the defined multiparticles are allowed in the 5108 # new model 5109 5110 for key in self._multiparticles.keys(): 5111 try: 5112 for part in self._multiparticles[key]: 5113 self._curr_model.get('particle_dict')[part] 5114 except Exception: 5115 del self._multiparticles[key] 5116 defined_multiparticles.remove(key) 5117 removed_multiparticles.append(key) 5118 5119 # Now add default multiparticles 5120 for line in open(pjoin(MG5DIR, 'input', \ 5121 'multiparticles_default.txt')): 5122 if line.startswith('#'): 5123 continue 5124 try: 5125 if not self._curr_model['case_sensitive']: 5126 multipart_name = line.lower().split()[0] 5127 else: 5128 multipart_name = line.split()[0] 5129 if multipart_name not in self._multiparticles: 5130 #self.do_define(line) 5131 self.exec_cmd('define %s' % line, printcmd=False, precmd=True) 5132 except self.InvalidCmd, why: 5133 logger_stderr.warning('impossible to set default multiparticles %s because %s' % 5134 (line.split()[0],why)) 5135 if self.history[-1] == 'define %s' % line.strip(): 5136 self.history.pop(-1) 5137 else: 5138 misc.sprint([self.history[-1], 'define %s' % line.strip()]) 5139 5140 scheme = "old" 5141 for qcd_container in ['p', 'j']: 5142 if qcd_container not in self._multiparticles: 5143 continue 5144 multi = self._multiparticles[qcd_container] 5145 b = self._curr_model.get_particle(5) 5146 if not b: 5147 break 5148 5149 if 5 in multi: 5150 if b['mass'] != 'ZERO': 5151 multi.remove(5) 5152 multi.remove(-5) 5153 scheme = 4 5154 elif b['mass'] == 'ZERO': 5155 multi.append(5) 5156 multi.append(-5) 5157 scheme = 5 5158 5159 if scheme in [4,5]: 5160 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme) 5161 for container in ['p', 'j']: 5162 if container in defined_multiparticles: 5163 defined_multiparticles.remove(container) 5164 self.history.append("define p = %s # pass to %s flavors" % \ 5165 (' ' .join([`i` for i in self._multiparticles['p']]), 5166 scheme) 5167 ) 5168 self.history.append("define j = p") 5169 5170 5171 if defined_multiparticles: 5172 if 'all' in defined_multiparticles: 5173 defined_multiparticles.remove('all') 5174 logger.info("Kept definitions of multiparticles %s unchanged" % \ 5175 " / ".join(defined_multiparticles)) 5176 5177 for removed_part in removed_multiparticles: 5178 if removed_part in self._multiparticles: 5179 removed_multiparticles.remove(removed_part) 5180 5181 if removed_multiparticles: 5182 logger.info("Removed obsolete multiparticles %s" % \ 5183 " / ".join(removed_multiparticles)) 5184 5185 # add all tag 5186 line = [] 5187 for part in self._curr_model.get('particles'): 5188 line.append('%s %s' % (part.get('name'), part.get('antiname'))) 5189 line = 'all =' + ' '.join(line) 5190 self.do_define(line)
5191
5192 - def advanced_install(self, tool_to_install, 5193 HepToolsInstaller_web_address=None, 5194 additional_options=[]):
5195 """ Uses the HEPToolsInstaller.py script maintened online to install 5196 HEP tools with more complicated dependences. 5197 Additional options will be added to the list when calling HEPInstaller""" 5198 5199 # Always refresh the installer if already present 5200 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')): 5201 if HepToolsInstaller_web_address is None: 5202 raise MadGraph5Error, "The option 'HepToolsInstaller_web_address'"+\ 5203 " must be specified in function advanced_install"+\ 5204 " if the installers are not already downloaded." 5205 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')): 5206 os.mkdir(pjoin(MG5DIR,'HEPTools')) 5207 elif not HepToolsInstaller_web_address is None: 5208 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5209 if not HepToolsInstaller_web_address is None: 5210 logger.info('Downloading the HEPToolInstaller at:\n %s'% 5211 HepToolsInstaller_web_address) 5212 # Guess if it is a local or web address 5213 if '//' in HepToolsInstaller_web_address: 5214 if sys.platform == "darwin": 5215 misc.call(['curl', HepToolsInstaller_web_address, '-o%s' 5216 %pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')], 5217 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'), 5218 cwd=MG5DIR) 5219 else: 5220 misc.call(['wget', HepToolsInstaller_web_address, 5221 '--output-document=%s'% pjoin(MG5DIR,'HEPTools', 5222 'HEPToolsInstallers.tar.gz')], stderr=open(os.devnull, 'w'), 5223 stdout=open(os.devnull, 'w'), cwd=MG5DIR) 5224 else: 5225 # If it is a local tarball, then just copy it 5226 shutil.copyfile(HepToolsInstaller_web_address, 5227 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5228 5229 # Untar the file 5230 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'], 5231 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w')) 5232 5233 # Remove the tarball 5234 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5235 5236 ############## FOR DEBUGGING ONLY, Take HEPToolsInstaller locally ############## 5237 # shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5238 # shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir, 5239 # 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5240 ################################################################################ 5241 5242 # Potential change in naming convention 5243 name_map = {} 5244 try: 5245 tool = name_map[tool_to_install] 5246 except: 5247 tool = tool_to_install 5248 5249 # Compiler options 5250 compiler_options = [] 5251 if not self.options['cpp_compiler'] is None: 5252 compiler_options.append('--cpp_compiler=%s'% 5253 self.options['cpp_compiler']) 5254 compiler_options.append('--cpp_standard_lib=%s'% 5255 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler'])) 5256 else: 5257 compiler_options.append('--cpp_standard_lib=%s'% 5258 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler'])) 5259 5260 if not self.options['fortran_compiler'] is None: 5261 compiler_options.append('--fortran_compiler=%s'% 5262 self.options['fortran_compiler']) 5263 5264 # Add the path of pythia8 if known and the MG5 path 5265 if tool=='mg5amc_py8_interface': 5266 additional_options.append('--mg5_path=%s'%MG5DIR) 5267 # Warn about the soft dependency to gnuplot 5268 if misc.which('gnuplot') is None: 5269 logger.warning("==========") 5270 logger.warning("The optional dependency 'gnuplot' for the tool"+\ 5271 " 'mg5amc_py8_interface' was not found. We recommend that you"+\ 5272 " install it so as to be able to view the plots related to "+\ 5273 " merging with Pythia 8.") 5274 logger.warning("==========") 5275 if self.options['pythia8_path']: 5276 additional_options.append( 5277 '--with_pythia8=%s'%self.options['pythia8_path']) 5278 5279 ##### FOR DEBUGGING ONLY, until the mg5amc_py8_interface is put online ######## 5280 # additional_options.append('--mg5amc_py8_interface_tarball=%s'% 5281 # pjoin(MG5DIR,os.path.pardir,'MG5aMC_PY8_interface', 5282 # 'MG5aMC_PY8_interface.tar.gz')) 5283 ################################################################################ 5284 5285 # Special rules for certain tools 5286 if tool=='pythia8': 5287 # All what's below is to handle the lhapdf dependency of Pythia8 5288 lhapdf_config = misc.which(self.options['lhapdf']) 5289 lhapdf_version = None 5290 if lhapdf_config is None: 5291 lhapdf_version = None 5292 else: 5293 try: 5294 version = misc.Popen( 5295 [lhapdf_config,'--version'], stdout=subprocess.PIPE) 5296 lhapdf_version = int(version.stdout.read()[0]) 5297 if lhapdf_version not in [5,6]: 5298 raise 5299 except: 5300 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+ 5301 " sure '%s --version ' runs properly."%lhapdf_config) 5302 5303 if lhapdf_version is None: 5304 answer = self.ask(question= 5305 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+ 5306 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >", 5307 default='y',text_format='33;32') 5308 if not answer.lower() in ['y','']: 5309 lhapdf_path = None 5310 else: 5311 self.advanced_install('lhapdf6', 5312 additional_options=additional_options) 5313 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6') 5314 lhapdf_version = 6 5315 else: 5316 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\ 5317 lhapdf_config),os.path.pardir)) 5318 if lhapdf_version is None: 5319 logger.warning('You decided not to link the Pythia8 installation'+ 5320 ' to LHAPDF. Beware that only built-in PDF sets can be used then.') 5321 else: 5322 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version) 5323 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN') 5324 lhapdf_option = [] 5325 if lhapdf_version is None: 5326 lhapdf_option.append('--with_lhapdf6=OFF') 5327 lhapdf_option.append('--with_lhapdf5=OFF') 5328 elif lhapdf_version==5: 5329 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path) 5330 lhapdf_option.append('--with_lhapdf6=OFF') 5331 elif lhapdf_version==6: 5332 lhapdf_option.append('--with_lhapdf5=OFF') 5333 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path) 5334 # Make sure each otion in additional_options appears only once 5335 additional_options = list(set(additional_options)) 5336 # And that the option '--force' is placed last. 5337 additional_options = [opt for opt in additional_options if opt!='--force']+\ 5338 (['--force'] if '--force' in additional_options else []) 5339 return_code = misc.call([pjoin(MG5DIR,'HEPTools', 5340 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8', 5341 '--prefix=%s'%pjoin(MG5DIR,'HEPTools')] 5342 + lhapdf_option + compiler_options + additional_options) 5343 else: 5344 logger.info('Now installing %s. Be patient...'%tool) 5345 # Make sure each otion in additional_options appears only once 5346 additional_options = list(set(additional_options)) 5347 # And that the option '--force' is placed last. 5348 additional_options = [opt for opt in additional_options if opt!='--force']+\ 5349 (['--force'] if '--force' in additional_options else []) 5350 return_code = misc.call([pjoin(MG5DIR,'HEPTools', 5351 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'% 5352 pjoin(MG5DIR,'HEPTools')] + compiler_options + additional_options) 5353 5354 if return_code == 0: 5355 logger.info("%s successfully installed in %s."%( 5356 tool_to_install, pjoin(MG5DIR,'HEPTools')),'$MG:color:GREEN') 5357 elif return_code == 66: 5358 answer = self.ask(question= 5359 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, pjoin(MG5DIR,'HEPTools'))+ 5360 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >""" 5361 ,default='y',text_format='33;32') 5362 if not answer.lower() in ['y','']: 5363 logger.info("Installation of %s aborted."%tool_to_install, 5364 '$MG:color:GREEN') 5365 return 5366 else: 5367 return self.advanced_install(tool_to_install, 5368 additional_options=additional_options+['--force']) 5369 else: 5370 raise self.InvalidCmd("Installation of %s failed."%tool_to_install) 5371 5372 # Post-installation treatment 5373 if tool == 'pythia8': 5374 self.options['pythia8_path'] = pjoin(MG5DIR,'HEPTools','pythia8') 5375 self.exec_cmd('save options') 5376 # Automatically re-install the mg5amc_py8_interface after a fresh 5377 # Pythia8 installation 5378 self.advanced_install('mg5amc_py8_interface', 5379 additional_options=additional_options+['--force']) 5380 elif tool == 'lhapdf6': 5381 self.options['lhapdf'] = pjoin(MG5DIR,'HEPTools','lhapdf6','bin', 5382 'lhapdf-config') 5383 self.exec_cmd('save options') 5384 elif tool == 'lhapdf5': 5385 self.options['lhapdf'] = pjoin(MG5DIR,'HEPTools','lhapdf5','bin', 5386 'lhapdf-config') 5387 self.exec_cmd('save options') 5388 5389 elif tool == 'mg5amc_py8_interface': 5390 self.options['mg5amc_py8_interface_path'] = \ 5391 pjoin(MG5DIR,'HEPTools','MG5aMC_PY8_interface') 5392 self.exec_cmd('save options') 5393 5394 elif tool == 'ninja': 5395 if not misc.get_ninja_quad_prec_support(pjoin( 5396 MG5DIR,'HEPTools','ninja','lib')): 5397 logger.warning( 5398 """Successful installation of Ninja, but without support for quadruple precision 5399 arithmetics. If you want to enable this (hence improving the treatment of numerically 5400 unstable points in the loop matrix elements) you can try to reinstall Ninja with: 5401 MG5aMC>install ninja 5402 After having made sure to have selected a C++ compiler in the 'cpp' option of 5403 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""") 5404 self.options['ninja'] = pjoin(os.curdir,'HEPTools','lib') 5405 self.exec_cmd('save options') 5406 5407 # Now warn the user if he didn't add HEPTools first in his environment 5408 # variables. 5409 path_to_be_set = [] 5410 if sys.platform == "darwin": 5411 library_variables = ["DYLD_LIBRARY_PATH"] 5412 else: 5413 library_variables = ["LD_LIBRARY_PATH"] 5414 for variable in library_variables: 5415 if (variable not in os.environ) or \ 5416 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\ 5417 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 5418 path_to_be_set.append((variable, 5419 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib')))) 5420 for variable in ["PATH"]: 5421 if (variable not in os.environ) or \ 5422 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\ 5423 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 5424 path_to_be_set.append((variable, 5425 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin')))) 5426 if (variable not in os.environ) or \ 5427 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\ 5428 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 5429 path_to_be_set.append((variable, 5430 os.path.abspath(pjoin(MG5DIR,'HEPTools','include')))) 5431 5432 if len(path_to_be_set)>0: 5433 shell_type = misc.get_shell_type() 5434 if shell_type in ['bash',None]: 5435 modification_line = r"printf '# MG5aMC paths:\n%s' >> ~/.bashrc"%\ 5436 (r'\n'.join('export %s=%s%s'% 5437 (var,path,'%s$%s'%(os.pathsep,var) if var in os.environ else '') 5438 for var,path in path_to_be_set)) 5439 elif shell_type=='tcsh': 5440 modification_line = r"printf '# MG5aMC paths:\n%s' >> ~/.cshrc"%\ 5441 (r'\n'.join('setenv %s %s%s'% 5442 (var,path,'%s$%s'%(os.pathsep,var) if var in os.environ else '') 5443 for var,path in path_to_be_set)) 5444 5445 logger.warning("==========") 5446 logger.warning("We recommend that you add to the following paths"+\ 5447 " to your environment variables, so that you are guaranteed that"+\ 5448 " at runtime, MG5_aMC will use the tools you have just installed"+\ 5449 " and not some other versions installed elsewhere on your system.\n"+\ 5450 "You can do so by running the following command in your terminal:" 5451 "\n %s"%modification_line) 5452 logger.warning("==========") 5453 5454 # Return true for successful installation 5455 return True
5456
5457 - def do_install(self, line, paths=None, additional_options=[]):
5458 """Install optional package from the MG suite. 5459 The argument 'additional_options' will be passed to the advanced_install 5460 functions. If it contains the option '--force', then the advanced_install 5461 function will overwrite any existing installation of the tool without 5462 warnings. 5463 """ 5464 5465 args = self.split_arg(line) 5466 #check the validity of the arguments 5467 self.check_install(args) 5468 5469 if sys.platform == "darwin": 5470 program = "curl" 5471 else: 5472 program = "wget" 5473 5474 # special command for auto-update 5475 if args[0] == 'update': 5476 self.install_update(args, wget=program) 5477 return 5478 5479 advertisements = {'pythia-pgs':['arXiv:0603175'], 5480 'Delphes':['arXiv:1307.6346'], 5481 'Delphes2':['arXiv:0903.2225'], 5482 'SysCalc':['arXiv:XXXX.YYYYY'], 5483 'Golem95':['arXiv:0807.0605'], 5484 'PJFry':['arXiv:1210.4095','arXiv:1112.0500'], 5485 'QCDLoop':['arXiv:0712.1851'], 5486 'pythia8':['arXiv:1410.3012'], 5487 'lhapdf6':['arXiv:1412.7420'], 5488 'lhapdf5':['arXiv:0605240'], 5489 'hepmc':['CPC 134 (2001) 41-46'], 5490 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'], 5491 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'], 5492 'oneloop':['arXiv:1007.4716']} 5493 5494 if args[0] in advertisements: 5495 logger.info("------------------------------------------------------", '$MG:color:GREEN') 5496 logger.info(" You are installing '%s', please cite ref(s): "%args[0], '$MG:color:BLACK') 5497 for ad in advertisements[args[0]]: 5498 logger.info(" %s"%ad, '$MG:color:GREEN') 5499 logger.info(" on top of the recommended MG5_aMC citations", '$MG:color:BLACK') 5500 logger.info(" when using results produced with this tool.", '$MG:color:BLACK') 5501 logger.info("------------------------------------------------------", '$MG:color:GREEN') 5502 5503 5504 # Load file with path of the different program: 5505 import urllib 5506 if paths: 5507 path = paths 5508 else: 5509 path = {} 5510 5511 data_path = ['http://madgraph.phys.ucl.ac.be/package_info.dat', 5512 'http://madgraph.hep.uiuc.edu/package_info.dat'] 5513 r = random.randint(0,1) 5514 r = [r, (1-r)] 5515 ################################################################################ 5516 # Force her to choose one particular server 5517 # r = [0] 5518 ################################################################################ 5519 5520 for index in r: 5521 cluster_path = data_path[index] 5522 try: 5523 data = urllib.urlopen(cluster_path) 5524 except Exception: 5525 continue 5526 break 5527 else: 5528 raise MadGraph5Error, '''Impossible to connect any of us servers. 5529 Please check your internet connection or retry later''' 5530 5531 for line in data: 5532 split = line.split() 5533 path[split[0]] = split[1] 5534 5535 ################################################################################ 5536 # TEMPORARY HACK WHERE WE ADD ENTRIES TO WHAT WILL BE EVENTUALLY ON THE WEB 5537 ################################################################################ 5538 # path['XXX'] = 'YYY' 5539 ################################################################################ 5540 5541 if args[0] in self._advanced_install_opts: 5542 # Now launch the advanced installation of the tool args[0] 5543 # path['HEPToolsInstaller'] is the online adress where to downlaod 5544 # the installers if necessary. 5545 # Specify the path of the MG5_aMC_interface 5546 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \ 5547 'MG5aMC_PY8_interface' in path else 'NA' 5548 additional_options.append('--mg5amc_py8_interface_tarball=%s'%\ 5549 MG5aMC_PY8_interface_path) 5550 return self.advanced_install(args[0], path['HEPToolsInstaller'], 5551 additional_options = additional_options) 5552 5553 if args[0] == 'PJFry' and not os.path.exists( 5554 pjoin(MG5DIR,'QCDLoop','lib','libqcdloop1.a')): 5555 logger.info("Installing PJFRY's dependence QCDLoop...") 5556 self.do_install('QCDLoop', paths=path) 5557 5558 if args[0] == 'Delphes': 5559 args[0] = 'Delphes3' 5560 5561 try: 5562 name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes', 5563 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs', 5564 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'MadAnalysis', 5565 'SysCalc':'SysCalc', 'Golem95': 'golem95', 5566 'PJFry':'PJFry','QCDLoop':'QCDLoop', 5567 } 5568 name = name[args[0]] 5569 except: 5570 pass 5571 5572 #check outdated install 5573 if args[0] in ['Delphes2', 'pythia-pgs']: 5574 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\ 5575 " You should consider using an up-to-date version of the code.") 5576 5577 try: 5578 os.system('rm -rf %s' % pjoin(MG5DIR, name)) 5579 except Exception: 5580 pass 5581 5582 # Load that path 5583 logger.info('Downloading %s' % path[args[0]]) 5584 if sys.platform == "darwin": 5585 misc.call(['curl', path[args[0]], '-o%s.tgz' % name], cwd=MG5DIR) 5586 else: 5587 misc.call(['wget', path[args[0]], '--output-document=%s.tgz'% name], cwd=MG5DIR) 5588 5589 # Untar the file 5590 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 5591 stdout=open(os.devnull, 'w')) 5592 5593 if returncode: 5594 raise MadGraph5Error, 'Fail to download correctly the File. Stop' 5595 5596 5597 # Check that the directory has the correct name 5598 if not os.path.exists(pjoin(MG5DIR, name)): 5599 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith( 5600 name.lower()) and not n.endswith('gz')] 5601 if not created_name: 5602 raise MadGraph5Error, 'The file was not loaded correctly. Stop' 5603 else: 5604 created_name = created_name[0] 5605 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name)) 5606 5607 5608 logger.info('compile %s. This might take a while.' % name) 5609 5610 # Modify Makefile for pythia-pgs on Mac 64 bit 5611 if args[0] == "pythia-pgs" and sys.maxsize > 2**32: 5612 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 5613 text = open(path).read() 5614 text = text.replace('MBITS=32','MBITS=64') 5615 open(path, 'w').writelines(text) 5616 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')): 5617 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')) 5618 5619 make_flags = [] #flags for the compilation 5620 # Compile the file 5621 # Check for F77 compiler 5622 if 'FC' not in os.environ or not os.environ['FC']: 5623 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None': 5624 compiler = self.options['fortran_compiler'] 5625 elif misc.which('gfortran'): 5626 compiler = 'gfortran' 5627 elif misc.which('g77'): 5628 compiler = 'g77' 5629 else: 5630 raise self.InvalidCmd('Require g77 or Gfortran compiler') 5631 5632 path = None 5633 base_compiler= ['FC=g77','FC=gfortran'] 5634 if args[0] == "pythia-pgs": 5635 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 5636 elif args[0] == 'MadAnalysis': 5637 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile') 5638 if path: 5639 text = open(path).read() 5640 for base in base_compiler: 5641 text = text.replace(base,'FC=%s' % compiler) 5642 open(path, 'w').writelines(text) 5643 os.environ['FC'] = compiler 5644 5645 # For Golem95, use autotools. 5646 if name == 'golem95': 5647 # Run the configure script 5648 ld_path = misc.Popen(['./configure', 5649 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']], 5650 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0] 5651 5652 # For PJFry, use autotools. 5653 if name == 'PJFry': 5654 # Run the configure script 5655 ld_path = misc.Popen(['./configure', 5656 '--prefix=%s'%str(pjoin(MG5DIR, name)), 5657 '--enable-golem-mode', '--with-integrals=qcdloop1', 5658 'LDFLAGS=-L%s'%str(pjoin(MG5DIR,'QCDLoop','lib')), 5659 'FC=%s'%os.environ['FC'], 5660 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 5661 stdout=subprocess.PIPE).communicate()[0] 5662 5663 # For QCDLoop, use autotools. 5664 if name == 'QCDLoop': 5665 # Run the configure script 5666 ld_path = misc.Popen(['./configure', 5667 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'], 5668 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 5669 stdout=subprocess.PIPE).communicate()[0] 5670 5671 # For Delphes edit the makefile to add the proper link to correct library 5672 if args[0] == 'Delphes3': 5673 #change in the makefile 5674 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) 5675 # to 5676 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,/Applications/root_v6.04.08/lib/ 5677 rootsys = os.environ['ROOTSYS'] 5678 text = open('./Delphes/Makefile').read() 5679 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)', 5680 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys) 5681 open('./Delphes/Makefile','w').write(text) 5682 5683 # For SysCalc link to lhapdf 5684 if name == 'SysCalc': 5685 if self.options['lhapdf']: 5686 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'], 5687 stdout=subprocess.PIPE).communicate()[0] 5688 ld_path = ld_path.replace('\n','') 5689 if 'LD_LIBRARY_PATH' not in os.environ: 5690 os.environ['LD_LIBRARY_PATH'] = ld_path 5691 elif not os.environ['LD_LIBRARY_PATH']: 5692 os.environ['LD_LIBRARY_PATH'] = ld_path 5693 elif ld_path not in os.environ['LD_LIBRARY_PATH']: 5694 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path 5695 if self.options['lhapdf'] != 'lhapdf-config': 5696 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']): 5697 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH']) 5698 else: 5699 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6') 5700 if self.options['cpp_compiler']: 5701 make_flags.append('CXX=%s' % self.options['cpp_compiler']) 5702 5703 5704 if logger.level <= logging.INFO: 5705 devnull = open(os.devnull,'w') 5706 try: 5707 misc.call(['make', 'clean'], stdout=devnull, stderr=-2) 5708 except Exception: 5709 pass 5710 if name == 'pythia-pgs': 5711 #SLC6 needs to have this first (don't ask why) 5712 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 5713 if name in ['golem95','QCDLoop','PJFry']: 5714 status = misc.call(['make','install'], 5715 cwd = os.path.join(MG5DIR, name)) 5716 else: 5717 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name)) 5718 else: 5719 try: 5720 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 5721 except Exception: 5722 pass 5723 if name == 'pythia-pgs': 5724 #SLC6 needs to have this first (don't ask why) 5725 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 5726 if name in ['golem95','QCDLoop','PJFry']: 5727 status = misc.compile(['install'], mode='', 5728 cwd = os.path.join(MG5DIR, name)) 5729 else: 5730 status = self.compile(make_flags, mode='', 5731 cwd = os.path.join(MG5DIR, name)) 5732 5733 if not status: 5734 logger.info('Compilation succeeded') 5735 else: 5736 # For pythia-pgs check when removing the "-fno-second-underscore" flag 5737 if name == 'pythia-pgs': 5738 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio', 5739 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch'] 5740 for f in to_comment: 5741 f = pjoin(MG5DIR, name, *f.split('/')) 5742 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l) 5743 fsock = open(f,'w').write(text) 5744 try: 5745 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 5746 except Exception: 5747 pass 5748 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name)) 5749 if not status: 5750 logger.info('Compilation succeeded') 5751 else: 5752 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.') 5753 5754 5755 # Special treatment for TD/Ghostscript program (require by MadAnalysis) 5756 if args[0] == 'MadAnalysis': 5757 try: 5758 os.system('rm -rf td') 5759 os.mkdir(pjoin(MG5DIR, 'td')) 5760 except Exception, error: 5761 print error 5762 pass 5763 5764 if sys.platform == "darwin": 5765 logger.info('Downloading TD for Mac') 5766 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td_mac_intel.tar.gz' 5767 misc.call(['curl', target, '-otd.tgz'], 5768 cwd=pjoin(MG5DIR,'td')) 5769 misc.call(['tar', '-xzpvf', 'td.tgz'], 5770 cwd=pjoin(MG5DIR,'td')) 5771 files.mv(MG5DIR + '/td/td_mac_intel',MG5DIR+'/td/td') 5772 else: 5773 if sys.maxsize > 2**32: 5774 logger.info('Downloading TD for Linux 64 bit') 5775 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td64/td' 5776 logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer. 5777 In 99% of the case, this is perfectly fine. If you do not have plot, please follow 5778 instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''') 5779 else: 5780 logger.info('Downloading TD for Linux 32 bit') 5781 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td' 5782 misc.call(['wget', target], cwd=pjoin(MG5DIR,'td')) 5783 os.chmod(pjoin(MG5DIR,'td','td'), 0775) 5784 self.options['td_path'] = pjoin(MG5DIR,'td') 5785 5786 if not misc.which('gs'): 5787 logger.warning('''gosthscript not install on your system. This is not required to run MA. 5788 but this prevent to create jpg files and therefore to have the plots in the html output.''') 5789 if sys.platform == "darwin": 5790 logger.warning('''You can download this program at the following link: 5791 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''') 5792 5793 if args[0] == 'Delphes2': 5794 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read() 5795 data = data.replace('data/', 'DELPHESDIR/data/') 5796 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w') 5797 out.write(data) 5798 if args[0] == 'Delphes3': 5799 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')): 5800 card_dir = pjoin(MG5DIR, 'Delphes','cards') 5801 else: 5802 card_dir = pjoin(MG5DIR, 'Delphes','examples') 5803 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 5804 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat')) 5805 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 5806 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat')) 5807 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'), 5808 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat')) 5809 5810 5811 #reset the position of the executable 5812 options_name = {'Delphes': 'delphes_path', 5813 'Delphes2': 'delphes_path', 5814 'Delphes3': 'delphes_path', 5815 'ExRootAnalysis': 'exrootanalysis_path', 5816 'MadAnalysis': 'madanalysis_path', 5817 'SysCalc': 'syscalc_path', 5818 'pythia-pgs':'pythia-pgs_path', 5819 'Golem95': 'golem', 5820 'PJFry': 'pjfry'} 5821 5822 if args[0] in options_name: 5823 opt = options_name[args[0]] 5824 if opt=='golem': 5825 self.options[opt] = pjoin(MG5DIR,name,'lib') 5826 self.exec_cmd('save options') 5827 elif opt=='pjfry': 5828 self.options[opt] = pjoin(MG5DIR,'PJFry','lib') 5829 self.exec_cmd('save options') 5830 elif self.options[opt] != self.options_configuration[opt]: 5831 self.options[opt] = self.options_configuration[opt] 5832 self.exec_cmd('save options')
5833 5834 5835
5836 - def install_update(self, args, wget):
5837 """ check if the current version of mg5 is up-to-date. 5838 and allow user to install the latest version of MG5 """ 5839 5840 def apply_patch(filetext): 5841 """function to apply the patch""" 5842 text = filetext.read() 5843 pattern = re.compile(r'''=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 5844 #=== renamed directory 'Template' => 'Template/LO' 5845 for orig, new in pattern.findall(text): 5846 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP')) 5847 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 5848 for i, name in enumerate(full_path): 5849 path = os.path.sep.join(full_path[:i+1]) 5850 if path and not os.path.isdir(path): 5851 os.mkdir(path) 5852 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new)) 5853 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP')) 5854 # track rename since patch fail to apply those correctly. 5855 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 5856 #=== renamed file 'Template/SubProcesses/addmothers.f' => 'madgraph/iolibs/template_files/addmothers.f' 5857 for orig, new in pattern.findall(text): 5858 print 'move %s to %s' % (orig, new) 5859 try: 5860 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 5861 except IOError: 5862 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 5863 for i, name in enumerate(full_path): 5864 path = os.path.sep.join(full_path[:i+1]) 5865 if path and not os.path.isdir(path): 5866 os.mkdir(path) 5867 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 5868 # track remove/re-added file: 5869 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M) 5870 all_add = pattern.findall(text) 5871 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 5872 #all_rm = pattern.findall(text) 5873 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S) 5874 print 'this step can take a few minuts. please be patient' 5875 all_rm_add = pattern.findall(text) 5876 #=== added file 'tests/input_files/full_sm/interactions.dat' 5877 for new in all_add: 5878 if new in all_rm_add: 5879 continue 5880 if os.path.isfile(pjoin(MG5DIR, new)): 5881 os.remove(pjoin(MG5DIR, new)) 5882 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 5883 #=== removed file 'tests/input_files/full_sm/interactions.dat' 5884 #for old in pattern.findall(text): 5885 # if not os.path.isfile(pjoin(MG5DIR, old)): 5886 # full_path = os.path.dirname(pjoin(MG5DIR, old)).split('/') 5887 # for i, _ in enumerate(full_path): 5888 # path = os.path.sep.join(full_path[:i+1]) 5889 # if path and not os.path.isdir(path): 5890 # os.mkdir(path) 5891 # subprocess.call(['touch', pjoin(MG5DIR, old)]) 5892 5893 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE, 5894 cwd=MG5DIR) 5895 p.communicate(text) 5896 5897 # check file which are not move 5898 #=== modified file 'Template/LO/Cards/run_card.dat' 5899 #--- old/Template/Cards/run_card.dat 2012-12-06 10:01:04 +0000 5900 #+++ new/Template/LO/Cards/run_card.dat 2013-12-09 02:35:59 +0000 5901 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 5902 for match in pattern.findall(text): 5903 new = pjoin(MG5DIR, match[0]) 5904 old = pjoin(MG5DIR, match[1]) 5905 if new == old: 5906 continue 5907 elif os.path.exists(old): 5908 if not os.path.exists(os.path.dirname(new)): 5909 split = new.split('/') 5910 for i in range(1,len(split)): 5911 path = '/'.join(split[:i]) 5912 if not os.path.exists(path): 5913 print 'mkdir', path 5914 os.mkdir(path) 5915 files.cp(old,new) 5916 #=== renamed file 'Template/bin/internal/run_delphes' => 'Template/Common/bin/internal/run_delphes' 5917 #--- old/Template/bin/internal/run_delphes 2011-12-09 07:28:10 +0000 5918 #+++ new/Template/Common/bin/internal/run_delphes 2012-10-23 02:41:37 +0000 5919 #pattern=re.compile('''=== renamed file \'(?P<old>[^\']*)\' => \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P=old)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 5920 #for match in pattern.findall(text): 5921 # old = pjoin(MG5DIR, match[0]) 5922 # new = pjoin(MG5DIR, match[1]) 5923 # if new == old: 5924 # continue 5925 # elif os.path.exists(old): 5926 # if not os.path.exists(os.path.dirname(new)): 5927 # split = new.split('/') 5928 # for i in range(1,len(split)): 5929 # path = '/'.join(split[:i]) 5930 # if not os.path.exists(path): 5931 # print 'mkdir', path 5932 # os.mkdir(path) 5933 # files.cp(old,new) 5934 5935 # check that all files in bin directory are executable 5936 for path in misc.glob('*', pjoin(MG5DIR, 'bin')): 5937 misc.call(['chmod', '+x', path]) 5938 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')): 5939 misc.call(['chmod', '+x', path]) 5940 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')): 5941 misc.call(['chmod', '+x', path]) 5942 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')): 5943 misc.call(['chmod', '+x', path]) 5944 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')): 5945 misc.call(['chmod', '+x', path]) 5946 5947 #add empty files/directory 5948 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M) 5949 for match in pattern.findall(text): 5950 if match[0] == 'file': 5951 new = os.path.dirname(pjoin(MG5DIR, match[1])) 5952 else: 5953 new = pjoin(MG5DIR, match[1]) 5954 if not os.path.exists(new): 5955 split = new.split('/') 5956 for i in range(1,len(split)+1): 5957 path = '/'.join(split[:i]) 5958 if path and not os.path.exists(path): 5959 print 'mkdir', path 5960 os.mkdir(path) 5961 if match[0] == 'file': 5962 print 'touch ', pjoin(MG5DIR, match[1]) 5963 misc.call(['touch', pjoin(MG5DIR, match[1])]) 5964 # add new symlink 5965 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M) 5966 for new, old in pattern.findall(text): 5967 if not os.path.exists(pjoin(MG5DIR, new)): 5968 files.ln(old, os.path.dirname(new), os.path.basename(new)) 5969 5970 # Re-compile CutTools and IREGI 5971 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')): 5972 misc.compile(cwd=pjoin(MG5DIR,'vendor','CutTools')) 5973 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')): 5974 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src')) 5975 5976 # check if it need to download binary: 5977 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M) 5978 if pattern.search(text): 5979 return True 5980 else: 5981 return False
5982 5983 # load options 5984 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')] 5985 if mode: 5986 mode = mode[-1] 5987 else: 5988 mode = "userrequest" 5989 force = any([arg=='-f' for arg in args]) 5990 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')] 5991 if timeout: 5992 try: 5993 timeout = int(timeout[-1]) 5994 except ValueError: 5995 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1]) 5996 else: 5997 timeout = self.options['timeout'] 5998 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')] 5999 6000 if input_path: 6001 fsock = open(input_path[0]) 6002 need_binary = apply_patch(fsock) 6003 logger.info('manual patch apply. Please test your version.') 6004 if need_binary: 6005 logger.warning('Note that some files need to be loaded separately!') 6006 sys.exit(0) 6007 6008 options = ['y','n','on_exit'] 6009 if mode == 'mg5_start': 6010 timeout = 2 6011 default = 'n' 6012 update_delay = self.options['auto_update'] * 24 * 3600 6013 if update_delay == 0: 6014 return 6015 elif mode == 'mg5_end': 6016 timeout = 5 6017 default = 'n' 6018 update_delay = self.options['auto_update'] * 24 * 3600 6019 if update_delay == 0: 6020 return 6021 options.remove('on_exit') 6022 elif mode == "userrequest": 6023 default = 'y' 6024 update_delay = 0 6025 else: 6026 raise self.InvalidCmd('Unknown mode for command install update') 6027 6028 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')) or \ 6029 os.path.exists(os.path.join(MG5DIR,'.bzr')): 6030 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are: 6031 1) This version was loaded via bazaar (use bzr pull to update instead). 6032 2) This version is a beta release of MG5.""" 6033 if mode == 'userrequest': 6034 raise self.ConfigurationError(error_text) 6035 return 6036 6037 if not misc.which('patch'): 6038 error_text = """Not able to find program \'patch\'. Please reload a clean version 6039 or install that program and retry.""" 6040 if mode == 'userrequest': 6041 raise self.ConfigurationError(error_text) 6042 return 6043 6044 6045 # read the data present in .autoupdate 6046 data = {} 6047 for line in open(os.path.join(MG5DIR,'input','.autoupdate')): 6048 if not line.strip(): 6049 continue 6050 sline = line.split() 6051 data[sline[0]] = int(sline[1]) 6052 6053 #check validity of the file 6054 if 'version_nb' not in data: 6055 if mode == 'userrequest': 6056 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)' 6057 raise self.ConfigurationError(error_text) 6058 return 6059 elif 'last_check' not in data: 6060 data['last_check'] = time.time() 6061 6062 #check if we need to update. 6063 if time.time() - data['last_check'] < update_delay: 6064 return 6065 6066 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout) 6067 class TimeOutError(Exception): pass 6068 6069 def handle_alarm(signum, frame): 6070 raise TimeOutError 6071 6072 signal.signal(signal.SIGALRM, handle_alarm) 6073 signal.alarm(timeout) 6074 to_update = 0 6075 try: 6076 filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/mg5amc_build_nb') 6077 signal.alarm(0) 6078 web_version = int(filetext.read().strip()) 6079 except (TimeOutError, ValueError, IOError): 6080 signal.alarm(0) 6081 print 'failed to connect server' 6082 if mode == 'mg5_end': 6083 # wait 24h before next check 6084 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6085 fsock.write("version_nb %s\n" % data['version_nb']) 6086 fsock.write("last_check %s\n" % \ 6087 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1)) 6088 fsock.close() 6089 return 6090 6091 if web_version == data['version_nb']: 6092 logger.info('No new version of MG5 available') 6093 # update .autoupdate to prevent a too close check 6094 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6095 fsock.write("version_nb %s\n" % data['version_nb']) 6096 fsock.write("last_check %s\n" % int(time.time())) 6097 fsock.close() 6098 return 6099 elif data['version_nb'] > web_version: 6100 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version)) 6101 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6102 fsock.write("version_nb %s\n" % data['version_nb']) 6103 fsock.write("last_check %s\n" % int(time.time())) 6104 fsock.close() 6105 return 6106 else: 6107 if not force: 6108 answer = self.ask('New Version of MG5 available! Do you want to update your current version?', 6109 default, options) 6110 else: 6111 answer = default 6112 6113 6114 if answer == 'y': 6115 logger.info('start updating code') 6116 fail = 0 6117 for i in range(data['version_nb'], web_version): 6118 try: 6119 filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1)) 6120 # filetext = urllib.urlopen('http://madgraph.phys.ucl.ac.be/patch_test/build%s.patch' %(i+1)) 6121 except Exception: 6122 print 'fail to load patch to build #%s' % (i+1) 6123 fail = i 6124 break 6125 need_binary = apply_patch(filetext) 6126 if need_binary: 6127 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1) 6128 name = "extra_file%i" % (i+1) 6129 if sys.platform == "darwin": 6130 misc.call(['curl', path, '-o%s.tgz' % name], cwd=MG5DIR) 6131 else: 6132 misc.call(['wget', path, '--output-document=%s.tgz'% name], cwd=MG5DIR) 6133 # Untar the file 6134 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6135 stdout=open(os.devnull, 'w')) 6136 6137 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6138 if not fail: 6139 fsock.write("version_nb %s\n" % web_version) 6140 else: 6141 fsock.write("version_nb %s\n" % fail) 6142 fsock.write("last_check %s\n" % int(time.time())) 6143 fsock.close() 6144 # logger.info('Refreshing installation of MG5aMC_PY8_interface.') 6145 # self.do_install('mg5amc_py8_interface',additional_options=['--force']) 6146 logger.info('Checking current version. (type ctrl-c to bypass the check)') 6147 subprocess.call([os.path.join('tests','test_manager.py')], 6148 cwd=MG5DIR) 6149 print 'new version installed, please relaunch mg5' 6150 sys.exit(0) 6151 elif answer == 'n': 6152 # prevent for a future check 6153 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6154 fsock.write("version_nb %s\n" % data['version_nb']) 6155 fsock.write("last_check %s\n" % int(time.time())) 6156 fsock.close() 6157 logger.info('Update bypassed.') 6158 logger.info('The next check for a new version will be performed in %s days' \ 6159 % abs(self.options['auto_update'])) 6160 logger.info('In order to change this delay. Enter the command:') 6161 logger.info('set auto_update X') 6162 logger.info('Putting X to zero will prevent this check at anytime.') 6163 logger.info('You can upgrade your version at any time by typing:') 6164 logger.info('install update') 6165 else: #answer is on_exit 6166 #ensure that the test will be done on exit 6167 #Do not use the set command here!! 6168 self.options['auto_update'] = -1 * self.options['auto_update'] 6169 6170 6171
6172 - def set_configuration(self, config_path=None, final=True):
6173 """ assign all configuration variable from file 6174 ./input/mg5_configuration.txt. assign to default if not define """ 6175 6176 if not self.options: 6177 self.options = dict(self.options_configuration) 6178 self.options.update(self.options_madgraph) 6179 self.options.update(self.options_madevent) 6180 6181 if not config_path: 6182 if os.environ.has_key('MADGRAPH_BASE'): 6183 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 6184 self.set_configuration(config_path, final=False) 6185 if 'HOME' in os.environ: 6186 config_path = pjoin(os.environ['HOME'],'.mg5', 6187 'mg5_configuration.txt') 6188 if os.path.exists(config_path): 6189 self.set_configuration(config_path, final=False) 6190 config_path = os.path.relpath(pjoin(MG5DIR,'input', 6191 'mg5_configuration.txt')) 6192 return self.set_configuration(config_path, final) 6193 6194 if not os.path.exists(config_path): 6195 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path) 6196 config_file = open(config_path) 6197 6198 # read the file and extract information 6199 logger.info('load MG5 configuration from %s ' % config_file.name) 6200 for line in config_file: 6201 if '#' in line: 6202 line = line.split('#',1)[0] 6203 line = line.replace('\n','').replace('\r\n','') 6204 try: 6205 name, value = line.split('=') 6206 except ValueError: 6207 pass 6208 else: 6209 name = name.strip() 6210 value = value.strip() 6211 if name != 'mg5_path': 6212 self.options[name] = value 6213 if value.lower() == "none" or value=="": 6214 self.options[name] = None 6215 6216 self.options['stdout_level'] = logging.getLogger('madgraph').level 6217 if not final: 6218 return self.options # the return is usefull for unittest 6219 6220 # Treat each expected input 6221 # 1: Pythia8_path and hewrig++ paths 6222 # try absolute and relative path 6223 for key in self.options: 6224 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path', 6225 'mg5amc_py8_interface_path']: 6226 if self.options[key] in ['None', None]: 6227 self.options[key] = None 6228 continue 6229 path = self.options[key] 6230 #this is for pythia8 6231 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')): 6232 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')): 6233 self.options['pythia8_path'] = None 6234 else: 6235 continue 6236 #this is for mg5amc_py8_interface_path 6237 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')): 6238 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')): 6239 self.options['pythia8_path'] = None 6240 else: 6241 continue 6242 6243 #this is for hw++ 6244 elif key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 6245 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 6246 self.options['hwpp_path'] = None 6247 else: 6248 continue 6249 # this is for thepeg 6250 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 6251 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 6252 self.options['thepeg_path'] = None 6253 else: 6254 continue 6255 # this is for hepmc 6256 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HEPEVT_Wrapper.h')): 6257 if not os.path.isfile(pjoin(path, 'include', 'HEPEVT_Wrapper.h')): 6258 self.options['hepmc_path'] = None 6259 else: 6260 continue 6261 6262 elif key in ['pjfry','golem','samurai']: 6263 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto': 6264 # try to find it automatically on the system 6265 program = misc.which_lib('lib%s.a'%key) 6266 if program != None: 6267 fpath, _ = os.path.split(program) 6268 logger.info('Using %s library in %s' % (key,fpath)) 6269 self.options[key]=fpath 6270 else: 6271 # Try to look for it locally 6272 local_install = {'pjfry':'PJFRY', 'golem':'golem95', 6273 'samurai':'samurai'} 6274 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)): 6275 self.options[key]=pjoin(MG5DIR,local_install[key],'lib') 6276 else: 6277 self.options[key]=None 6278 # Make sure that samurai version is recent enough 6279 if key=='samurai' and \ 6280 isinstance(self.options[key],str) and \ 6281 self.options[key].lower() != 'auto': 6282 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')): 6283 try: 6284 version = open(pjoin(self.options[key],os.pardir, 6285 'VERSION'),'r').read() 6286 except IOError: 6287 version = None 6288 if version is None: 6289 self.options[key] = None 6290 logger.info('--------') 6291 logger.info( 6292 """The version of 'samurai' automatically detected seems too old to be compatible 6293 with MG5aMC and it will be turned off. Ask the authors for the latest version if 6294 you want to use samurai. 6295 If you want to enforce its use as-it-is, then specify directly its library folder 6296 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""") 6297 logger.info('--------') 6298 6299 elif key.endswith('path'): 6300 pass 6301 elif key in ['run_mode', 'auto_update']: 6302 self.options[key] = int(self.options[key]) 6303 elif key in ['cluster_type','automatic_html_opening']: 6304 pass 6305 elif key in ['notification_center']: 6306 if self.options[key] in ['False', 'True']: 6307 self.allow_notification_center = eval(self.options[key]) 6308 self.options[key] = self.allow_notification_center 6309 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']: 6310 # Default: try to set parameter 6311 try: 6312 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 6313 except MadGraph5Error, error: 6314 print error 6315 logger.warning("Option %s from config file not understood" \ 6316 % key) 6317 else: 6318 if key in self.options_madgraph: 6319 self.history.append('set %s %s' % (key, self.options[key])) 6320 6321 # warnings = misc.mg5amc_py8_interface_consistency_warning(self.options) 6322 # if warnings: 6323 # logger.warning(warnings) 6324 6325 # Configure the way to open a file: 6326 launch_ext.open_file.configure(self.options) 6327 return self.options
6328
6329 - def check_for_export_dir(self, filepath):
6330 """Check if the files is in a valid export directory and assign it to 6331 export path if if is""" 6332 6333 # keep previous if a previous one is defined 6334 if self._export_dir: 6335 return 6336 6337 if os.path.exists(pjoin(os.getcwd(), 'Cards')): 6338 self._export_dir = os.getcwd() 6339 return 6340 6341 path_split = filepath.split(os.path.sep) 6342 if len(path_split) > 2 and path_split[-2] == 'Cards': 6343 self._export_dir = os.path.sep.join(path_split[:-2]) 6344 return
6345
6346 - def do_launch(self, line):
6347 """Main commands: Ask for editing the parameter and then 6348 Execute the code (madevent/standalone/...) 6349 """ 6350 6351 #ensure that MG option are not modified by the launch routine 6352 current_options = dict([(name, self.options[name]) for name in self.options_madgraph]) 6353 start_cwd = os.getcwd() 6354 6355 args = self.split_arg(line) 6356 # check argument validity and normalise argument 6357 (options, args) = _launch_parser.parse_args(args) 6358 self.check_launch(args, options) 6359 options = options.__dict__ 6360 # args is now MODE PATH 6361 6362 if args[0].startswith('standalone'): 6363 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\ 6364 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\ 6365 os.getcwd(),args[1],'SubProcesses','check_poles.f')): 6366 ext_program = launch_ext.MadLoopLauncher(self, args[1], \ 6367 options=self.options, **options) 6368 else: 6369 ext_program = launch_ext.SALauncher(self, args[1], \ 6370 options=self.options, **options) 6371 elif args[0] == 'madevent': 6372 if options['interactive']: 6373 6374 if isinstance(self, cmd.CmdShell): 6375 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options) 6376 else: 6377 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options) 6378 ME.pass_in_web_mode() 6379 stop = self.define_child_cmd_interface(ME) 6380 return stop 6381 6382 #check if this is a cross-section 6383 if not self._generate_info: 6384 # This relaunch an old run -> need to check if this is a 6385 # cross-section or a width 6386 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read() 6387 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1] 6388 generate_info = generate_info.split('#')[0] 6389 else: 6390 generate_info = self._generate_info 6391 6392 if len(generate_info.split('>')[0].strip().split())>1: 6393 ext_program = launch_ext.MELauncher(args[1], self, 6394 shell = isinstance(self, cmd.CmdShell), 6395 options=self.options,**options) 6396 else: 6397 # This is a width computation 6398 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV', 6399 shell = isinstance(self, cmd.CmdShell), 6400 options=self.options,**options) 6401 6402 elif args[0] == 'pythia8': 6403 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options) 6404 6405 elif args[0] == 'aMC@NLO': 6406 if options['interactive']: 6407 if isinstance(self, cmd.CmdShell): 6408 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options) 6409 else: 6410 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options) 6411 ME.pass_in_web_mode() 6412 # transfer interactive configuration 6413 config_line = [l for l in self.history if l.strip().startswith('set')] 6414 for line in config_line: 6415 ME.exec_cmd(line) 6416 stop = self.define_child_cmd_interface(ME) 6417 return stop 6418 ext_program = launch_ext.aMCatNLOLauncher( args[1], self, 6419 shell = isinstance(self, cmd.CmdShell), 6420 **options) 6421 elif args[0] == 'madweight': 6422 import madgraph.interface.madweight_interface as madweight_interface 6423 if options['interactive']: 6424 if isinstance(self, cmd.CmdShell): 6425 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options) 6426 else: 6427 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options) 6428 # transfer interactive configuration 6429 config_line = [l for l in self.history if l.strip().startswith('set')] 6430 for line in config_line: 6431 MW.exec_cmd(line) 6432 stop = self.define_child_cmd_interface(MW) 6433 return stop 6434 ext_program = launch_ext.MWLauncher( self, args[1], 6435 shell = isinstance(self, cmd.CmdShell), 6436 options=self.options,**options) 6437 else: 6438 os.chdir(start_cwd) #ensure to go to the initial path 6439 raise self.InvalidCmd , '%s cannot be run from MG5 interface' % args[0] 6440 6441 6442 ext_program.run() 6443 os.chdir(start_cwd) #ensure to go to the initial path 6444 # ensure that MG options are not changed! 6445 for key, value in current_options.items(): 6446 self.options[key] = value
6447
6448 - def do_load(self, line):
6449 """Not in help: Load information from file""" 6450 6451 args = self.split_arg(line) 6452 # check argument validity 6453 self.check_load(args) 6454 6455 cpu_time1 = time.time() 6456 if args[0] == 'model': 6457 self._curr_model = save_load_object.load_from_file(args[1]) 6458 if self._curr_model.get('parameters'): 6459 # This is a UFO model 6460 self._model_v4_path = None 6461 self._curr_fortran_model = \ 6462 helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 6463 else: 6464 # This is a v4 model 6465 self._model_v4_path = import_v4.find_model_path(\ 6466 self._curr_model.get('name').replace("_v4", ""), 6467 self._mgme_dir) 6468 self._curr_fortran_model = \ 6469 helas_call_writers.FortranHelasCallWriter(self._curr_model) 6470 6471 # Do post-processing of model 6472 self.process_model() 6473 6474 #save_model.save_model(args[1], self._curr_model) 6475 if isinstance(self._curr_model, base_objects.Model): 6476 cpu_time2 = time.time() 6477 logger.info("Loaded model from file in %0.3f s" % \ 6478 (cpu_time2 - cpu_time1)) 6479 else: 6480 raise self.RWError('Could not load model from file %s' \ 6481 % args[1]) 6482 elif args[0] == 'processes': 6483 amps = save_load_object.load_from_file(args[1]) 6484 if isinstance(amps, diagram_generation.AmplitudeList): 6485 cpu_time2 = time.time() 6486 logger.info("Loaded processes from file in %0.3f s" % \ 6487 (cpu_time2 - cpu_time1)) 6488 if amps: 6489 model = amps[0].get('process').get('model') 6490 if not model.get('parameters'): 6491 # This is a v4 model. Look for path. 6492 self._model_v4_path = import_v4.find_model_path(\ 6493 model.get('name').replace("_v4", ""), 6494 self._mgme_dir) 6495 self._curr_fortran_model = \ 6496 helas_call_writers.FortranHelasCallWriter(\ 6497 model) 6498 else: 6499 self._model_v4_path = None 6500 self._curr_fortran_model = \ 6501 helas_call_writers.FortranUFOHelasCallWriter(\ 6502 model) 6503 # If not exceptions from previous steps, set 6504 # _curr_amps and _curr_model 6505 self._curr_amps = amps 6506 self._curr_model = model 6507 logger.info("Model set from process.") 6508 # Do post-processing of model 6509 self.process_model() 6510 self._done_export = None 6511 else: 6512 raise self.RWError('Could not load processes from file %s' % args[1])
6513 6514
6515 - def do_customize_model(self, line):
6516 """create a restriction card in a interactive way""" 6517 6518 args = self.split_arg(line) 6519 self.check_customize_model(args) 6520 6521 model_path = self._curr_model.get('modelpath') 6522 if not os.path.exists(pjoin(model_path,'build_restrict.py')): 6523 raise self.InvalidCmd('''Model not compatible with this option.''') 6524 6525 # (re)import the full model (get rid of the default restriction) 6526 self._curr_model = import_ufo.import_model(model_path, restrict=False) 6527 6528 #1) create the full param_card 6529 out_path = StringIO.StringIO() 6530 param_writer.ParamCardWriter(self._curr_model, out_path) 6531 # and load it to a python object 6532 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 6533 6534 6535 all_categories = self.ask('','0',[], ask_class=AskforCustomize) 6536 put_to_one = [] 6537 ## Make a Temaplate for the restriction card. (card with no restrict) 6538 for block in param_card: 6539 value_dict = {} 6540 for param in param_card[block]: 6541 value = param.value 6542 if value == 0: 6543 param.value = 0.000001e-99 6544 elif value == 1: 6545 if block != 'qnumbers': 6546 put_to_one.append((block,param.lhacode)) 6547 param.value = random.random() 6548 elif abs(value) in value_dict: 6549 param.value += value_dict[abs(value)] * 1e-4 * param.value 6550 value_dict[abs(value)] += 1 6551 else: 6552 value_dict[abs(value)] = 1 6553 6554 for category in all_categories: 6555 for options in category: 6556 if not options.status: 6557 continue 6558 param = param_card[options.lhablock].get(options.lhaid) 6559 param.value = options.value 6560 6561 logger.info('Loading the resulting model') 6562 # Applying the restriction 6563 self._curr_model = import_ufo.RestrictModel(self._curr_model) 6564 model_name = self._curr_model.get('name') 6565 if model_name == 'mssm': 6566 keep_external=True 6567 else: 6568 keep_external=False 6569 self._curr_model.restrict_model(param_card,keep_external=keep_external) 6570 6571 if args: 6572 name = args[0].split('=',1)[1] 6573 path = pjoin(model_path,'restrict_%s.dat' % name) 6574 logger.info('Save restriction file as %s' % path) 6575 param_card.write(path) 6576 self._curr_model['name'] += '-%s' % name 6577 6578 # if some need to put on one 6579 if put_to_one: 6580 out_path = StringIO.StringIO() 6581 param_writer.ParamCardWriter(self._curr_model, out_path) 6582 # and load it to a python object 6583 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 6584 6585 for (block, lhacode) in put_to_one: 6586 misc.sprint(block, lhacode) 6587 try: 6588 param_card[block].get(lhacode).value = 1 6589 except: 6590 pass # was removed of the model! 6591 self._curr_model.set_parameters_and_couplings(param_card) 6592 6593 if args: 6594 name = args[0].split('=',1)[1] 6595 path = pjoin(model_path,'paramcard_%s.dat' % name) 6596 logger.info('Save default card file as %s' % path) 6597 param_card.write(path)
6598
6599 - def do_save(self, line, check=True, to_keep={}, log=True):
6600 """Not in help: Save information to file""" 6601 6602 args = self.split_arg(line) 6603 # Check argument validity 6604 if check: 6605 self.check_save(args) 6606 6607 if args[0] == 'model': 6608 if self._curr_model: 6609 #save_model.save_model(args[1], self._curr_model) 6610 if save_load_object.save_to_file(args[1], self._curr_model): 6611 logger.info('Saved model to file %s' % args[1]) 6612 else: 6613 raise self.InvalidCmd('No model to save!') 6614 elif args[0] == 'processes': 6615 if self._curr_amps: 6616 if save_load_object.save_to_file(args[1], self._curr_amps): 6617 logger.info('Saved processes to file %s' % args[1]) 6618 else: 6619 raise self.InvalidCmd('No processes to save!') 6620 6621 elif args[0] == 'options': 6622 # First look at options which should be put in MG5DIR/input 6623 to_define = {} 6624 for key, default in self.options_configuration.items(): 6625 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None: 6626 to_define[key] = self.options[key] 6627 6628 if not '--auto' in args: 6629 for key, default in self.options_madevent.items(): 6630 if self.options_madevent[key] != self.options[key] != None: 6631 if '_path' in key and os.path.basename(self.options[key]) == 'None': 6632 continue 6633 to_define[key] = self.options[key] 6634 elif key == 'cluster_queue' and self.options[key] is None: 6635 to_define[key] = self.options[key] 6636 6637 if '--all' in args: 6638 for key, default in self.options_madgraph.items(): 6639 if self.options_madgraph[key] != self.options[key] != None and \ 6640 key != 'stdout_level': 6641 to_define[key] = self.options[key] 6642 elif not '--auto' in args: 6643 for key, default in self.options_madgraph.items(): 6644 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level': 6645 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 6646 % (key,self.options_madgraph[key]) ) 6647 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 6648 if len(args) >1 and not args[1].startswith('--'): 6649 filepath = args[1] 6650 else: 6651 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 6652 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt') 6653 basedir = MG5DIR 6654 6655 if to_keep: 6656 to_define = to_keep 6657 self.write_configuration(filepath, basefile, basedir, to_define)
6658 6659 # Set an option
6660 - def do_set(self, line, log=True, model_reload=True):
6661 """Set an option, which will be default for coming generations/outputs. 6662 """ 6663 6664 # Be careful: 6665 # This command is associated to a post_cmd: post_set. 6666 args = self.split_arg(line) 6667 6668 # Check the validity of the arguments 6669 self.check_set(args) 6670 6671 if args[0] == 'ignore_six_quark_processes': 6672 if args[1] == 'False': 6673 self.options[args[0]] = False 6674 return 6675 self.options[args[0]] = list(set([abs(p) for p in \ 6676 self._multiparticles[args[1]]\ 6677 if self._curr_model.get_particle(p).\ 6678 is_fermion() and \ 6679 self._curr_model.get_particle(abs(p)).\ 6680 get('color') == 3])) 6681 if log: 6682 logger.info('Ignore processes with >= 6 quarks (%s)' % \ 6683 ",".join([\ 6684 self._curr_model.get_particle(q).get('name') \ 6685 for q in self.options[args[0]]])) 6686 6687 elif args[0] == 'group_subprocesses': 6688 if args[1] not in ['Auto', 'NLO']: 6689 self.options[args[0]] = eval(args[1]) 6690 else: 6691 self.options[args[0]] = args[1] 6692 if log: 6693 logger.info('Set group_subprocesses to %s' % \ 6694 str(self.options[args[0]])) 6695 logger.info('Note that you need to regenerate all processes') 6696 self._curr_amps = diagram_generation.AmplitudeList() 6697 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 6698 6699 elif args[0] == "stdout_level": 6700 if args[1].isdigit(): 6701 level = int(args[1]) 6702 else: 6703 level = eval('logging.' + args[1]) 6704 logging.root.setLevel(level) 6705 logging.getLogger('madgraph').setLevel(level) 6706 logging.getLogger('madevent').setLevel(level) 6707 if log: 6708 logger.info('set output information to level: %s' % level) 6709 elif args[0].lower() == "ewscheme": 6710 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." %\ 6711 (self._curr_model.get('name'), args[1])) 6712 logger.info("Importing a model will restore the default scheme") 6713 self._curr_model.change_electroweak_mode(args[1]) 6714 elif args[0] == "complex_mass_scheme": 6715 old = self.options[args[0]] 6716 self.options[args[0]] = eval(args[1]) 6717 aloha.complex_mass = eval(args[1]) 6718 aloha_lib.KERNEL.clean() 6719 if self.options[args[0]]: 6720 if old: 6721 if log: 6722 logger.info('Complex mass already activated.') 6723 return 6724 if log: 6725 logger.info('Activate complex mass scheme.') 6726 else: 6727 if not old: 6728 if log: 6729 logger.info('Complex mass already desactivated.') 6730 return 6731 if log: 6732 logger.info('Desactivate complex mass scheme.') 6733 if not self._curr_model: 6734 return 6735 self.exec_cmd('import model %s' % self._curr_model.get('name')) 6736 6737 elif args[0] == "gauge": 6738 # Treat the case where they are no model loaded 6739 if not self._curr_model: 6740 if args[1] == 'unitary': 6741 aloha.unitary_gauge = True 6742 else: 6743 aloha.unitary_gauge = False 6744 aloha_lib.KERNEL.clean() 6745 self.options[args[0]] = args[1] 6746 if log: logger.info('Passing to gauge %s.' % args[1]) 6747 return 6748 6749 # They are a valid model 6750 able_to_mod = True 6751 if args[1] == 'unitary': 6752 if 0 in self._curr_model.get('gauge'): 6753 aloha.unitary_gauge = True 6754 else: 6755 able_to_mod = False 6756 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \ 6757 % self._curr_model.get('name')) 6758 else: 6759 if 1 in self._curr_model.get('gauge'): 6760 aloha.unitary_gauge = False 6761 else: 6762 able_to_mod = False 6763 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \ 6764 % self._curr_model.get('name')) 6765 self.options[args[0]] = args[1] 6766 6767 if able_to_mod and log and args[0] == 'gauge' and \ 6768 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \ 6769 isinstance(self._curr_model,loop_base_objects.LoopModel) and \ 6770 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 6771 logger.warning('You will only be able to do tree level'+\ 6772 ' and QCD corrections in the unitary gauge.') 6773 6774 #re-init all variable 6775 model_name = self._curr_model.get('modelpath+restriction') 6776 self._curr_model = None 6777 self._curr_amps = diagram_generation.AmplitudeList() 6778 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 6779 self._curr_fortran_model = None 6780 self._curr_cpp_model = None 6781 self._curr_exporter = None 6782 self._done_export = False 6783 import_ufo._import_once = [] 6784 logger.info('Passing to gauge %s.' % args[1]) 6785 6786 if able_to_mod: 6787 # We don't want to go through the MasterCommand again 6788 # because it messes with the interface switching when 6789 # importing a loop model from MG5 6790 MadGraphCmd.do_import(self,'model %s' %model_name, force=True) 6791 elif log: 6792 logger.info('Note that you have to reload the model') 6793 6794 elif args[0] == 'fortran_compiler': 6795 if args[1] != 'None': 6796 if log: 6797 logger.info('set fortran compiler to %s' % args[1]) 6798 self.options['fortran_compiler'] = args[1] 6799 else: 6800 self.options['fortran_compiler'] = None 6801 elif args[0] == 'f2py_compiler': 6802 if args[1] != 'None': 6803 if log: 6804 logger.info('set f2py compiler to %s' % args[1]) 6805 self.options['f2py_compiler'] = args[1] 6806 else: 6807 self.options['f2py_compiler'] = None 6808 6809 elif args[0] == 'loop_optimized_output': 6810 if log: 6811 logger.info('set loop optimized output to %s' % args[1]) 6812 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 6813 self.options[args[0]] = args[1] 6814 if not self.options['loop_optimized_output'] and \ 6815 self.options['loop_color_flows']: 6816 logger.warning("Turning off option 'loop_color_flows'"+\ 6817 " since it is not available for non-optimized loop output.") 6818 self.do_set('loop_color_flows False',log=False) 6819 elif args[0] == 'loop_color_flows': 6820 if log: 6821 logger.info('set loop color flows to %s' % args[1]) 6822 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 6823 self.options[args[0]] = args[1] 6824 if self.options['loop_color_flows'] and \ 6825 not self.options['loop_optimized_output']: 6826 logger.warning("Turning on option 'loop_optimized'"+\ 6827 " needed for loop color flow computation.") 6828 self.do_set('loop_optimized_output True',False) 6829 6830 elif args[0] == 'fastjet': 6831 try: 6832 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE, 6833 stderr=subprocess.PIPE) 6834 output, error = p.communicate() 6835 res = 0 6836 except Exception: 6837 res = 1 6838 6839 if res != 0 or error: 6840 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \ 6841 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \ 6842 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' + 6843 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n') 6844 self.options[args[0]] = None 6845 self.history.pop() 6846 elif int(output.split('.')[0]) < 3: 6847 logger.warning('%s is not ' % args[1] + \ 6848 'v3 or greater. Please install FastJet v3+.') 6849 self.options[args[0]] = None 6850 self.history.pop() 6851 else: #everything is fine 6852 logger.info('set fastjet to %s' % args[1]) 6853 self.options[args[0]] = args[1] 6854 6855 elif args[0] in ['pjfry','golem','samurai','ninja'] and \ 6856 not (args[0]=='ninja' and args[1]=='./HEPTools/lib'): 6857 if args[1] in ['None',"''",'""']: 6858 self.options[args[0]] = None 6859 else: 6860 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0])) 6861 if program!=None: 6862 res = 0 6863 logger.info('set %s to %s' % (args[0],args[1])) 6864 self.options[args[0]] = args[1] 6865 else: 6866 res = 1 6867 6868 if res != 0 : 6869 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \ 6870 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \ 6871 'You will NOT be able to run %s otherwise.\n'%args[0]) 6872 6873 elif args[0] == 'lhapdf': 6874 try: 6875 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE, 6876 stderr=subprocess.PIPE) 6877 logger.info('set lhapdf to %s' % args[1]) 6878 self.options[args[0]] = args[1] 6879 except Exception: 6880 res = 1 6881 if res != 0: 6882 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \ 6883 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \ 6884 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \ 6885 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \ 6886 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n') 6887 6888 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry', 6889 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']: 6890 self.options[args[0]] = int(args[1]) 6891 6892 elif args[0] in ['cluster_local_path']: 6893 self.options[args[0]] = args[1].strip() 6894 6895 elif args[0] == 'cluster_status_update': 6896 if '(' in args[1]: 6897 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 6898 data = data.replace('(','').replace(')','').replace(',',' ').split() 6899 first, second = data[:2] 6900 else: 6901 first, second = args[1:3] 6902 6903 self.options[args[0]] = (int(first), int(second)) 6904 6905 elif args[0] == 'OLP': 6906 # Reset the amplitudes, MatrixElements and exporter as they might 6907 # depend on this option 6908 self._curr_amps = diagram_generation.AmplitudeList() 6909 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 6910 self._curr_exporter = None 6911 self.options[args[0]] = args[1] 6912 6913 elif args[0] =='output_dependencies': 6914 self.options[args[0]] = args[1] 6915 elif args[0] =='notification_center': 6916 if args[1] in ['None','True','False']: 6917 self.options[args[0]] = eval(args[1]) 6918 self.allow_notification_center = self.options[args[0]] 6919 else: 6920 raise self.InvalidCmd('expected bool for notification_center') 6921 elif args[0] in ['cluster_queue']: 6922 self.options[args[0]] = args[1].strip() 6923 elif args[0] in self.options: 6924 if args[1] in ['None','True','False']: 6925 self.options[args[0]] = eval(args[1]) 6926 else: 6927 self.options[args[0]] = args[1]
6928
6929 - def post_set(self, stop, line):
6930 """Check if we need to save this in the option file""" 6931 6932 args = self.split_arg(line) 6933 # Check the validity of the arguments 6934 try: 6935 self.check_set(args, log=False) 6936 except Exception: 6937 return stop 6938 6939 if args[0] in self.options_configuration and '--no_save' not in args: 6940 self.exec_cmd('save options --auto', log=False) 6941 elif args[0] in self.options_madevent: 6942 if not '--no_save' in line: 6943 logger.info('This option will be the default in any output that you are going to create in this session.') 6944 logger.info('In order to keep this changes permanent please run \'save options\'') 6945 else: 6946 #MadGraph5_aMC@NLO configuration 6947 if not self.history or self.history[-1].split() != line.split(): 6948 self.history.append('set %s' % line) 6949 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set']) 6950 return stop
6951
6952 - def do_open(self, line):
6953 """Open a text file/ eps file / html file""" 6954 6955 args = self.split_arg(line) 6956 # Check Argument validity and modify argument to be the real path 6957 self.check_open(args) 6958 file_path = args[0] 6959 6960 launch_ext.open_file(file_path)
6961
6962 - def do_output(self, line):
6963 """Main commands: Initialize a new Template or reinitialize one""" 6964 6965 args = self.split_arg(line) 6966 # Check Argument validity 6967 self.check_output(args) 6968 6969 6970 noclean = '-noclean' in args 6971 force = '-f' in args 6972 nojpeg = '-nojpeg' in args 6973 flaglist = [] 6974 6975 if '--postpone_model' in args: 6976 flaglist.append('store_model') 6977 6978 main_file_name = "" 6979 try: 6980 main_file_name = args[args.index('-name') + 1] 6981 except Exception: 6982 pass 6983 6984 6985 ################ 6986 # ALOHA OUTPUT # 6987 ################ 6988 if self._export_format == 'aloha': 6989 # catch format 6990 format = [d[9:] for d in args if d.startswith('--format=')] 6991 if not format: 6992 format = 'Fortran' 6993 else: 6994 format = format[-1] 6995 # catch output dir 6996 output = [d for d in args if d.startswith('--output=')] 6997 if not output: 6998 output = import_ufo.find_ufo_path(self._curr_model['name']) 6999 output = pjoin(output, format) 7000 if not os.path.isdir(output): 7001 os.mkdir(output) 7002 else: 7003 output = output[-1] 7004 if not os.path.isdir(output): 7005 raise self.InvalidCmd('%s is not a valid directory' % output) 7006 logger.info('creating routines in directory %s ' % output) 7007 # build the calling list for aloha 7008 names = [d for d in args if not d.startswith('-')] 7009 wanted_lorentz = aloha_fct.guess_routine_from_name(names) 7010 # Create and write ALOHA Routine 7011 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name')) 7012 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz')) 7013 if wanted_lorentz: 7014 aloha_model.compute_subset(wanted_lorentz) 7015 else: 7016 aloha_model.compute_all(save=False) 7017 aloha_model.write(output, format) 7018 return 7019 7020 ################# 7021 ## Other Output # 7022 ################# 7023 # Configuration of what to do: 7024 # check: check status of the directory 7025 # exporter: which exporter to use (v4/cpp/...) 7026 # output: [Template/dir/None] copy the Template, just create dir or do nothing 7027 config = {} 7028 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7029 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'} 7030 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7031 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7032 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7033 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7034 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'} 7035 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'} 7036 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} 7037 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'} 7038 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7039 7040 options = config[self._export_format] 7041 # check 7042 if os.path.realpath(self._export_dir) == os.getcwd(): 7043 if len(args) == 0: 7044 i=0 7045 while 1: 7046 if os.path.exists('Pythia8_proc_%i' %i): 7047 i+=1 7048 else: 7049 break 7050 os.mkdir('Pythia8_proc_%i' %i) 7051 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i) 7052 logger.info('Create output in %s' % self._export_dir) 7053 elif not args[0] in ['.', '-f']: 7054 raise self.InvalidCmd, 'Wrong path directory to create in local directory use \'.\'' 7055 elif not noclean and os.path.isdir(self._export_dir) and options['check']: 7056 if not force: 7057 # Don't ask if user already specified force or noclean 7058 logger.info('INFO: directory %s already exists.' % self._export_dir) 7059 logger.info('If you continue this directory will be deleted and replaced.') 7060 answer = self.ask('Do you want to continue?', 'y', ['y','n']) 7061 else: 7062 answer = 'y' 7063 if answer != 'y': 7064 raise self.InvalidCmd('Stopped by user request') 7065 else: 7066 shutil.rmtree(self._export_dir) 7067 7068 # Choose here whether to group subprocesses or not, if the option was 7069 # set to 'Auto' and propagate this choice down the line: 7070 if self.options['group_subprocesses'] in [True, False]: 7071 group_processes = self.options['group_subprocesses'] 7072 elif self.options['group_subprocesses'] == 'Auto': 7073 # By default we set it to True 7074 group_processes = True 7075 # But we turn if off for decay processes which 7076 # have been defined with multiparticle labels, because then 7077 # branching ratios necessitates to keep subprocesses independent. 7078 # That applies only if there is more than one subprocess of course. 7079 if self._curr_amps[0].get_ninitial() == 1 and \ 7080 len(self._curr_amps)>1: 7081 processes = [amp.get('process') for amp in self._curr_amps] 7082 if len(set(proc.get('id') for proc in processes))!=len(processes): 7083 # Special warning for loop-induced 7084 if any(proc['perturbation_couplings'] != [] for proc in 7085 processes) and self._export_format == 'madevent': 7086 logger.warning(""" 7087 || The loop-induced decay process you have specified contains several 7088 || subprocesses and, in order to be able to compute individual branching ratios, 7089 || MG5_aMC will *not* group them. Integration channels will also be considered 7090 || for each diagrams and as a result integration will be inefficient. 7091 || It is therefore recommended to perform this simulation by setting the MG5_aMC 7092 || option 'group_subprocesses' to 'True' (before the output of the process). 7093 || Notice that when doing so, processes for which one still wishes to compute 7094 || branching ratios independently can be specified using the syntax: 7095 || -> add process <proc_def> 7096 """) 7097 group_processes = False 7098 7099 #Exporter + Template 7100 if options['exporter'] == 'v4': 7101 self._curr_exporter = export_v4.ExportV4Factory(self, noclean, 7102 group_subprocesses=group_processes) 7103 if options['output'] == 'Template': 7104 self._curr_exporter.copy_v4template(modelname=self._curr_model.get('name')) 7105 if options['exporter'] == 'cpp' and options['output'] == 'Template': 7106 export_cpp.setup_cpp_standalone_dir(self._export_dir, self._curr_model) 7107 7108 if options['output'] == 'dir' and not os.path.isdir(self._export_dir): 7109 os.makedirs(self._export_dir) 7110 7111 # Reset _done_export, since we have new directory 7112 self._done_export = False 7113 7114 if self._export_format == "madevent": 7115 # for MadEvent with MadLoop decide if we keep the box as channel of 7116 #integration or not. Forbid them for matching and for h+j 7117 if self.options['max_npoint_for_channel']: 7118 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel'] 7119 else: 7120 base_objects.Vertex.max_n_loop_for_multichanneling = 3 7121 7122 # Perform export and finalize right away 7123 self.export(nojpeg, main_file_name, group_processes, args) 7124 7125 # Automatically run finalize 7126 self.finalize(nojpeg, flaglist=flaglist) 7127 7128 # Remember that we have done export 7129 self._done_export = (self._export_dir, self._export_format) 7130 7131 # Reset _export_dir, so we don't overwrite by mistake later 7132 self._export_dir = None
7133 7134 # Export a matrix element
7135 - def export(self, nojpeg = False, main_file_name = "", group_processes=True, 7136 args=[]):
7137 """Export a generated amplitude to file.""" 7138 7139 version = [arg[10:] for arg in args if arg.startswith('--version=')] 7140 if version: 7141 version = version[-1] 7142 else: 7143 version = '' 7144 7145 def generate_matrix_elements(self, group_processes=True): 7146 """Helper function to generate the matrix elements before 7147 exporting. Uses the main function argument 'group_processes' to decide 7148 whether to use group_subprocess or not. (it has been set in do_output to 7149 the appropriate value if the MG5 option 'group_subprocesses' was set 7150 to 'Auto'.""" 7151 7152 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']: 7153 to_distinguish = [] 7154 for part in self._curr_model.get('particles'): 7155 if part.get('name') in args and part.get('antiname') in args and\ 7156 part.get('name') != part.get('antiname'): 7157 to_distinguish.append(abs(part.get('pdg_code'))) 7158 # Sort amplitudes according to number of diagrams, 7159 # to get most efficient multichannel output 7160 self._curr_amps.sort(lambda a1, a2: a2.get_number_of_diagrams() - \ 7161 a1.get_number_of_diagrams()) 7162 7163 cpu_time1 = time.time() 7164 ndiags = 0 7165 if not self._curr_matrix_elements.get_matrix_elements(): 7166 if group_processes: 7167 cpu_time1 = time.time() 7168 dc_amps = diagram_generation.DecayChainAmplitudeList(\ 7169 [amp for amp in self._curr_amps if isinstance(amp, \ 7170 diagram_generation.DecayChainAmplitude)]) 7171 non_dc_amps = diagram_generation.AmplitudeList(\ 7172 [amp for amp in self._curr_amps if not \ 7173 isinstance(amp, \ 7174 diagram_generation.DecayChainAmplitude)]) 7175 subproc_groups = group_subprocs.SubProcessGroupList() 7176 matrix_elements_opts = {'optimized_output': 7177 self.options['loop_optimized_output']} 7178 if non_dc_amps: 7179 subproc_groups.extend(\ 7180 group_subprocs.SubProcessGroup.group_amplitudes(\ 7181 non_dc_amps, self._export_format, 7182 matrix_elements_opts=matrix_elements_opts)) 7183 7184 if dc_amps: 7185 dc_subproc_group = \ 7186 group_subprocs.DecayChainSubProcessGroup.\ 7187 group_amplitudes(dc_amps, self._export_format, 7188 matrix_elements_opts=matrix_elements_opts) 7189 subproc_groups.extend(dc_subproc_group.\ 7190 generate_helas_decay_chain_subproc_groups()) 7191 7192 ndiags = sum([len(m.get('diagrams')) for m in \ 7193 subproc_groups.get_matrix_elements()]) 7194 self._curr_matrix_elements = subproc_groups 7195 # assign a unique id number to all groups 7196 uid = 0 7197 for group in subproc_groups: 7198 uid += 1 # update the identification number 7199 for me in group.get('matrix_elements'): 7200 me.get('processes')[0].set('uid', uid) 7201 else: # Not grouped subprocesses 7202 mode = {} 7203 if self._export_format in [ 'standalone_msP' , 7204 'standalone_msF', 'standalone_rw']: 7205 mode['mode'] = 'MadSpin' 7206 # The conditional statement tests whether we are dealing 7207 # with a loop induced process. 7208 if isinstance(self._curr_amps[0], 7209 loop_diagram_generation.LoopAmplitude): 7210 mode['optimized_output']=self.options['loop_optimized_output'] 7211 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess 7212 compute_loop_nc = True 7213 else: 7214 HelasMultiProcessClass = helas_objects.HelasMultiProcess 7215 compute_loop_nc = False 7216 7217 self._curr_matrix_elements = HelasMultiProcessClass( 7218 self._curr_amps, compute_loop_nc=compute_loop_nc, 7219 matrix_element_opts=mode) 7220 7221 ndiags = sum([len(me.get('diagrams')) for \ 7222 me in self._curr_matrix_elements.\ 7223 get_matrix_elements()]) 7224 # assign a unique id number to all process 7225 uid = 0 7226 for me in self._curr_matrix_elements.get_matrix_elements()[:]: 7227 uid += 1 # update the identification number 7228 me.get('processes')[0].set('uid', uid) 7229 7230 cpu_time2 = time.time() 7231 7232 7233 return ndiags, cpu_time2 - cpu_time1
7234 7235 # Start of the actual routine 7236 7237 ndiags, cpu_time = generate_matrix_elements(self,group_processes) 7238 7239 calls = 0 7240 7241 path = self._export_dir 7242 if self._export_format in ['standalone_cpp', 'madevent', 'standalone', 7243 'standalone_msP', 'standalone_msF', 'standalone_rw', 7244 'matchbox_cpp', 'madweight', 'matchbox']: 7245 path = pjoin(path, 'SubProcesses') 7246 7247 cpu_time1 = time.time() 7248 7249 # First treat madevent and pythia8 exports, where we need to 7250 # distinguish between grouped and ungrouped subprocesses 7251 7252 # MadEvent 7253 if self._export_format == 'madevent': 7254 calls += self._curr_exporter.export_processes(self._curr_matrix_elements, 7255 self._curr_fortran_model) 7256 7257 # Write the procdef_mg5.dat file with process info 7258 card_path = pjoin(path, os.path.pardir, 'SubProcesses', \ 7259 'procdef_mg5.dat') 7260 if self._generate_info: 7261 self._curr_exporter.write_procdef_mg5(card_path, 7262 self._curr_model['name'], 7263 self._generate_info) 7264 try: 7265 cmd.Cmd.onecmd(self, 'history .') 7266 except Exception: 7267 misc.sprint('command history fails.', 10) 7268 pass 7269 7270 # Pythia 8 7271 if self._export_format == 'pythia8': 7272 # Output the process files 7273 process_names = [] 7274 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList): 7275 for (group_number, me_group) in enumerate(self._curr_matrix_elements): 7276 exporter = export_cpp.generate_process_files_pythia8(\ 7277 me_group.get('matrix_elements'), self._curr_cpp_model, 7278 process_string = me_group.get('name'), 7279 process_number = group_number, path = path, 7280 version = version) 7281 process_names.append(exporter.process_name) 7282 else: 7283 exporter = export_cpp.generate_process_files_pythia8(\ 7284 self._curr_matrix_elements, self._curr_cpp_model, 7285 process_string = self._generate_info, path = path) 7286 process_names.append(exporter.process_file_name) 7287 7288 # Output the model parameter and ALOHA files 7289 model_name, model_path = exporter.convert_model_to_pythia8(\ 7290 self._curr_model, self._export_dir) 7291 7292 # Generate the main program file 7293 filename, make_filename = \ 7294 export_cpp.generate_example_file_pythia8(path, 7295 model_path, 7296 process_names, 7297 exporter, 7298 main_file_name) 7299 7300 # Pick out the matrix elements in a list 7301 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 7302 7303 # Fortran MadGraph MadWeight 7304 if self._export_format == 'madweight': 7305 7306 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList): 7307 #remove the merging between electron and muon 7308 self._curr_matrix_elements = self._curr_matrix_elements.split_lepton_grouping() 7309 7310 for (group_number, me_group) in enumerate(self._curr_matrix_elements): 7311 calls = calls + \ 7312 self._curr_exporter.generate_subprocess_directory_v4(\ 7313 me_group, self._curr_fortran_model, 7314 group_number) 7315 else: 7316 for me_number, me in \ 7317 enumerate(self._curr_matrix_elements.get_matrix_elements()): 7318 calls = calls + \ 7319 self._curr_exporter.generate_subprocess_directory_v4(\ 7320 me, self._curr_fortran_model, me_number) 7321 7322 # Fortran MadGraph5_aMC@NLO Standalone 7323 if self._export_format in ['standalone', 'standalone_msP', 7324 'standalone_msF', 'standalone_rw', 'matchbox']: 7325 for me in matrix_elements[:]: 7326 new_calls = self._curr_exporter.generate_subprocess_directory_v4(\ 7327 me, self._curr_fortran_model) 7328 if not new_calls: 7329 matrix_elements.remove(me) 7330 calls = calls + new_calls 7331 7332 # Just the matrix.f files 7333 if self._export_format == 'matrix': 7334 for me in matrix_elements: 7335 filename = pjoin(path, 'matrix_' + \ 7336 me.get('processes')[0].shell_string() + ".f") 7337 if os.path.isfile(filename): 7338 logger.warning("Overwriting existing file %s" % filename) 7339 else: 7340 logger.info("Creating new file %s" % filename) 7341 calls = calls + self._curr_exporter.write_matrix_element_v4(\ 7342 writers.FortranWriter(filename),\ 7343 me, self._curr_fortran_model) 7344 7345 # C++ standalone 7346 if self._export_format in ['standalone_cpp', 'matchbox_cpp']: 7347 for me in matrix_elements: 7348 export_cpp.generate_subprocess_directory_standalone_cpp(\ 7349 me, self._curr_cpp_model, 7350 path = path, 7351 format=self._export_format) 7352 7353 cpu_time2 = time.time() - cpu_time1 7354 7355 logger.info(("Generated helas calls for %d subprocesses " + \ 7356 "(%d diagrams) in %0.3f s") % \ 7357 (len(matrix_elements), 7358 ndiags, cpu_time)) 7359 7360 if calls: 7361 if "cpu_time2" in locals(): 7362 logger.info("Wrote files for %d helas calls in %0.3f s" % \ 7363 (calls, cpu_time2)) 7364 else: 7365 logger.info("Wrote files for %d helas calls" % \ 7366 (calls)) 7367 7368 if self._export_format == 'pythia8': 7369 logger.info("- All necessary files for Pythia 8 generated.") 7370 logger.info("- Run \"launch\" and select %s.cc," % filename) 7371 logger.info(" or go to %s/examples and run" % path) 7372 logger.info(" make -f %s" % make_filename) 7373 logger.info(" (with process_name replaced by process name).") 7374 logger.info(" You can then run ./%s to produce events for the process" % \ 7375 filename) 7376 7377 # Replace the amplitudes with the actual amplitudes from the 7378 # matrix elements, which allows proper diagram drawing also of 7379 # decay chain processes 7380 self._curr_amps = diagram_generation.AmplitudeList(\ 7381 [me.get('base_amplitude') for me in \ 7382 matrix_elements]) 7383
7384 - def finalize(self, nojpeg, online = False, flaglist=[]):
7385 """Make the html output, write proc_card_mg5.dat and create 7386 madevent.tar.gz for a MadEvent directory""" 7387 7388 compiler_dict = {'fortran': self.options['fortran_compiler'], 7389 'cpp': self.options['cpp_compiler'], 7390 'f2py': self.options['f2py_compiler']} 7391 7392 7393 if self._export_format in ['madevent', 'standalone', 'standalone_msP', 7394 'standalone_msF', 'standalone_rw', 'NLO', 'madweight', 7395 'matchbox']: 7396 7397 # For v4 models, copy the model/HELAS information. 7398 if self._model_v4_path: 7399 logger.info('Copy %s model files to directory %s' % \ 7400 (os.path.basename(self._model_v4_path), self._export_dir)) 7401 self._curr_exporter.export_model_files(self._model_v4_path) 7402 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS')) 7403 else: 7404 logger.info('Export UFO model to MG4 format') 7405 # wanted_lorentz are the lorentz structures which are 7406 # actually used in the wavefunctions and amplitudes in 7407 # these processes 7408 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 7409 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 7410 # For a unique output of multiple type of exporter need to store this 7411 # information. 7412 if hasattr(self, 'previous_lorentz'): 7413 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz)) 7414 wanted_couplings = list(set(self.previous_couplings + wanted_couplings)) 7415 del self.previous_lorentz 7416 del self.previous_couplings 7417 if 'store_model' in flaglist: 7418 self.previous_lorentz = wanted_lorentz 7419 self.previous_couplings = wanted_couplings 7420 else: 7421 self._curr_exporter.convert_model_to_mg4(self._curr_model, 7422 wanted_lorentz, 7423 wanted_couplings) 7424 if self._export_format in ['standalone_cpp', 'matchbox_cpp']: 7425 logger.info('Export UFO model to C++ format') 7426 # wanted_lorentz are the lorentz structures which are 7427 # actually used in the wavefunctions and amplitudes in 7428 # these processes 7429 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 7430 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 7431 export_cpp.convert_model_to_cpp(self._curr_model, 7432 pjoin(self._export_dir), 7433 wanted_lorentz, 7434 wanted_couplings) 7435 export_cpp.make_model_cpp(self._export_dir) 7436 7437 7438 elif self._export_format in ['NLO']: 7439 ## write fj_lhapdf_opts file 7440 devnull = os.open(os.devnull, os.O_RDWR) 7441 try: 7442 res = misc.call([self.options['lhapdf'], '--version'], \ 7443 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 7444 except Exception: 7445 res = 1 7446 if res != 0: 7447 logger.info('The value for lhapdf in the current configuration does not ' + \ 7448 'correspond to a valid executable.\nPlease set it correctly either in ' + \ 7449 'input/mg5_configuration or with "set lhapdf /path/to/lhapdf-config" ' + \ 7450 'and regenrate the process. \nTo avoid regeneration, edit the ' + \ 7451 ('%s/Cards/amcatnlo_configuration.txt file.\n' % self._export_dir ) + \ 7452 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n') 7453 7454 7455 7456 self._curr_exporter.finalize_fks_directory( \ 7457 self._curr_matrix_elements, 7458 self.history, 7459 not nojpeg, 7460 online, 7461 compiler_dict, 7462 output_dependencies = self.options['output_dependencies'], 7463 MG5DIR = MG5DIR) 7464 7465 # Create configuration file [path to executable] for amcatnlo 7466 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt') 7467 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path', 7468 'hepmc_path'] 7469 to_keep = {} 7470 for opt in opts_to_keep: 7471 if self.options[opt]: 7472 to_keep[opt] = self.options[opt] 7473 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \ 7474 to_keep = to_keep) 7475 7476 elif self._export_format in ['madevent', 'madweight']: 7477 # Create configuration file [path to executable] for madevent 7478 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt') 7479 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, 7480 to_keep={'mg5_path':MG5DIR}) 7481 7482 if self._export_format in ['madevent', 'standalone', 'standalone_msP', 'standalone_msF', 7483 'standalone_rw', 'madweight', 'matchbox']: 7484 7485 self._curr_exporter.finalize_v4_directory( \ 7486 self._curr_matrix_elements, 7487 self.history, 7488 not nojpeg, 7489 online, 7490 compiler_dict) 7491 7492 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']: 7493 logger.info('Output to directory ' + self._export_dir + ' done.') 7494 7495 if self._export_format in ['madevent', 'NLO']: 7496 logger.info('Type \"launch\" to generate events from this process, or see') 7497 logger.info(self._export_dir + '/README') 7498 logger.info('Run \"open index.html\" to see more information about this process.')
7499
7500 - def do_help(self, line):
7501 """ propose some usefull possible action """ 7502 7503 super(MadGraphCmd,self).do_help(line) 7504 7505 if line: 7506 return 7507 7508 if len(self.history) == 0: 7509 last_action_2 = 'mg5_start' 7510 last_action = 'mg5_start' 7511 else: 7512 args = self.history[-1].split() 7513 last_action = args[0] 7514 if len(args)>1: 7515 last_action_2 = '%s %s' % (last_action, args[1]) 7516 else: 7517 last_action_2 = 'none'
7518 7519 7520 7521 # Calculate decay width
7522 - def do_compute_widths(self, line, model=None, do2body=True):
7523 """Documented commands:Generate amplitudes for decay width calculation, with fixed 7524 number of final particles (called level) 7525 syntax; compute_widths particle [other particles] [--options=] 7526 7527 - particle/other particles can also be multiparticle name (can also be 7528 pid of the particle) 7529 7530 --body_decay=X [default=4.0025] allow to choose the precision. 7531 if X is an integer: compute all X body decay 7532 if X is a float <1: compute up to the time that total error < X 7533 if X is a float >1: stops at the first condition. 7534 7535 --path=X. Use a given file for the param_card. (default UFO built-in) 7536 7537 special argument: 7538 - skip_2body: allow to not consider those decay (use FR) 7539 - model: use the model pass in argument. 7540 7541 """ 7542 7543 7544 7545 self.change_principal_cmd('MadGraph') 7546 if '--nlo' not in line: 7547 warning_text = """Please note that the automatic computation of the width is 7548 only valid in narrow-width approximation and at tree-level.""" 7549 logger.warning(warning_text) 7550 7551 if not model: 7552 modelname = self._curr_model.get('modelpath+restriction') 7553 with misc.MuteLogger(['madgraph'], ['INFO']): 7554 model = import_ufo.import_model(modelname, decay=True) 7555 else: 7556 self._curr_model = model 7557 self._curr_fortran_model = \ 7558 helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 7559 if not isinstance(model, model_reader.ModelReader): 7560 model = model_reader.ModelReader(model) 7561 7562 if '--nlo' in line: 7563 # call SMWidth to calculate NLO Width 7564 self.compute_widths_SMWidth(line, model=model) 7565 return 7566 7567 # check the argument and return those in a dictionary format 7568 particles, opts = self.check_compute_widths(self.split_arg(line)) 7569 7570 if opts['path']: 7571 correct = True 7572 param_card = check_param_card.ParamCard(opts['path']) 7573 for param in param_card['decay']: 7574 if param.value == "auto": 7575 param.value = 1 7576 param.format = 'float' 7577 correct = False 7578 if not correct: 7579 if opts['output']: 7580 param_card.write(opts['output']) 7581 opts['path'] = opts['output'] 7582 else: 7583 param_card.write(opts['path']) 7584 7585 data = model.set_parameters_and_couplings(opts['path']) 7586 7587 # find UFO particles linked to the require names. 7588 if do2body: 7589 skip_2body = True 7590 decay_info = {} 7591 for pid in particles: 7592 particle = model.get_particle(pid) 7593 if not hasattr(particle, 'partial_widths'): 7594 skip_2body = False 7595 break 7596 elif not decay_info: 7597 logger_mg.info('Get two body decay from FeynRules formula') 7598 decay_info[pid] = [] 7599 mass = abs(eval(str(particle.get('mass')), data).real) 7600 data = model.set_parameters_and_couplings(opts['path'], scale= mass) 7601 total = 0 7602 7603 for mode, expr in particle.partial_widths.items(): 7604 tmp_mass = mass 7605 for p in mode: 7606 try: 7607 value_mass = eval(str(p.mass), data) 7608 except Exception: 7609 # the p object can still be UFO reference. since the 7610 # mass name might hve change load back the MG5 one. 7611 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data) 7612 tmp_mass -= abs(value_mass) 7613 if tmp_mass <=0: 7614 continue 7615 7616 decay_to = [p.get('pdg_code') for p in mode] 7617 value = eval(expr,{'cmath':cmath},data).real 7618 if -1e-10 < value < 0: 7619 value = 0 7620 if -1e-5 < value < 0: 7621 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' % 7622 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 7623 value = 0 7624 elif value < 0: 7625 raise Exception, 'Partial width for %s > %s negative: %s' % \ 7626 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value) 7627 elif value < 0.1 and particle['color'] !=1: 7628 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 7629 % (particle.get('name'), value, decay_to)) 7630 value = 0 7631 7632 decay_info[particle.get('pdg_code')].append([decay_to, value]) 7633 total += value 7634 else: 7635 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 7636 opts['path'], opts['output']) 7637 if float(opts['body_decay']) == 2: 7638 return 7639 else: 7640 skip_2body = True 7641 7642 # 7643 # add info from decay module 7644 # 7645 self.do_decay_diagram('%s %s' % (' '.join([`id` for id in particles]), 7646 ' '.join('--%s=%s' % (key,value) 7647 for key,value in opts.items() 7648 if key not in ['precision_channel']) 7649 ), skip_2body=skip_2body) 7650 7651 if self._curr_amps: 7652 logger.info('Pass to numerical integration for computing the widths:') 7653 else: 7654 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output']) 7655 7656 7657 7658 return 7659 7660 # Do the MadEvent integration!! 7661 with misc.TMP_directory(dir=os.getcwd()) as path: 7662 decay_dir = pjoin(path,'temp_decay') 7663 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir)) 7664 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]): 7665 self.exec_cmd('output %s -f' % decay_dir) 7666 # Need to write the correct param_card in the correct place !!! 7667 if os.path.exists(opts['output']): 7668 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 7669 else: 7670 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 7671 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 7672 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat')) 7673 # call a ME interface and define as it as child for correct error handling 7674 me_cmd = madevent_interface.MadEventCmd(decay_dir) 7675 #self.define_child_cmd_interface(me_cmd, interface=False) 7676 me_cmd.model_name = self._curr_model['name'] #needed for mssm 7677 me_cmd.options['automatic_html_opening'] = False 7678 7679 me_opts=[('accuracy', opts['precision_channel']), # default 0.01 7680 ('points', 1000), 7681 ('iterations',9)] 7682 me_cmd.exec_cmd('survey decay -f %s' % ( 7683 " ".join(['--%s=%s' % val for val in me_opts])), 7684 postcmd=False) 7685 me_cmd.exec_cmd('combine_events', postcmd=False) 7686 #me_cmd.exec_cmd('store_events', postcmd=False) 7687 me_cmd.collect_decay_widths() 7688 me_cmd.do_quit('') 7689 # cleaning 7690 del me_cmd 7691 7692 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat')) 7693 7694 for pid in particles: 7695 width = param['decay'].get((pid,)).value 7696 particle = self._curr_model.get_particle(pid) 7697 #if particle['color'] !=1 and 0 < width.real < 0.1: 7698 # logger.warning("width of colored particle \"%s(%s)\" lower than QCD scale: %s. Set width to zero " 7699 # % (particle.get('name'), pid, width.real)) 7700 # width = 0 7701 7702 7703 if not pid in param['decay'].decay_table: 7704 continue 7705 if pid not in decay_info: 7706 decay_info[pid] = [] 7707 for BR in param['decay'].decay_table[pid]: 7708 if len(BR.lhacode) == 3 and skip_2body: 7709 continue 7710 if BR.value * width <0.1 and particle['color'] !=1: 7711 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 7712 % (particle.get('name'), BR.value * width, BR.lhacode[1:])) 7713 7714 continue 7715 7716 decay_info[pid].append([BR.lhacode[1:], BR.value * width]) 7717 7718 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 7719 opts['path'], opts['output']) 7720 7721 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 7722 check_param_card.convert_to_slha1(opts['output']) 7723 return
7724 7725 7726 7727 # Calculate decay width with SMWidth
7728 - def compute_widths_SMWidth(self, line, model=None):
7729 """Compute widths with SMWidth. 7730 """ 7731 7732 # check the argument and return those in a dictionary format 7733 particles, opts = self.check_compute_widths(self.split_arg(line)) 7734 7735 if opts['path']: 7736 correct = True 7737 param_card = check_param_card.ParamCard(opts['path']) 7738 for param in param_card['decay']: 7739 if param.value == "auto": 7740 param.value = 1 7741 param.format = 'float' 7742 correct = False 7743 if not correct: 7744 if opts['output']: 7745 param_card.write(opts['output']) 7746 opts['path'] = opts['output'] 7747 else: 7748 param_card.write(opts['path']) 7749 7750 if not model: 7751 model_path = self._curr_model.get('modelpath') 7752 model_name = self._curr_model.get('name') 7753 currmodel = self._curr_model 7754 else: 7755 model_path = model.get('modelpath') 7756 model_name = model.get('name') 7757 currmodel = model 7758 7759 if not os.path.exists(pjoin(model_path, 'SMWidth')): 7760 raise self.InvalidCmd, "Model %s is not valid for computing NLO width with SMWidth"%model_name 7761 7762 # determine the EW scheme 7763 externparam = [(param.lhablock.lower(),param.name.lower()) for param \ 7764 in currmodel.get('parameters')[('external',)]] 7765 7766 if ('sminputs','aewm1') in externparam: 7767 # alpha(MZ) scheme 7768 arg2 = "1" 7769 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam: 7770 # Gmu scheme 7771 arg2 = "2" 7772 else: 7773 raise Exception, "Do not know the EW scheme in the model %s"%model_name 7774 7775 #compile the code 7776 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')): 7777 logger.info('Compiling SMWidth. This has to be done only once and'+\ 7778 ' can take a couple of minutes.','$MG:color:BLACK') 7779 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth', 7780 'makefile_MW5')) 7781 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \ 7782 self.options_configuration['fortran_compiler'] 7783 if current != new: 7784 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current) 7785 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current) 7786 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current) 7787 misc.compile(cwd=pjoin(model_path, 'SMWidth')) 7788 7789 # look for the ident_card.dat 7790 identpath=" " 7791 carddir=os.path.dirname(opts['path']) 7792 if 'ident_card.dat' in os.listdir(carddir): 7793 identpath=pjoin(carddir,'ident_card.dat') 7794 #run the code 7795 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2], 7796 stdout=subprocess.PIPE, 7797 stdin=subprocess.PIPE, 7798 cwd=pjoin(model_path, 'SMWidth')).communicate() 7799 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I) 7800 width_list = pattern.findall(output) 7801 width_dict = {} 7802 for pid,width in width_list: 7803 width_dict[int(pid)] = float(width) 7804 7805 for pid in particles: 7806 if not pid in width_dict: 7807 width = 0 7808 else: 7809 width = width_dict[pid] 7810 param = param_card['decay'].get((pid,)) 7811 param.value = width 7812 param.format = 'float' 7813 if pid not in param_card['decay'].decay_table: 7814 continue 7815 del param_card['decay'].decay_table[pid] # reset the BR 7816 # write the output file. (the new param_card) 7817 if opts['output']: 7818 param_card.write(opts['output']) 7819 logger.info('Results are written in %s' % opts['output']) 7820 else: 7821 param_card.write(opts['path']) 7822 logger.info('Results are written in %s' % opts['path']) 7823 return
7824 7825 # Calculate decay width
7826 - def do_decay_diagram(self, line, skip_2body=False, model=None):
7827 """Not in help: Generate amplitudes for decay width calculation, with fixed 7828 number of final particles (called level) 7829 syntax; decay_diagram part_name level param_path 7830 args; part_name level param_path 7831 part_name = name of the particle you want to calculate width 7832 level = a.) when level is int, 7833 it means the max number of decay products 7834 b.) when level is float, 7835 it means the required precision for width. 7836 param_path = path for param_card 7837 (this is necessary to determine whether a channel is onshell or not) 7838 e.g. calculate width for higgs up to 2-body decays. 7839 calculate_width h 2 [path] 7840 N.B. param_card must be given so that the program knows which channel 7841 is on shell and which is not. 7842 7843 special argument: 7844 - skip_2body: allow to not consider those decay (use FR) 7845 - model: use the model pass in argument. 7846 """ 7847 7848 if model: 7849 self._curr_model = model 7850 7851 args = self.split_arg(line) 7852 #check the validity of the arguments 7853 particles, args = self.check_decay_diagram(args) 7854 #print args 7855 pids = particles 7856 level = float(args['body_decay']) 7857 param_card_path = args['path'] 7858 min_br = float(args['min_br']) 7859 7860 # Reset amplitudes 7861 self._curr_amps = diagram_generation.AmplitudeList() 7862 # Reset Helas matrix elements 7863 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7864 # Reset _done_export, since we have new process 7865 self._done_export = False 7866 # Also reset _export_format and _export_dir 7867 self._export_format = None 7868 7869 7870 # Setup before find_channels 7871 if not model: 7872 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model, 7873 True) 7874 self._curr_decaymodel.read_param_card(param_card_path) 7875 else: 7876 self._curr_decaymodel = model 7877 model = self._curr_decaymodel 7878 7879 if isinstance(pids, int): 7880 pids = [pids] 7881 7882 first =True 7883 for part_nb,pid in enumerate(pids): 7884 part = self._curr_decaymodel.get_particle(pid) 7885 if part.get('width').lower() == 'zero': 7886 continue 7887 logger_mg.info('get decay diagram for %s' % part['name']) 7888 # Find channels as requested 7889 if level // 1 == level and level >1: 7890 level = int(level) 7891 self._curr_decaymodel.find_channels(part, level, min_br) 7892 if not skip_2body: 7893 amp = part.get_amplitudes(2) 7894 if amp: 7895 self._curr_amps.extend(amp) 7896 7897 for l in range(3, level+1): 7898 amp = part.get_amplitudes(l) 7899 if amp: 7900 self._curr_amps.extend(amp) 7901 else: 7902 max_level = level // 1 7903 if max_level < 2: 7904 max_level = 999 7905 precision = level % 1 7906 if first: 7907 model.find_all_channels(2,generate_abstract=False) 7908 first = False 7909 if not skip_2body: 7910 amp = part.get_amplitudes(2) 7911 if amp: 7912 self._curr_amps.extend(amp) 7913 clevel = 2 7914 while part.get('apx_decaywidth_err').real > precision: 7915 clevel += 1 7916 if clevel > max_level: 7917 logger_mg.info(' stop to %s body-decay. approximate error: %s' % 7918 (max_level, part.get('apx_decaywidth_err')) ) 7919 break 7920 if clevel > 3: 7921 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\ 7922 (part.get('apx_decaywidth_err'), clevel)) 7923 part.find_channels_nextlevel(model, min_br) 7924 #part.group_channels_2_amplitudes(clevel, model, min_br) 7925 amp = part.get_amplitudes(clevel) 7926 if amp: 7927 self._curr_amps.extend(amp) 7928 part.update_decay_attributes(False, True, True, model) 7929 7930 7931 # Set _generate_info 7932 if len(self._curr_amps) > 0: 7933 process = self._curr_amps[0]['process'].nice_string() 7934 #print process 7935 self._generate_info = process[9:] 7936 #print self._generate_info 7937 else: 7938 logger.info("No decay is found")
7939
7940 -class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd):
7941 """Temporary parser"""
7942 7943 #=============================================================================== 7944 # Command Parser 7945 #=============================================================================== 7946 # DRAW 7947 _draw_usage = "draw FILEPATH [options]\n" + \ 7948 "-- draw the diagrams in eps format\n" + \ 7949 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \ 7950 " Example: draw plot_dir . \n" 7951 _draw_parser = misc.OptionParser(usage=_draw_usage) 7952 _draw_parser.add_option("", "--horizontal", default=False, 7953 action='store_true', help="force S-channel to be horizontal") 7954 _draw_parser.add_option("", "--external", default=0, type='float', 7955 help="authorizes external particles to end at top or " + \ 7956 "bottom of diagram. If bigger than zero this tune the " + \ 7957 "length of those line.") 7958 _draw_parser.add_option("", "--max_size", default=1.5, type='float', 7959 help="this forbids external line bigger than max_size") 7960 _draw_parser.add_option("", "--non_propagating", default=True, \ 7961 dest="contract_non_propagating", action='store_false', 7962 help="avoid contractions of non propagating lines") 7963 _draw_parser.add_option("", "--add_gap", default=0, type='float', \ 7964 help="set the x-distance between external particles") 7965 7966 # LAUNCH PROGRAM 7967 _launch_usage = "launch [DIRPATH] [options]\n" + \ 7968 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \ 7969 " By default DIRPATH is the latest created directory \n" + \ 7970 " (for pythia8, it should be the Pythia 8 main directory) \n" + \ 7971 " Example: launch PROC_sm_1 --name=run2 \n" + \ 7972 " Example: launch ../pythia8 \n" 7973 _launch_parser = misc.OptionParser(usage=_launch_usage) 7974 _launch_parser.add_option("-f", "--force", default=False, action='store_true', 7975 help="Use the card present in the directory in order to launch the different program") 7976 _launch_parser.add_option("-n", "--name", default='', type='str', 7977 help="Provide a name to the run (for madevent run)") 7978 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true', 7979 help="submit the job on the cluster") 7980 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true', 7981 help="submit the job on multicore core") 7982 7983 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true', 7984 help="Use Interactive Console [if available]") 7985 _launch_parser.add_option("-s", "--laststep", default='', 7986 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]") 7987 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true', 7988 help="Run the reweight module (reweighting by different model parameter") 7989 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', 7990 help="Run the madspin package")
7991 7992 #=============================================================================== 7993 # Interface for customize question. 7994 #=============================================================================== 7995 -class AskforCustomize(cmd.SmartQuestion):
7996 """A class for asking a question where in addition you can have the 7997 set command define and modifying the param_card/run_card correctly""" 7998
7999 - def __init__(self, question, allow_arg=[], default=None, 8000 mother_interface=None, *arg, **opt):
8001 8002 model_path = mother_interface._curr_model.get('modelpath') 8003 #2) Import the option available in the model 8004 ufo_model = ufomodels.load_model(model_path) 8005 self.all_categories = ufo_model.build_restrict.all_categories 8006 8007 question = self.get_question() 8008 # determine the possible value and how they are linked to the restriction 8009 #options. 8010 allow_arg = ['0'] 8011 self.name2options = {} 8012 for category in self.all_categories: 8013 for options in category: 8014 if not options.first: 8015 continue 8016 self.name2options[str(len(allow_arg))] = options 8017 self.name2options[options.name.replace(' ','')] = options 8018 allow_arg.append(len(allow_arg)) 8019 allow_arg.append('done') 8020 8021 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8022 8023 8024
8025 - def default(self, line):
8026 """Default action if line is not recognized""" 8027 8028 line = line.strip() 8029 args = line.split() 8030 if line == '' and self.default_value is not None: 8031 self.value = self.default_value 8032 # check if input is a file 8033 elif hasattr(self, 'do_%s' % args[0]): 8034 self.do_set(' '.join(args[1:])) 8035 elif line.strip() != '0' and line.strip() != 'done' and \ 8036 str(line) != 'EOF' and line.strip() in self.allow_arg: 8037 option = self.name2options[line.strip()] 8038 option.status = not option.status 8039 self.value = 'repeat' 8040 else: 8041 self.value = line 8042 8043 return self.all_categories
8044
8045 - def reask(self, reprint_opt=True):
8046 """ """ 8047 reprint_opt = True 8048 self.question = self.get_question() 8049 cmd.SmartQuestion.reask(self, reprint_opt)
8050
8051 - def do_set(self, line):
8052 """ """ 8053 self.value = 'repeat' 8054 8055 args = line.split() 8056 if args[0] not in self.name2options: 8057 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' % 8058 (args[0], ', '.join(self.name2options.keys()) )) 8059 return 8060 elif len(args) != 2: 8061 logger.warning('Invalid set command. Not correct number of argument') 8062 return 8063 8064 8065 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']: 8066 self.name2options[args[0]].status = True 8067 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']: 8068 self.name2options[args[0]].status = False 8069 else: 8070 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8071 8072 8073
8074 - def get_question(self):
8075 """define the current question.""" 8076 question = '' 8077 i=0 8078 for category in self.all_categories: 8079 question += category.name + ':\n' 8080 for options in category: 8081 if not options.first: 8082 continue 8083 i+=1 8084 question += ' %s: %s [%s]\n' % (i, options.name, 8085 options.display(options.status)) 8086 question += 'Enter a number to change it\'s status or press enter to validate.\n' 8087 question += 'For scripting this function, please type: \'help\'' 8088 return question
8089 8090
8091 - def complete_set(self, text, line, begidx, endidx):
8092 """ Complete the set command""" 8093 signal.alarm(0) # avoid timer if any 8094 args = self.split_arg(line[0:begidx]) 8095 8096 if len(args) == 1: 8097 possibilities = [x for x in self.name2options if not x.isdigit()] 8098 return self.list_completion(text, possibilities, line) 8099 else: 8100 return self.list_completion(text,['True', 'False'], line)
8101 8102
8103 - def do_help(self, line):
8104 '''help message''' 8105 8106 print 'This allows you to optimize your model to your needs.' 8107 print 'Enter the number associate to the possible restriction/add-on' 8108 print ' to change the status of this restriction/add-on.' 8109 print '' 8110 print 'In order to allow scripting of this function you can use the ' 8111 print 'function \'set\'. This function takes two argument:' 8112 print 'set NAME VALUE' 8113 print ' NAME is the description of the option where you remove all spaces' 8114 print ' VALUE is either True or False' 8115 print ' Example: For the question' 8116 print ''' sm customization: 8117 1: diagonal ckm [True] 8118 2: c mass = 0 [True] 8119 3: b mass = 0 [False] 8120 4: tau mass = 0 [False] 8121 5: muon mass = 0 [True] 8122 6: electron mass = 0 [True] 8123 Enter a number to change it's status or press enter to validate.''' 8124 print ''' you can answer by''' 8125 print ' set diagonalckm False' 8126 print ' set taumass=0 True'
8127
8128 - def cmdloop(self, intro=None):
8129 cmd.SmartQuestion.cmdloop(self, intro) 8130 return self.all_categories
8131 8132 8133 8134 #=============================================================================== 8135 # __main__ 8136 #=============================================================================== 8137 8138 if __name__ == '__main__': 8139 8140 run_option = sys.argv 8141 if len(run_option) > 1: 8142 # The first argument of sys.argv is the name of the program 8143 input_file = open(run_option[1], 'rU') 8144 cmd_line = MadGraphCmd(stdin=input_file) 8145 cmd_line.use_rawinput = False #put it in non interactive mode 8146 cmd_line.cmdloop() 8147 else: 8148 # Interactive mode 8149 MadGraphCmd().cmdloop() 8150