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  from __future__ import absolute_import 
  21  from __future__ import print_function 
  22  import atexit 
  23  import collections 
  24  import cmath 
  25  import glob 
  26  import logging 
  27  import optparse 
  28  import os 
  29  import pydoc 
  30  import random 
  31  import re 
  32  import signal 
  33  import subprocess 
  34  import copy 
  35  import sys 
  36  import shutil 
  37   
  38  import traceback 
  39  import time 
  40  import inspect 
  41  import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error 
  42  import random 
  43  import six 
  44  StringIO = six 
  45  from six.moves import range 
  46   
  47  #useful shortcut 
  48  pjoin = os.path.join 
  49   
  50  try: 
  51      import readline 
  52      GNU_SPLITTING = ('GNU' in readline.__doc__) 
  53  except: 
  54      GNU_SPLITTING = True 
  55   
  56  import aloha 
  57  import madgraph 
  58  from madgraph import MG4DIR, MG5DIR, MadGraph5Error 
  59   
  60   
  61  import madgraph.core.base_objects as base_objects 
  62  import madgraph.core.diagram_generation as diagram_generation 
  63  import madgraph.loop.loop_diagram_generation as loop_diagram_generation 
  64  import madgraph.loop.loop_base_objects as loop_base_objects 
  65  import madgraph.core.drawing as draw_lib 
  66  import madgraph.core.helas_objects as helas_objects 
  67   
  68   
  69   
  70  import madgraph.iolibs.drawing_eps as draw 
  71  import madgraph.iolibs.export_cpp as export_cpp 
  72  import madgraph.iolibs.export_v4 as export_v4 
  73  import madgraph.iolibs.helas_call_writers as helas_call_writers 
  74  import madgraph.iolibs.file_writers as writers 
  75  import madgraph.iolibs.files as files 
  76  import madgraph.iolibs.group_subprocs as group_subprocs 
  77  import madgraph.iolibs.import_v4 as import_v4 
  78  import madgraph.iolibs.save_load_object as save_load_object 
  79   
  80  import madgraph.interface.extended_cmd as cmd 
  81  import madgraph.interface.tutorial_text as tutorial_text 
  82  import madgraph.interface.tutorial_text_nlo as tutorial_text_nlo 
  83  import madgraph.interface.tutorial_text_madloop as tutorial_text_madloop 
  84  import madgraph.interface.launch_ext_program as launch_ext 
  85  import madgraph.interface.madevent_interface as madevent_interface 
  86  import madgraph.interface.amcatnlo_run_interface as amcatnlo_run 
  87   
  88  import madgraph.loop.loop_exporters as loop_exporters 
  89  import madgraph.loop.loop_helas_objects as loop_helas_objects 
  90   
  91  import madgraph.various.process_checks as process_checks 
  92  import madgraph.various.banner as banner_module 
  93  import madgraph.various.misc as misc 
  94  import madgraph.various.cluster as cluster 
  95   
  96  import models as ufomodels 
  97  import models.import_ufo as import_ufo 
  98  import models.write_param_card as param_writer 
  99  import models.check_param_card as check_param_card 
 100  import models.model_reader as model_reader 
 101   
 102  import aloha.aloha_fct as aloha_fct 
 103  import aloha.create_aloha as create_aloha 
 104  import aloha.aloha_lib as aloha_lib 
 105   
 106  import mg5decay.decay_objects as decay_objects 
 107   
 108   
 109  # Special logger for the Cmd Interface 
 110  logger = logging.getLogger('cmdprint') # -> stdout 
 111  logger_check = logging.getLogger('check') # -> stdout 
 112  logger_mg = logging.getLogger('madgraph.interface') # -> stdout 
 113  logger_stderr = logging.getLogger('fatalerror') # ->stderr 
 114  logger_tuto = logging.getLogger('tutorial') # -> stdout include instruction in 
 115                                              #order to learn MG5 
 116  logger_tuto_nlo = logging.getLogger('tutorial_aMCatNLO') # -> stdout include instruction in 
 117                                                          #order to learn aMC@NLO 
 118   
 119  logger_tuto_madloop = logging.getLogger('tutorial_MadLoop') # -> stoud for MadLoop tuto 
120 121 #=============================================================================== 122 # CmdExtended 123 #=============================================================================== 124 -class CmdExtended(cmd.Cmd):
125 """Particularisation of the cmd command for MG5""" 126 127 #suggested list of command 128 next_possibility = { 129 'start': ['import model ModelName', 'import command PATH', 130 'import proc_v4 PATH', 'tutorial'], 131 'import model' : ['generate PROCESS','define MULTIPART PART1 PART2 ...', 132 'display particles', 'display interactions'], 133 'define': ['define MULTIPART PART1 PART2 ...', 'generate PROCESS', 134 'display multiparticles'], 135 'generate': ['add process PROCESS','output [OUTPUT_TYPE] [PATH]','display diagrams'], 136 'add process':['output [OUTPUT_TYPE] [PATH]', 'display processes'], 137 'output':['launch','open index.html','history PATH', 'exit'], 138 'display': ['generate PROCESS', 'add process PROCESS', 'output [OUTPUT_TYPE] [PATH]'], 139 'import proc_v4' : ['launch','exit'], 140 'launch': ['open index.html','exit'], 141 'tutorial': ['generate PROCESS', 'import model MODEL', 'help TOPIC'] 142 } 143 144 debug_output = 'MG5_debug' 145 error_debug = 'Please report this bug on https://bugs.launchpad.net/mg5amcnlo\n' 146 error_debug += 'More information is found in \'%(debug)s\'.\n' 147 error_debug += 'Please attach this file to your report.' 148 149 config_debug = 'If you need help with this issue please contact us on https://answers.launchpad.net/mg5amcnlo\n' 150 151 keyboard_stop_msg = """stopping all operation 152 in order to quit mg5 please enter exit""" 153 154 # Define the Error Class # Define how error are handle 155 InvalidCmd = madgraph.InvalidCmd 156 ConfigurationError = MadGraph5Error 157 158 intro_banner = "************************************************************\n" + \ 159 "* *\n" + \ 160 "* W E L C O M E to *\n" + \ 161 "* M A D G R A P H 5 _ a M C @ N L O *\n" + \ 162 "* *\n" + \ 163 "* *\n" + \ 164 "* * * *\n" + \ 165 "* * * * * *\n" + \ 166 "* * * * * 5 * * * * *\n" + \ 167 "* * * * * *\n" + \ 168 "* * * *\n" + \ 169 "* *\n" + \ 170 "%s" + \ 171 "* *\n" + \ 172 "* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \ 173 "* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \ 174 "* and *\n" + \ 175 "* http://amcatnlo.web.cern.ch/amcatnlo/ *\n" + \ 176 "* *\n" + \ 177 "* Type 'help' for in-line help. *\n" + \ 178 "* Type 'tutorial' to learn how MG5 works *\n" + \ 179 "* Type 'tutorial aMCatNLO' to learn how aMC@NLO works *\n" + \ 180 "* Type 'tutorial MadLoop' to learn how MadLoop works *\n" + \ 181 "* *\n" + \ 182 "************************************************************" 183 184
185 - def __init__(self, *arg, **opt):
186 """Init history and line continuation""" 187 188 # If possible, build an info line with current version number 189 # and date, from the VERSION text file 190 info = misc.get_pkg_info() 191 info_line = "" 192 193 if 'version' in info and 'date' in info: 194 len_version = len(info['version']) 195 len_date = len(info['date']) 196 if len_version + len_date < 30: 197 info_line = "#* VERSION %s %s %s *\n" % \ 198 (info['version'], 199 (30 - len_version - len_date) * ' ', 200 info['date']) 201 202 if os.path.exists(pjoin(MG5DIR, '.bzr')): 203 proc = subprocess.Popen(['bzr', 'nick'], stdout=subprocess.PIPE,cwd=MG5DIR) 204 bzrname,_ = proc.communicate() 205 proc = subprocess.Popen(['bzr', 'revno'], stdout=subprocess.PIPE,cwd=MG5DIR) 206 bzrversion,_ = proc.communicate() 207 bzrname, bzrversion = bzrname.decode().strip(), bzrversion.decode().strip() 208 len_name = len(bzrname) 209 len_version = len(bzrversion) 210 info_line += "#* BZR %s %s %s *\n" % \ 211 (bzrname, 212 (34 - len_name - len_version) * ' ', 213 bzrversion) 214 215 # Create a header for the history file. 216 # Remember to fill in time at writeout time! 217 self.history_header = banner_module.ProcCard.history_header % {'info_line': info_line} 218 banner_module.ProcCard.history_header = self.history_header 219 220 if info_line: 221 info_line = info_line.replace("#*","*") 222 223 224 logger.info(self.intro_banner % info_line) 225 226 cmd.Cmd.__init__(self, *arg, **opt) 227 228 self.history = banner_module.ProcCard()
229 230
231 - def default(self, line):
232 """Default action if line is not recognized""" 233 234 # Faulty command 235 log=True 236 if line.startswith('p') or line.startswith('e'): 237 logger.warning("Command %s not recognized. Did you mean \'generate %s\'?. Please try again" % 238 (line.split()[0], line)) 239 log=False 240 return super(CmdExtended,self).default(line, log=log)
241
242 - def postcmd(self,stop, line):
243 """ finishing a command 244 This looks if the command add a special post part. 245 This looks if we have to write an additional text for the tutorial.""" 246 247 stop = super(CmdExtended, self).postcmd(stop, line) 248 # Print additional information in case of routines fails 249 if stop == False: 250 return False 251 252 args=line.split() 253 # Return for empty line 254 if len(args)==0: 255 return stop 256 257 # try to print linked to the first word in command 258 #as import_model,... if you don't find then try print with only 259 #the first word. 260 if len(args)==1: 261 command=args[0] 262 else: 263 command = args[0]+'_'+args[1].split('.')[0] 264 265 try: 266 logger_tuto.info(getattr(tutorial_text, command).replace('\n','\n\t')) 267 except Exception: 268 try: 269 logger_tuto.info(getattr(tutorial_text, args[0]).replace('\n','\n\t')) 270 except Exception: 271 pass 272 273 try: 274 logger_tuto_nlo.info(getattr(tutorial_text_nlo, command).replace('\n','\n\t')) 275 except Exception: 276 try: 277 logger_tuto_nlo.info(getattr(tutorial_text_nlo, args[0]).replace('\n','\n\t')) 278 except Exception: 279 pass 280 281 try: 282 logger_tuto_madloop.info(getattr(tutorial_text_madloop, command).replace('\n','\n\t')) 283 except Exception: 284 try: 285 logger_tuto_madloop.info(getattr(tutorial_text_madloop, args[0]).replace('\n','\n\t')) 286 except Exception: 287 pass 288 289 return stop
290 291
292 - def get_history_header(self):
293 """return the history header""" 294 return self.history_header % misc.get_time_info()
295
296 #=============================================================================== 297 # HelpToCmd 298 #=============================================================================== 299 -class HelpToCmd(cmd.HelpCmd):
300 """ The Series of help routine for the MadGraphCmd""" 301
302 - def help_save(self):
303 logger.info("syntax: save %s FILENAME" % "|".join(self._save_opts),'$MG:color:BLUE') 304 logger.info("-- save information as file FILENAME",'$MG:BOLD') 305 logger.info(" FILENAME is optional for saving 'options'.") 306 logger.info(' By default it uses ./input/mg5_configuration.txt') 307 logger.info(' If you put "global" for FILENAME it will use ~/.mg5/mg5_configuration.txt') 308 logger.info(' If this files exists, it is uses by all MG5 on the system but continues') 309 logger.info(' to read the local options files.')
310
311 - def help_load(self):
312 logger.info("syntax: load %s FILENAME" % "|".join(self._save_opts),'$MG:color:BLUE') 313 logger.info("-- load information from file FILENAME",'$MG:BOLD')
314
315 - def help_import(self):
316 logger.info("syntax: import " + "|".join(self._import_formats) + \ 317 " FILENAME",'$MG:color:BLUE') 318 logger.info("-- imports file(s) in various formats",'$MG:color:GREEN') 319 logger.info("") 320 logger.info(" import model MODEL[-RESTRICTION] [OPTIONS]:",'$MG:BOLD') 321 logger.info(" Import a UFO model.") 322 logger.info(" MODEL should be a valid UFO model name") 323 logger.info(" Model restrictions are specified by MODEL-RESTRICTION") 324 logger.info(" with the file restrict_RESTRICTION.dat in the model dir.") 325 logger.info(" By default, restrict_default.dat is used.") 326 logger.info(" Specify model_name-full to get unrestricted model.") 327 logger.info(" '--modelname' keeps the original particle names for the model") 328 logger.info("") 329 logger.info(" Type 'display modellist' to have the list of all model available.",'$MG:color:GREEN') 330 logger.info("") 331 logger.info(" import model_v4 MODEL [--modelname] :",'$MG:BOLD') 332 logger.info(" Import an MG4 model.") 333 logger.info(" Model should be the name of the model") 334 logger.info(" or the path to theMG4 model directory") 335 logger.info(" '--modelname' keeps the original particle names for the model") 336 logger.info("") 337 logger.info(" import proc_v4 [PATH] :",'$MG:BOLD') 338 logger.info(" Execute MG5 based on a proc_card.dat in MG4 format.") 339 logger.info(" Path to the proc_card is optional if you are in a") 340 logger.info(" madevent directory") 341 logger.info("") 342 logger.info(" import command PATH :",'$MG:BOLD') 343 logger.info(" Execute the list of command in the file at PATH") 344 logger.info("") 345 logger.info(" import banner PATH [--no_launch]:",'$MG:BOLD') 346 logger.info(" Rerun the exact same run define in the valid banner.")
347
348 - def help_install(self):
349 logger.info("syntax: install " + "|".join(self._install_opts),'$MG:color:BLUE') 350 logger.info("-- Download the last version of the program and install it") 351 logger.info(" locally in the current MadGraph5_aMC@NLO version. In order to have") 352 logger.info(" a successful installation, you will need to have an up-to-date") 353 logger.info(" F77 and/or C and Root compiler.") 354 logger.info(" ") 355 logger.info(" When installing any of the following programs:") 356 logger.info(" %s"%(', '.join(self._advanced_install_opts))) 357 logger.info(" The following options are available:") 358 logger.info(" --force Overwrite without asking any existing installation.") 359 logger.info(" --keep_source Keep a local copy of the sources of the tools MG5_aMC installed from.") 360 logger.info(" ") 361 logger.info(" \"install update\"",'$MG:BOLD') 362 logger.info(" check if your MG5 installation is the latest one.") 363 logger.info(" If not it load the difference between your current version and the latest one,") 364 logger.info(" and apply it to the code. Two options are available for this command:") 365 logger.info(" -f: didn't ask for confirmation if it founds an update.") 366 logger.info(" --timeout=: Change the maximum time allowed to reach the server.")
367
368 - def help_display(self):
369 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLUE') 370 logger.info("-- display a the status of various internal state variables") 371 logger.info(" for particles/interactions you can specify the name or id of the") 372 logger.info(" particles/interactions to receive more details information.") 373 logger.info(" Example: display particles e+.",'$MG:color:GREEN') 374 logger.info(" > For \"checks\", can specify only to see failed checks.") 375 logger.info(" > For \"diagrams\", you can specify where the file will be written.") 376 logger.info(" Example: display diagrams ./",'$MG:color:GREEN')
377 378
379 - def help_launch(self):
380 """help for launch command""" 381 # Using the built-in parser help is not convenient when one wants to use 382 # color schemes. 383 #_launch_parser.print_help() 384 logger.info("syntax: launch <dir_path> <options>",'$MG:color:BLUE') 385 logger.info("-- execute the aMC@NLO/madevent/standalone/pythia8 output present in dir_path",'$MG:BOLD') 386 logger.info("By default, dir_path points to the last created directory.") 387 logger.info("(for pythia8, it should be the Pythia 8 main directory)") 388 logger.info("") 389 logger.info("Launch on madevent/pythia8/standalone outputs:",'$MG:BOLD') 390 logger.info(" o Example: launch PROC_sm_1 --name=run2",'$MG:color:GREEN') 391 logger.info(" o Example: launch ../pythia8",'$MG:color:GREEN') 392 logger.info(" > Options:") 393 logger.info(" -h, --help show this help message and exit") 394 logger.info(" -f, --force Use the card present in the directory in order") 395 logger.info(" to launch the different program") 396 logger.info(" -n NAME, --name=NAME Provide a name to the run (for madevent run)") 397 logger.info(" -c, --cluster submit the job on the cluster") 398 logger.info(" -m, --multicore submit the job on multicore core") 399 logger.info(" -i, --interactive Use Interactive Console [if available]") 400 logger.info(" -s LASTSTEP, --laststep=LASTSTEP") 401 logger.info(" last program run in MadEvent run.") 402 logger.info(" [auto|parton|pythia|pgs|delphes]") 403 logger.info("") 404 logger.info("Launch on MadLoop standalone output:",'$MG:BOLD') 405 logger.info(" o Example: launch PROC_loop_sm_1 -f",'$MG:color:GREEN') 406 logger.info(" > Simple check of a single Phase-space points.") 407 logger.info(" > You will be asked whether you want to edit the MadLoop ") 408 logger.info(" and model param card as well as the PS point, unless ") 409 logger.info(" the -f option is specified. All other options are ") 410 logger.info(" irrelevant for this kind of launch.") 411 logger.info("") 412 logger.info("Launch on aMC@NLO output:",'$MG:BOLD') 413 logger.info(" > launch <dir_path> <mode> <options>",'$MG:color:BLUE') 414 logger.info(" o Example: launch MyProc aMC@NLO -f -p",'$MG:color:GREEN')
415
416 - def help_tutorial(self):
417 logger.info("syntax: tutorial [" + "|".join(self._tutorial_opts) + "]",'$MG:color:BLUE') 418 logger.info("-- start/stop the MG5 tutorial mode (or stop any other mode)") 419 logger.info("-- aMCatNLO: start aMC@NLO tutorial mode") 420 logger.info("-- MadLoop: start MadLoop tutorial mode")
421
422 - def help_open(self):
423 logger.info("syntax: open FILE ",'$MG:color:BLUE') 424 logger.info("-- open a file with the appropriate editor.",'$MG:BOLD') 425 logger.info(' If FILE belongs to index.html, param_card.dat, run_card.dat') 426 logger.info(' the path to the last created/used directory is used') 427 logger.info(' The program used to open those files can be chosen in the') 428 logger.info(' configuration file ./input/mg5_configuration.txt')
429
430 - def help_customize_model(self):
431 logger.info("syntax: customize_model --save=NAME",'$MG:color:BLUE') 432 logger.info("-- Open an invite where you options to tweak the model.",'$MG:BOLD') 433 logger.info(" If you specify the option --save=NAME, this tweak will be") 434 logger.info(" available for future import with the command 'import model XXXX-NAME'")
435
436 - def help_output(self):
437 logger.info("syntax: output [" + "|".join(self._export_formats) + \ 438 "] [path|.|auto] [options]",'$MG:color:BLUE') 439 logger.info("-- Output any generated process(es) to file.",'$MG:BOLD') 440 logger.info(" Default mode is madevent. Default path is \'.\' or auto.") 441 logger.info(" mode:",'$MG:BOLD') 442 logger.info(" - For MadLoop and aMC@NLO runs, there is only one mode and") 443 logger.info(" it is set by default.") 444 logger.info(" - If mode is madevent, create a MadEvent process directory.") 445 logger.info(" - If mode is standalone, create a Standalone directory") 446 logger.info(" - If mode is matrix, output the matrix.f files for all") 447 logger.info(" generated processes in directory \"path\".") 448 logger.info(" - If mode is standalone_cpp, create a standalone C++") 449 logger.info(" directory in \"path\".") 450 logger.info(" - If mode is pythia8, output all files needed to generate") 451 logger.info(" the processes using Pythia 8. The files are written in") 452 logger.info(" the Pythia 8 directory (default).") 453 logger.info(" NOTE: The Pythia 8 directory is set in the ./input/mg5_configuration.txt") 454 logger.info(" - If mode is aloha: Special syntax output:") 455 logger.info(" syntax: aloha [ROUTINE] [--options]" ) 456 logger.info(" valid options for aloha output are:") 457 logger.info(" --format=Fortran|Python|Cpp : defining the output language") 458 logger.info(" --output= : defining output directory") 459 logger.info(" path: The path of the process directory.",'$MG:BOLD') 460 logger.info(" If you put '.' as path, your pwd will be used.") 461 logger.info(" If you put 'auto', an automatic directory PROC_XX_n will be created.") 462 logger.info(" options:",'$MG:BOLD') 463 logger.info(" -f: force cleaning of the directory if it already exists") 464 logger.info(" -d: specify other MG/ME directory") 465 logger.info(" -noclean: no cleaning performed in \"path\".") 466 logger.info(" -nojpeg: no jpeg diagrams will be generated.") 467 logger.info(" --noeps=True: no jpeg and eps diagrams will be generated.") 468 logger.info(" -name: the postfix of the main file in pythia8 mode.") 469 logger.info(" Examples:",'$MG:color:GREEN') 470 logger.info(" output",'$MG:color:GREEN') 471 logger.info(" output standalone MYRUN -f",'$MG:color:GREEN') 472 logger.info(" output pythia8 ../pythia8/ -name qcdprocs",'$MG:color:GREEN')
473
474 - def help_check(self):
475 logger.info("syntax: check [" + "|".join(self._check_opts) + "] [param_card] process_definition [--energy=] [--split_orders=] [--reduction=]",'$MG:color:BLUE') 476 logger.info("-- check a process or set of processes.",'$MG:BOLD') 477 logger.info("General options:",'$MG:BOLD') 478 logger.info("o full:",'$MG:color:GREEN') 479 logger.info(" Perform all four checks described below:") 480 logger.info(" permutation, brs, gauge and lorentz_invariance.") 481 logger.info("o permutation:",'$MG:color:GREEN') 482 logger.info(" Check that the model and MG5 are working properly") 483 logger.info(" by generating permutations of the process and checking") 484 logger.info(" that the resulting matrix elements give the same value.") 485 logger.info("o gauge:",'$MG:color:GREEN') 486 logger.info(" Check that processes are gauge invariant by ") 487 logger.info(" comparing Feynman and unitary gauges.") 488 logger.info(" This check is, for now, not available for loop processes.") 489 logger.info("o brs:",'$MG:color:GREEN') 490 logger.info(" Check that the Ward identities are satisfied if the ") 491 logger.info(" process has at least one massless gauge boson as an") 492 logger.info(" external particle.") 493 logger.info("o lorentz_invariance:",'$MG:color:GREEN') 494 logger.info(" Check that the amplitude is lorentz invariant by") 495 logger.info(" comparing the amplitiude in different frames") 496 logger.info("o cms:",'$MG:color:GREEN') 497 logger.info(" Check the complex mass scheme consistency by comparing") 498 logger.info(" it to the narrow width approximation in the off-shell") 499 logger.info(" region of detected resonances and by progressively") 500 logger.info(" decreasing the width. Additional options for this check are:") 501 logger.info(" --offshellness=f : f is a positive or negative float specifying ") 502 logger.info(" the distance from the pole as f*particle_mass. Default is 10.0") 503 logger.info(" --seed=i : to force a specific RNG integer seed i (default is fixed to 0)") 504 logger.info(" --cms=order1&order2;...,p1->f(p,lambdaCMS)&p2->f2(p,lambdaCMS);...") 505 logger.info(" 'order_i' specifies the expansion orders considered for the test.") 506 logger.info(" The substitution lists specifies how internal parameter must be modified") 507 logger.info(" with the width scaling 'lambdaCMS'. The default value for this option is:") 508 logger.info(" --cms=QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS ") 509 logger.info(" The number of order and parameters don't have to be the same.") 510 logger.info(" The scaling must be specified so that one occurrence of the coupling order.") 511 logger.info(" brings in exactly one power of lambdaCMS.") 512 logger.info(" --recompute_width= never|first_time|always|auto") 513 logger.info(" Decides when to use MadWidth to automatically recompute the width") 514 logger.info(" 'auto' (default) let MG5 chose the most appropriate behavior.") 515 logger.info(" 'never' uses the default width value for lambdaCMS=1.0.") 516 logger.info(" 'first_time' uses MadWidth to compute the width for lambdaCMS=1.0.") 517 logger.info(" 'first_time' and 'never' assume linear scaling of the widths with lambdaCMS") 518 logger.info(" 'always' uses MadWidth to compute the widths for all values of lambdaCMS") 519 logger.info(" the test relies on linear scaling of the width, so 'always' is ") 520 logger.info(" only for double-checks") 521 logger.info(" --lambdaCMS = <python_list> : specifies the list of lambdaCMS values to ") 522 logger.info(" use for the test. For example: '[(1/2.0)**exp\ for\ exp\ in\ range(0,20)]'") 523 logger.info(" In the list expression, you must escape spaces. Also, this option") 524 logger.info(" *must* appear last in the otpion list. Finally, the default value is '1.0e-6'") 525 logger.info(" for which an optimal list of progressive values is picked up to 1.0e-6") 526 logger.info(" --show_plot = True or False: Whether to show plot during analysis (default is True)") 527 logger.info(" --report = concise or full: Whether return a concise or full report.") 528 logger.info("Comments",'$MG:color:GREEN') 529 logger.info(" > If param_card is given, that param_card is used ") 530 logger.info(" instead of the default values for the model.") 531 logger.info(" If that file is an (LHE) event file. The param_card of the banner") 532 logger.info(" is used and the first event compatible with the requested process") 533 logger.info(" is used for the computation of the square matrix elements") 534 logger.info(" > \"--energy=\" allows to change the default value of sqrt(S).") 535 logger.info(" > Except for the 'gauge' test, all checks above are also") 536 logger.info(" available for loop processes with ML5 ('virt=' mode)") 537 logger.info("Example: check full p p > j j",'$MG:color:GREEN') 538 logger.info("Using leshouches file as input",'$MG:color:GREEN') 539 logger.info(" use the option --events=PATH") 540 logger.info(" zipped file are not supported") 541 logger.info(" to loop over the file use the option --skip_evt=X") 542 logger.info("") 543 logger.info("Options for loop processes only:",'$MG:BOLD') 544 logger.info("o timing:",'$MG:color:GREEN') 545 logger.info(" Generate and output a process and returns detailed") 546 logger.info(" information about the code and a timing benchmark.") 547 logger.info("o stability:",'$MG:color:GREEN') 548 logger.info(" Generate and output a process and returns detailed") 549 logger.info(" statistics about the numerical stability of the code.") 550 logger.info("o profile:",'$MG:color:GREEN') 551 logger.info(" Performs both the timing and stability analysis at once") 552 logger.info(" and outputs the result in a log file without prompting") 553 logger.info(" it to the user.") 554 logger.info("Comments",'$MG:color:GREEN') 555 logger.info(" > These checks are only available for ML5 ('virt=' mode)") 556 logger.info(" > For the 'profile' and 'stability' checks, you can chose") 557 logger.info(" how many PS points should be used for the statistic by") 558 logger.info(" specifying it as an integer just before the [param_card]") 559 logger.info(" optional argument.") 560 logger.info(" > Notice multiparticle labels cannot be used with these checks.") 561 logger.info(" > \"--reduction=\" allows to change what reduction methods should be used.") 562 logger.info(" > \"--split_orders=\" allows to change what specific combination of coupling orders to consider.") 563 logger.info(" > For process syntax, please see help generate.") 564 logger.info(" > In order to save the directory generated or the reuse an existing one") 565 logger.info(" previously generated with the check command, one can add the '-reuse' ") 566 logger.info(" keyword just after the specification of the type of check desired.") 567 logger.info("Example: check profile g g > t t~ [virt=QCD]",'$MG:color:GREEN')
568 569
570 - def help_generate(self):
571 572 logger.info("-- generate diagrams for a given process",'$MG:color:BLUE') 573 logger.info("General leading-order syntax:",'$MG:BOLD') 574 logger.info(" o generate INITIAL STATE > REQ S-CHANNEL > FINAL STATE $ EXCL S-CHANNEL / FORBIDDEN PARTICLES COUP1=ORDER1 COUP2^2=ORDER2 @N") 575 logger.info(" o Example: generate l+ vl > w+ > l+ vl a $ z / a h QED<=3 QCD=0 @1",'$MG:color:GREEN') 576 logger.info(" > Alternative required s-channels can be separated by \"|\":") 577 logger.info(" b b~ > W+ W- | H+ H- > ta+ vt ta- vt~") 578 logger.info(" > If no coupling orders are given, MG5 will try to determine") 579 logger.info(" orders to ensure maximum number of QCD vertices.") 580 logger.info(" > Desired coupling orders combination can be specified directly for") 581 logger.info(" the squared matrix element by appending '^2' to the coupling name.") 582 logger.info(" For example, 'p p > j j QED^2==2 QCD^==2' selects the QED-QCD") 583 logger.info(" interference terms only. The other two operators '<=' and '>' are") 584 logger.info(" supported. Finally, a negative value COUP^2==-I refers to the") 585 logger.info(" N^(-I+1)LO term in the expansion of the COUP order.") 586 logger.info(" > allowed coupling operator are: \"==\", \"=\", \"<=\" and \">\".") 587 logger.info(" \"==\" request exactly that number of coupling while \"=\" is interpreted as \"<=\".") 588 logger.info(" > To generate a second process use the \"add process\" command") 589 logger.info("Decay chain syntax:",'$MG:BOLD') 590 logger.info(" o core process, decay1, (decay2, (decay2', ...)), ... etc") 591 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') 592 logger.info(" > Note that identical particles will all be decayed.") 593 logger.info("Loop processes syntax:",'$MG:BOLD') 594 logger.info(" o core process [ <NLO_mode=> LoopOrder1 LoopOrder2 ... ] SQUAREDCOUPi=ORDERi") 595 logger.info(" o Example: generate p p > t~ t QED=0 QCD=2 [ all= QCD ] QCD=6",'$MG:color:GREEN') 596 logger.info(" > Notice that in this format, decay chains are not allowed.") 597 logger.info(" > The LoopOrder(s) defined specify the kind of loops to consider (only QCD for now).") 598 logger.info(" > The coupling restrictions before '[' restrict the orders of born *amplitudes*.") 599 logger.info(" So that in the example above QCD=2 restricts the born amplitude to have at") 600 logger.info(" most QCD=2 and loop amplitudes at most QCD=2+2 (because QCD loops are considered)") 601 logger.info(" > The coupling restrictions after ']' restrict the orders of the matrix element, ") 602 logger.info(" namely the squared amplitudes. In the example above QCD=6 correspond to born") 603 logger.info(" amplitudes with QCD=2 squared against loop amplitudes with QCD=4, adding up to 6.") 604 logger.info(" > The optional <NLO_mode=> can be any of the following ('all=' by default if absent):") 605 logger.info(" all= : Generate all the real-emission and loop diagrams, ready for aMC@NLO runs.") 606 logger.info(" virt= : Generate only the loop diagrams, read for MadLoop standalone checks/runs.") 607 logger.info(" real= : Generate only the real-emission diagrams, for use with alternative OLP. ") 608 logger.info(" > For processes without born amplitudes (i.e. loop-induced like g g > z), please use ") 609 logger.info(" the 'virt=' NLO mode. aMC@NLO cannot integrate these processes, but standalone MadLoop5") 610 logger.info(" can still handle these.")
611
612 - def help_add(self):
613 logger.info("-- generate diagrams for a process and add to existing processes",'$MG:color:BLUE') 614 logger.info(" OR merge two model",'$MG:color:BLUE') 615 logger.info('') 616 logger.info("-- generate diagrams for a process and add to existing processes",'$MG:color:BLUE') 617 logger.info("General leading-order syntax:",'$MG:BOLD') 618 logger.info(" o add process INITIAL STATE > REQ S-CHANNEL > FINAL STATE $ EXCL S-CHANNEL / FORBIDDEN PARTICLES COUP1=ORDER1 COUP2=ORDER2 @N") 619 logger.info(" o Example: add process l+ vl > w+ > l+ vl a $ z / a h QED=3 QCD=0 @1",'$MG:color:GREEN') 620 logger.info(" > Alternative required s-channels can be separated by \"|\":") 621 logger.info(" b b~ > W+ W- | H+ H- > ta+ vt ta- vt~") 622 logger.info(" > If no coupling orders are given, MG5 will try to determine") 623 logger.info(" orders to ensure maximum number of QCD vertices.") 624 logger.info(" > Note that if there are more than one non-QCD coupling type,") 625 logger.info(" coupling orders need to be specified by hand.") 626 logger.info("Decay chain syntax:",'$MG:BOLD') 627 logger.info(" o core process, decay1, (decay2, (decay2', ...)), ... etc") 628 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') 629 logger.info(" > Note that identical particles will all be decayed.") 630 logger.info("Loop processes syntax:",'$MG:BOLD') 631 logger.info(" o core process [ <NLO_mode=> LoopOrder1 LoopOrder2 ... ] SQUAREDCOUPi=ORDERi") 632 logger.info(" o Example: add process p p > t~ t QED=0 QCD=2 [ all= QCD ] QCD=6",'$MG:color:GREEN') 633 logger.info(" > Notice that in this format, decay chains are not allowed.") 634 logger.info(" > The LoopOrder(s) defined specify the kind of loops to consider (only QCD for now).") 635 logger.info(" > The coupling restrictions before '[' restrict the orders of born *amplitudes*.") 636 logger.info(" So that in the example above QCD=2 restricts the born amplitude to have at") 637 logger.info(" most QCD=2 and loop amplitudes at most QCD=2+2 (because QCD loops are considered)") 638 logger.info(" > The coupling restrictions after ']' restrict the orders of the matrix element, ") 639 logger.info(" namely the squared amplitudes. In the example above QCD=6 correspond to born") 640 logger.info(" amplitudes with QCD=2 squared against loop amplitudes with QCD=4, adding up to 6.") 641 logger.info(" > The optional <NLO_mode=> can be any of the following ('all=' by default if absent):") 642 logger.info(" all= : Generate all the real-emission and loop diagrams, ready for aMC@NLO runs.") 643 logger.info(" virt= : Generate only the loop diagrams, read for MadLoop standalone checks/runs.") 644 logger.info(" real= : Generate only the real-emission diagrams, for use with alternative OLP. ") 645 logger.info(" > For processes without born amplitudes (i.e. loop-induced like g g > z), please use ") 646 logger.info(" the 'virt=' NLO mode. aMC@NLO cannot integrate these processes, but standalone MadLoop5") 647 logger.info(" can still handle these.") 648 649 logger.info("-- merge two model to create a new one", '$MG:color:BLUE') 650 logger.info("syntax:",'$MG:BOLD') 651 logger.info(" o add model MODELNAME [OPTIONS]") 652 logger.info(" o Example: add model taudecay",'$MG:color:GREEN') 653 logger.info(" > Merge the two model in a single one. If that same merge was done before.") 654 logger.info(" > Just reload the previous merge. (WARNING: This doesn't check if those model are modified)") 655 logger.info(" > Options:") 656 logger.info(" --output= : Specify the name of the directory where the merge is done.") 657 logger.info(" This allow to do \"import NAME\" to load that merge.") 658 logger.info(" --recreate : Force to recreated the merge model even if the merge model directory already exists.")
659
660 - def help_convert(self):
661 logger.info("syntax: convert model FULLPATH") 662 logger.info("modify (in place) the UFO model to make it compatible with both python2 and python3")
663
664 - def help_compute_widths(self):
665 logger.info("syntax: calculate_width PART [other particles] [OPTIONS]") 666 logger.info(" Computes the width and partial width for a set of particles") 667 logger.info(" Returns a valid param_card with this information.") 668 logger.info(" ") 669 logger.info(" PART: name of the particle you want to calculate width") 670 logger.info(" you can enter either the name or pdg code.\n") 671 logger.info(" Various options:\n") 672 logger.info(" --body_decay=X: Parameter to control the precision of the computation") 673 logger.info(" if X is an integer, we compute all channels up to X-body decay.") 674 logger.info(" if X <1, then we stop when the estimated error is lower than X.") 675 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer") 676 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.") 677 logger.info(" default: 4.0025") 678 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.") 679 logger.info(" default: precision (decimal part of the body_decay options) divided by four") 680 logger.info(" --precision_channel=X: requested numerical precision for each channel") 681 logger.info(" default: 0.01") 682 logger.info(" --path=X: path for param_card") 683 logger.info(" default: take value from the model") 684 logger.info(" --output=X: path where to write the resulting card. ") 685 logger.info(" default: overwrite input file. If no input file, write it in the model directory") 686 logger.info(" --nlo: Compute NLO width [if the model support it]") 687 logger.info("") 688 logger.info(" example: calculate_width h --body_decay=2 --output=./param_card")
689
690 - def help_decay_diagram(self):
691 logger.info("syntax: decay_diagram PART [other particles] [OPTIONS]") 692 logger.info(" Returns the amplitude required for the computation of the widths") 693 logger.info(" ") 694 logger.info(" PART: name of the particle you want to calculate width") 695 logger.info(" you can enter either the name or pdg code.\n") 696 logger.info(" Various options:\n") 697 logger.info(" --body_decay=X: Parameter to control the precision of the computation") 698 logger.info(" if X is an integer, we compute all channels up to X-body decay.") 699 logger.info(" if X <1, then we stop when the estimated error is lower than X.") 700 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer") 701 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.") 702 logger.info(" default: 4.0025") 703 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.") 704 logger.info(" default: precision (decimal part of the body_decay options) divided by four") 705 logger.info(" --precision_channel=X: requested numerical precision for each channel") 706 logger.info(" default: 0.01") 707 logger.info(" --path=X: path for param_card") 708 logger.info(" default: take value from the model") 709 logger.info(" --output=X: path where to write the resulting card. ") 710 logger.info(" default: overwrite input file. If no input file, write it in the model directory") 711 logger.info("") 712 logger.info(" example: calculate_width h --body_decay=2 --output=./param_card")
713
714 - def help_define(self):
715 logger.info("-- define a multiparticle",'$MG:color:BLUE') 716 logger.info("Syntax: define multipart_name [=] part_name_list") 717 logger.info("Example: define p = g u u~ c c~ d d~ s s~ b b~",'$MG:color:GREEN') 718 logger.info("Special syntax: Use | for OR (used for required s-channels)") 719 logger.info("Special syntax: Use / to remove particles. Example: define q = p / g")
720
721 - def help_set(self):
722 logger.info("-- set options for generation or output.",'$MG:color:BLUE') 723 logger.info("syntax: set <option_name> <option_value>",'$MG:BOLD') 724 logger.info("Possible options are: ") 725 for opts in [self._set_options[i*3:(i+1)*3] for i in \ 726 range((len(self._set_options)//4)+1)]: 727 logger.info("%s"%(','.join(opts)),'$MG:color:GREEN') 728 logger.info("Details of each option:") 729 logger.info("group_subprocesses True/False/Auto: ",'$MG:color:GREEN') 730 logger.info(" > (default Auto) Smart grouping of subprocesses into ") 731 logger.info(" directories, mirroring of initial states, and ") 732 logger.info(" combination of integration channels.") 733 logger.info(" > Example: p p > j j j w+ gives 5 directories and 184 channels",'$MG:BOLD') 734 logger.info(" (cf. 65 directories and 1048 channels for regular output)",'$MG:BOLD') 735 logger.info(" > Auto means False for decay computation and True for collisions.") 736 logger.info("ignore_six_quark_processes multi_part_label",'$MG:color:GREEN') 737 logger.info(" > (default none) ignore processes with at least 6 of any") 738 logger.info(" of the quarks given in multi_part_label.") 739 logger.info(" > These processes give negligible contribution to the") 740 logger.info(" cross section but have subprocesses/channels.") 741 logger.info("stdout_level DEBUG|INFO|WARNING|ERROR|CRITICAL",'$MG:color:GREEN') 742 logger.info(" > change the default level for printed information") 743 logger.info("fortran_compiler NAME",'$MG:color:GREEN') 744 logger.info(" > (default None) Force a specific fortran compiler.") 745 logger.info(" If None, it tries first g77 and if not present gfortran") 746 logger.info(" but loop output use gfortran.") 747 logger.info("loop_optimized_output True|False",'$MG:color:GREEN') 748 logger.info(" > Exploits the open loop thechnique for considerable") 749 logger.info(" improvement.") 750 logger.info(" > CP relations among helicites are detected and the helicity") 751 logger.info(" filter has more potential.") 752 logger.info("loop_color_flows True|False",'$MG:color:GREEN') 753 logger.info(" > Only relevant for the loop optimized output.") 754 logger.info(" > Reduces the loop diagrams at the amplitude level") 755 logger.info(" rendering possible the computation of the loop amplitude") 756 logger.info(" for a fixed color flow or color configuration.") 757 logger.info(" > This option can considerably slow down the loop ME") 758 logger.info(" computation time, especially when summing over all color") 759 logger.info(" and helicity configuration, hence turned off by default.") 760 logger.info("gauge unitary|Feynman|axial",'$MG:color:GREEN') 761 logger.info(" > (default unitary) choose the gauge of the non QCD part.") 762 logger.info(" > For loop processes, only Feynman gauge is employable.") 763 logger.info("complex_mass_scheme True|False",'$MG:color:GREEN') 764 logger.info(" > (default False) Set complex mass scheme.") 765 logger.info(" > Complex mass scheme is not yet supported for loop processes.") 766 logger.info("timeout VALUE",'$MG:color:GREEN') 767 logger.info(" > (default 20) Seconds allowed to answer questions.") 768 logger.info(" > Note that pressing tab always stops the timer.") 769 logger.info("cluster_temp_path PATH",'$MG:color:GREEN') 770 logger.info(" > (default None) [Used in Madevent Output]") 771 logger.info(" > Allow to perform the run in PATH directory") 772 logger.info(" > This allow to not run on the central disk. ") 773 logger.info(" > This is not used by condor cluster (since condor has") 774 logger.info(" its own way to prevent it).") 775 logger.info("mg5amc_py8_interface_path PATH",'$MG:color:GREEN') 776 logger.info(" > Necessary when showering events with Pythia8 from Madevent.") 777 logger.info("OLP ProgramName",'$MG:color:GREEN') 778 logger.info(" > (default 'MadLoop') [Used for virtual generation]") 779 logger.info(" > Chooses what One-Loop Program to use for the virtual") 780 logger.info(" > matrix element generation via the BLAH accord.") 781 logger.info("output_dependencies <mode>",'$MG:color:GREEN') 782 logger.info(" > (default 'external') [Use for NLO outputs]") 783 logger.info(" > Choses how the external dependences (such as CutTools)") 784 logger.info(" > of NLO outputs are handled. Possible values are:") 785 logger.info(" o external: Some of the libraries the output depends") 786 logger.info(" on are links to their installation in MG5 root dir.") 787 logger.info(" o internal: All libraries the output depends on are") 788 logger.info(" copied and compiled locally in the output directory.") 789 logger.info(" o environment_paths: The location of all libraries the ") 790 logger.info(" output depends on should be found in your env. paths.") 791 logger.info("max_npoint_for_channel <value>",'$MG:color:GREEN') 792 logger.info(" > (default '0') [Used ONLY for loop-induced outputs with madevent]") 793 logger.info(" > Sets the maximum 'n' of n-points loops to be used for") 794 logger.info(" > setting up the integration multichannels.") 795 logger.info(" > The default value of zero automatically picks the apparent") 796 logger.info(" > appropriate choice which is to sometimes pick box loops") 797 logger.info(" > but never higher n-points ones.") 798 logger.info("max_t_for_channel <value>",'$MG:color:GREEN') 799 logger.info(" > (default '0') [Used ONLY for tree-level output with madevent]") 800 logger.info(" > Forbids the inclusion of channel of integration with more than X") 801 logger.info(" > T channel propagators. Such channel can sometimes be quite slow to integrate") 802 logger.info("zerowidth_tchannel <value>",'$MG:color:GREEN') 803 logger.info(" > (default: True) [Used ONLY for tree-level output with madevent]") 804 logger.info(" > set the width to zero for all T-channel propagator --no impact on complex-mass scheme mode")
805 #===============================================================================
806 # CheckValidForCmd 807 #=============================================================================== 808 -class CheckValidForCmd(cmd.CheckCmd):
809 """ The Series of help routine for the MadGraphCmd""" 810
811 - class RWError(MadGraph5Error):
812 """a class for read/write errors"""
813
814 - def check_add(self, args):
815 """check the validity of line 816 syntax: add process PROCESS | add model MODELNAME 817 """ 818 819 if len(args) < 2: 820 self.help_add() 821 raise self.InvalidCmd('\"add\" requires at least two arguments') 822 823 if args[0] not in ['model', 'process']: 824 raise self.InvalidCmd('\"add\" requires the argument \"process\" or \"model\"') 825 826 if args[0] == 'process': 827 return self.check_generate(args) 828 829 if args[0] == 'model': 830 pass
831 832
833 - def check_define(self, args):
834 """check the validity of line 835 syntax: define multipart_name [ part_name_list ] 836 """ 837 838 if len(args) < 2: 839 self.help_define() 840 raise self.InvalidCmd('\"define\" command requires at least two arguments') 841 842 if args[1] == '=': 843 del args[1] 844 if len(args) < 2: 845 self.help_define() 846 raise self.InvalidCmd('\"define\" command requires at least one particles name after \"=\"') 847 848 if '=' in args: 849 self.help_define() 850 raise self.InvalidCmd('\"define\" command requires symbols \"=\" at the second position') 851 852 if not self._curr_model: 853 logger.info('No model currently active. Try with the Standard Model') 854 self.do_import('model sm') 855 856 if self._curr_model['particles'].find_name(args[0]): 857 raise self.InvalidCmd("label %s is a particle name in this model\n\ 858 Please retry with another name." % args[0])
859
860 - def check_display(self, args):
861 """check the validity of line 862 syntax: display XXXXX 863 """ 864 865 if len(args) < 1: 866 self.help_display() 867 raise self.InvalidCmd('display requires an argument specifying what to display') 868 if args[0] not in self._display_opts + ['model_list']: 869 self.help_display() 870 raise self.InvalidCmd('Invalid arguments for display command: %s' % args[0]) 871 872 if not self._curr_model: 873 raise self.InvalidCmd("No model currently active, please import a model!") 874 875 # check that either _curr_amps or _fks_multi_proc exists 876 if (args[0] in ['processes', 'diagrams'] and not self._curr_amps and not self._fks_multi_proc): 877 raise self.InvalidCmd("No process generated, please generate a process!") 878 if args[0] == 'checks' and not self._comparisons and not self._cms_checks: 879 raise self.InvalidCmd("No check results to display.") 880 881 if args[0] == 'variable' and len(args) !=2: 882 raise self.InvalidCmd('variable need a variable name')
883 884
885 - def check_draw(self, args):
886 """check the validity of line 887 syntax: draw DIRPATH [option=value] 888 """ 889 890 if len(args) < 1: 891 args.append('/tmp') 892 893 if not self._curr_amps: 894 raise self.InvalidCmd("No process generated, please generate a process!") 895 896 if not os.path.isdir(args[0]): 897 raise self.InvalidCmd( "%s is not a valid directory for export file" % args[0])
898
899 - def check_check(self, args):
900 """check the validity of args""" 901 902 if not self._curr_model: 903 raise self.InvalidCmd("No model currently active, please import a model!") 904 905 if self._model_v4_path: 906 raise self.InvalidCmd(\ 907 "\"check\" not possible for v4 models") 908 909 if len(args) < 2 and not args[0].lower().endswith('options'): 910 self.help_check() 911 raise self.InvalidCmd("\"check\" requires a process.") 912 913 if args[0] not in self._check_opts and \ 914 not args[0].lower().endswith('options'): 915 args.insert(0, 'full') 916 917 param_card = None 918 if args[0] not in ['stability','profile','timing'] and \ 919 len(args)>1 and os.path.isfile(args[1]): 920 param_card = args.pop(1) 921 922 if len(args)>1: 923 if args[1] != "-reuse": 924 args.insert(1, '-no_reuse') 925 else: 926 args.append('-no_reuse') 927 928 if args[0] in ['timing'] and len(args)>2 and os.path.isfile(args[2]): 929 param_card = args.pop(2) 930 if args[0] in ['stability', 'profile'] and len(args)>1: 931 # If the first argument after 'stability' is not the integer 932 # specifying the desired statistics (i.e. number of points), then 933 # we insert the default value 100 934 try: 935 int(args[2]) 936 except ValueError: 937 args.insert(2, '100') 938 939 if args[0] in ['stability', 'profile'] and os.path.isfile(args[3]): 940 param_card = args.pop(3) 941 if any([',' in elem for elem in args if not elem.startswith('--')]): 942 raise self.InvalidCmd('Decay chains not allowed in check') 943 944 user_options = {'--energy':'1000','--split_orders':'-1', 945 '--reduction':'1|3|5|6','--CTModeRun':'-1', 946 '--helicity':'-1','--seed':'-1','--collier_cache':'-1', 947 '--collier_req_acc':'auto', 948 '--collier_internal_stability_test':'False', 949 '--collier_mode':'1', 950 '--events': None, 951 '--skip_evt':0} 952 953 if args[0] in ['cms'] or args[0].lower()=='cmsoptions': 954 # increase the default energy to 5000 955 user_options['--energy']='5000' 956 # The first argument gives the name of the coupling order in which 957 # the cms expansion is carried, and the expression following the 958 # comma gives the relation of an external parameter with the 959 # CMS expansions parameter called 'lambdaCMS'. 960 parameters = ['aewm1->10.0/lambdaCMS','as->0.1*lambdaCMS'] 961 user_options['--cms']='QED&QCD,'+'&'.join(parameters) 962 # Widths are assumed to scale linearly with lambdaCMS unless 963 # --force_recompute_width='always' or 'first_time' is used. 964 user_options['--recompute_width']='auto' 965 # It can be negative so as to be offshell below the resonant mass 966 user_options['--offshellness']='10.0' 967 # Pick the lambdaCMS values for the test. Instead of a python list 968 # we specify here (low,N) which means that do_check will automatically 969 # pick lambda values up to the value low and with N values uniformly 970 # spread in each interval [1.0e-i,1.0e-(i+1)]. 971 # Some points close to each other will be added at the end for the 972 # stability test. 973 user_options['--lambdaCMS']='(1.0e-6,5)' 974 # Set the RNG seed, -1 is default (random). 975 user_options['--seed']=666 976 # The option below can help the user re-analyze existing pickled check 977 user_options['--analyze']='None' 978 # Decides whether to show plot or not during the analysis 979 user_options['--show_plot']='True' 980 # Decides what kind of report 981 user_options['--report']='concise' 982 # 'secret' option to chose by which lambda power one should divide 983 # the nwa-cms difference. Useful to set to 2 when doing the Born check 984 # to see whether the NLO check will have sensitivity to the CMS 985 # implementation 986 user_options['--diff_lambda_power']='1' 987 # Sets the range of lambda values to plot 988 user_options['--lambda_plot_range']='[-1.0,-1.0]' 989 # Sets a filter to apply at generation. See name of available 990 # filters in loop_diagram_generations.py, function user_filter 991 user_options['--loop_filter']='None' 992 # Apply tweaks to the check like multiplying a certain width by a 993 # certain parameters or changing the analytical continuation of the 994 # logarithms of the UV counterterms 995 user_options['--tweak']='default()' 996 # Give a name to the run for the files to be saved 997 user_options['--name']='auto' 998 # Select what resonances must be run 999 user_options['--resonances']='1' 1000 1001 for arg in args[:]: 1002 if arg.startswith('--') and '=' in arg: 1003 parsed = arg.split('=') 1004 key, value = parsed[0],'='.join(parsed[1:]) 1005 if key not in user_options: 1006 raise self.InvalidCmd("unknown option %s" % key) 1007 user_options[key] = value 1008 args.remove(arg) 1009 1010 # If we are just re-analyzing saved data or displaying options then we 1011 # shouldn't check the process format. 1012 if not (args[0]=='cms' and '--analyze' in user_options and \ 1013 user_options['--analyze']!='None') and not \ 1014 args[0].lower().endswith('options'): 1015 1016 self.check_process_format(" ".join(args[1:])) 1017 1018 for option, value in user_options.items(): 1019 args.append('%s=%s'%(option,value)) 1020 1021 return param_card
1022
1023 - def check_generate(self, args):
1024 """check the validity of args""" 1025 1026 if not self._curr_model: 1027 logger.info("No model currently active, so we import the Standard Model") 1028 self.do_import('model sm') 1029 1030 if args[-1].startswith('--optimize'): 1031 if args[2] != '>': 1032 raise self.InvalidCmd('optimize mode valid only for 1->N processes. (See model restriction for 2->N)') 1033 if '=' in args[-1]: 1034 path = args[-1].split('=',1)[1] 1035 if not os.path.exists(path) or \ 1036 self.detect_file_type(path) != 'param_card': 1037 raise self.InvalidCmd('%s is not a valid param_card') 1038 else: 1039 path=None 1040 # Update the default value of the model here. 1041 if not isinstance(self._curr_model, model_reader.ModelReader): 1042 self._curr_model = model_reader.ModelReader(self._curr_model) 1043 self._curr_model.set_parameters_and_couplings(path) 1044 self.check_process_format(' '.join(args[1:-1])) 1045 else: 1046 self.check_process_format(' '.join(args[1:]))
1047 1048
1049 - def check_process_format(self, process):
1050 """ check the validity of the string given to describe a format """ 1051 1052 #check balance of paranthesis 1053 if process.count('(') != process.count(')'): 1054 raise self.InvalidCmd('Invalid Format, no balance between open and close parenthesis') 1055 #remove parenthesis for fututre introspection 1056 process = process.replace('(',' ').replace(')',' ') 1057 1058 # split following , (for decay chains) 1059 subprocesses = process.split(',') 1060 if len(subprocesses) > 1: 1061 for subprocess in subprocesses: 1062 self.check_process_format(subprocess) 1063 return 1064 1065 # request that we have one or two > in the process 1066 nbsep = len(re.findall('>\D', process)) # not use process.count because of QCD^2>2 1067 if nbsep not in [1,2]: 1068 raise self.InvalidCmd( 1069 'wrong format for \"%s\" this part requires one or two symbols \'>\', %s found' 1070 % (process, nbsep)) 1071 1072 # we need at least one particles in each pieces 1073 particles_parts = re.split('>\D', process) 1074 for particles in particles_parts: 1075 if re.match(r'^\s*$', particles): 1076 raise self.InvalidCmd( 1077 '\"%s\" is a wrong process format. Please try again' % process) 1078 1079 # '/' and '$' sould be used only after the process definition 1080 for particles in particles_parts[:-1]: 1081 if re.search('\D/', particles): 1082 raise self.InvalidCmd( 1083 'wrong process format: restriction should be place after the final states') 1084 if re.search('\D\$', particles): 1085 raise self.InvalidCmd( 1086 'wrong process format: restriction should be place after the final states') 1087 1088 # '{}' should only be used for onshell particle (including initial/final state) 1089 # check first that polarization are not include between > > 1090 if nbsep == 2: 1091 if '{' in particles_parts[1]: 1092 raise self.InvalidCmd('Polarization restriction can not be used as required s-channel') 1093 split = re.split('\D[$|/]',particles_parts[-1],1) 1094 if len(split)==2: 1095 if '{' in split[1]: 1096 raise self.InvalidCmd('Polarization restriction can not be used in forbidding particles') 1097 1098 if '[' in process and '{' in process: 1099 valid = False 1100 if 'noborn' in process or 'sqrvirt' in process: 1101 valid = True 1102 else: 1103 raise self.InvalidCmd('Polarization restriction can not be used for NLO processes') 1104 1105 # below are the check when [QCD] will be valid for computation 1106 order = process.split('[')[1].split(']')[0] 1107 if '=' in order: 1108 order = order.split('=')[1] 1109 if order.strip().lower() != 'qcd': 1110 raise self.InvalidCmd('Polarization restriction can not be used for generic NLO computations') 1111 1112 1113 for p in particles_parts[1].split(): 1114 if '{' in p: 1115 part = p.split('{')[0] 1116 else: 1117 continue 1118 if self._curr_model: 1119 p = self._curr_model.get_particle(part) 1120 if not p: 1121 if part in self._multiparticles: 1122 for part2 in self._multiparticles[part]: 1123 p = self._curr_model.get_particle(part2) 1124 if p.get('color') != 1: 1125 raise self.InvalidCmd('Polarization restriction can not be used for color charged particles') 1126 continue 1127 if p.get('color') != 1: 1128 raise self.InvalidCmd('Polarization restriction can not be used for color charged particles')
1129 1130 1131
1132 - def check_tutorial(self, args):
1133 """check the validity of the line""" 1134 if len(args) == 1: 1135 if not args[0] in self._tutorial_opts: 1136 self.help_tutorial() 1137 raise self.InvalidCmd('Invalid argument for tutorial') 1138 elif len(args) == 0: 1139 #this means mg5 tutorial 1140 args.append('MadGraph5') 1141 else: 1142 self.help_tutorial() 1143 raise self.InvalidCmd('Too many arguments for tutorial')
1144 1145 1146
1147 - def check_import(self, args):
1148 """check the validity of line""" 1149 1150 modelname = False 1151 prefix = True 1152 if '-modelname' in args: 1153 args.remove('-modelname') 1154 modelname = True 1155 elif '--modelname' in args: 1156 args.remove('--modelname') 1157 modelname = True 1158 1159 if '--noprefix' in args: 1160 args.remove('--noprefix') 1161 prefix = False 1162 1163 if args and args[0] == 'model' and '--last' in args: 1164 # finding last created directory 1165 args.remove('--last') 1166 last_change = 0 1167 to_search = [pjoin(MG5DIR,'models')] 1168 if 'PYTHONPATH' in os.environ: 1169 to_search += os.environ['PYTHONPATH'].split(':') 1170 to_search = [d for d in to_search if os.path.exists(d)] 1171 1172 models = [] 1173 for d in to_search: 1174 for p in misc.glob('*/particles.py', path=d ): 1175 if p.endswith(('__REAL/particles.py','__COMPLEX/particles.py')): 1176 continue 1177 models.append(os.path.dirname(p)) 1178 1179 lastmodel = max(models, key=os.path.getmtime) 1180 logger.info('last model found is %s', lastmodel) 1181 args.insert(1, lastmodel) 1182 1183 if not args: 1184 self.help_import() 1185 raise self.InvalidCmd('wrong \"import\" format') 1186 1187 if len(args) >= 2 and args[0] not in self._import_formats: 1188 self.help_import() 1189 raise self.InvalidCmd('wrong \"import\" format') 1190 elif len(args) == 1: 1191 if args[0] in self._import_formats: 1192 if args[0] != "proc_v4": 1193 self.help_import() 1194 raise self.InvalidCmd('wrong \"import\" format') 1195 elif not self._export_dir: 1196 self.help_import() 1197 raise self.InvalidCmd('PATH is mandatory in the current context\n' + \ 1198 'Did you forget to run the \"output\" command') 1199 # The type of the import is not given -> guess it 1200 format = self.find_import_type(args[0]) 1201 logger.info('The import format was not given, so we guess it as %s' % format) 1202 args.insert(0, format) 1203 if self.history[-1].startswith('import'): 1204 self.history[-1] = 'import %s %s' % \ 1205 (format, ' '.join(self.history[-1].split()[1:])) 1206 1207 if not prefix: 1208 args.append('--noprefix') 1209 1210 if modelname: 1211 args.append('-modelname')
1212 1213 1214
1215 - def check_install(self, args):
1216 """check that the install command is valid""" 1217 1218 1219 install_options = {'options_for_HEPToolsInstaller':[], 1220 'update_options':[]} 1221 hidden_prog = ['Delphes2', 'pythia-pgs','SysCalc'] 1222 1223 if len(args) < 1: 1224 self.help_install() 1225 raise self.InvalidCmd('install command require at least one argument') 1226 1227 if len(args) > 1: 1228 for arg in args[1:]: 1229 try: 1230 option, value = arg.split('=') 1231 except ValueError: 1232 option = arg 1233 value = None 1234 # Options related to the MadGraph installer can be treated here, i.e 1235 if args[0]=='update': 1236 if value is None: 1237 install_options['update_options'].append(option) 1238 else: 1239 install_options['update_options'].append('='.join([option,value])) 1240 else: 1241 # Other options will be directly added to the call to HEPToolsInstallers 1242 # in the advanced_install function 1243 install_options['options_for_HEPToolsInstaller'].append(arg) 1244 # Now that the options have been treated keep only the target tool 1245 # to install as argument. 1246 args = args[:1] 1247 1248 if args[0] not in self._install_opts + hidden_prog + self._advanced_install_opts: 1249 if not args[0].startswith('td'): 1250 self.help_install() 1251 raise self.InvalidCmd('Not recognize program %s ' % args[0]) 1252 1253 if args[0] in ["ExRootAnalysis", "Delphes", "Delphes2"]: 1254 if not misc.which('root'): 1255 raise self.InvalidCmd( 1256 '''In order to install ExRootAnalysis, you need to install Root on your computer first. 1257 please follow information on http://root.cern.ch/drupal/content/downloading-root''') 1258 if 'ROOTSYS' not in os.environ: 1259 raise self.InvalidCmd( 1260 '''The environment variable ROOTSYS is not configured. 1261 You can set it by adding the following lines in your .bashrc [.bash_profile for mac]: 1262 export ROOTSYS=%s 1263 export PATH=$PATH:$ROOTSYS/bin 1264 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ROOTSYS/lib 1265 export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$ROOTSYS/lib 1266 This will take effect only in a NEW terminal 1267 ''' % os.path.realpath(pjoin(misc.which('root'), \ 1268 os.path.pardir, os.path.pardir))) 1269 1270 return install_options
1271
1272 - def check_launch(self, args, options):
1273 """check the validity of the line""" 1274 # modify args in order to be MODE DIR 1275 # mode being either standalone or madevent 1276 if not( 0 <= int(options.cluster) <= 2): 1277 return self.InvalidCmd( 'cluster mode should be between 0 and 2') 1278 1279 if not args: 1280 if self._done_export: 1281 mode = self.find_output_type(self._done_export[0]) 1282 if (self._done_export[1] == 'plugin' and mode in self._export_formats): 1283 args.append(mode) 1284 args.append(self._done_export[0]) 1285 elif self._done_export[1].startswith(mode): 1286 args.append(self._done_export[1]) 1287 args.append(self._done_export[0]) 1288 else: 1289 raise self.InvalidCmd('%s not valid directory for launch' % self._done_export[0]) 1290 return 1291 else: 1292 logger.warning('output command missing, run it automatically (with default argument)') 1293 self.do_output('') 1294 logger.warning('output done: running launch') 1295 return self.check_launch(args, options) 1296 1297 if len(args) != 1: 1298 self.help_launch() 1299 return self.InvalidCmd( 'Invalid Syntax: Too many argument') 1300 1301 # search for a valid path 1302 if os.path.isdir(args[0]): 1303 path = os.path.realpath(args[0]) 1304 elif os.path.isdir(pjoin(MG5DIR,args[0])): 1305 path = pjoin(MG5DIR,args[0]) 1306 elif MG4DIR and os.path.isdir(pjoin(MG4DIR,args[0])): 1307 path = pjoin(MG4DIR,args[0]) 1308 else: 1309 raise self.InvalidCmd('%s is not a valid directory' % args[0]) 1310 1311 mode = self.find_output_type(path) 1312 1313 args[0] = mode 1314 args.append(path) 1315 # inform where we are for future command 1316 self._done_export = [path, mode]
1317 1318
1319 - def find_import_type(self, path):
1320 """ identify the import type of a given path 1321 valid output: model/model_v4/proc_v4/command""" 1322 1323 possibility = [pjoin(MG5DIR,'models',path), \ 1324 pjoin(MG5DIR,'models',path+'_v4'), path] 1325 if '-' in path: 1326 name = path.rsplit('-',1)[0] 1327 possibility = [pjoin(MG5DIR,'models',name), name] + possibility 1328 # Check if they are a valid directory 1329 for name in possibility: 1330 if os.path.isdir(name): 1331 if os.path.exists(pjoin(name,'particles.py')): 1332 return 'model' 1333 elif os.path.exists(pjoin(name,'particles.dat')): 1334 return 'model_v4' 1335 1336 # Not valid directory so maybe a file 1337 if os.path.isfile(path): 1338 text = open(path).read() 1339 pat = re.compile('(Begin process|<MGVERSION>)', re.I) 1340 matches = pat.findall(text) 1341 if not matches: 1342 return 'command' 1343 elif len(matches) > 1: 1344 return 'banner' 1345 elif matches[0].lower() == 'begin process': 1346 return 'proc_v4' 1347 else: 1348 return 'banner' 1349 else: 1350 return 'proc_v4'
1351 1352 1353 1354
1355 - def find_output_type(self, path):
1356 """ identify the type of output of a given directory: 1357 valid output: madevent/standalone/standalone_cpp""" 1358 1359 card_path = pjoin(path,'Cards') 1360 bin_path = pjoin(path,'bin') 1361 src_path = pjoin(path,'src') 1362 include_path = pjoin(path,'include') 1363 subproc_path = pjoin(path,'SubProcesses') 1364 mw_path = pjoin(path,'Source','MadWeight') 1365 1366 if os.path.isfile(pjoin(include_path, 'Pythia.h')) or \ 1367 os.path.isfile(pjoin(include_path, 'Pythia8', 'Pythia.h')): 1368 return 'pythia8' 1369 elif not os.path.isdir(os.path.join(path, 'SubProcesses')): 1370 raise self.InvalidCmd('%s : Not a valid directory' % path) 1371 1372 if os.path.isdir(src_path): 1373 return 'standalone_cpp' 1374 elif os.path.isdir(mw_path): 1375 return 'madweight' 1376 elif os.path.isfile(pjoin(bin_path,'madevent')): 1377 return 'madevent' 1378 elif os.path.isfile(pjoin(bin_path,'aMCatNLO')): 1379 return 'aMC@NLO' 1380 elif os.path.isdir(card_path): 1381 return 'standalone' 1382 1383 raise self.InvalidCmd('%s : Not a valid directory' % path)
1384
1385 - def check_load(self, args):
1386 """ check the validity of the line""" 1387 1388 if len(args) != 2 or args[0] not in self._save_opts: 1389 self.help_load() 1390 raise self.InvalidCmd('wrong \"load\" format')
1391
1392 - def check_customize_model(self, args):
1393 """check the validity of the line""" 1394 1395 # Check argument validity 1396 if len(args) >1 : 1397 self.help_customize_model() 1398 raise self.InvalidCmd('No argument expected for this command') 1399 1400 if len(args): 1401 if not args[0].startswith('--save='): 1402 self.help_customize_model() 1403 raise self.InvalidCmd('Wrong argument for this command') 1404 if '-' in args[0][6:]: 1405 raise self.InvalidCmd('The name given in save options can\'t contain \'-\' symbol.') 1406 1407 if self._model_v4_path: 1408 raise self.InvalidCmd('Restriction of Model is not supported by v4 model.')
1409 1410
1411 - def check_save(self, args):
1412 """ check the validity of the line""" 1413 1414 if len(args) == 0: 1415 args.append('options') 1416 1417 if args[0] not in self._save_opts and args[0] != 'global': 1418 self.help_save() 1419 raise self.InvalidCmd('wrong \"save\" format') 1420 elif args[0] == 'global': 1421 args.insert(0, 'options') 1422 1423 if args[0] != 'options' and len(args) != 2: 1424 self.help_save() 1425 raise self.InvalidCmd('wrong \"save\" format') 1426 elif args[0] != 'options' and len(args) == 2: 1427 basename = os.path.dirname(args[1]) 1428 if not os.path.exists(basename): 1429 raise self.InvalidCmd('%s is not a valid path, please retry' % \ 1430 args[1]) 1431 1432 if args[0] == 'options': 1433 has_path = None 1434 for arg in args[1:]: 1435 if arg in ['--auto', '--all'] or arg in self.options: 1436 continue 1437 elif arg.startswith('--'): 1438 raise self.InvalidCmd('unknow command for \'save options\'') 1439 elif arg == 'global': 1440 if 'HOME' in os.environ: 1441 args.remove('global') 1442 args.insert(1,pjoin(os.environ['HOME'],'.mg5','mg5_configuration.txt')) 1443 has_path = True 1444 else: 1445 basename = os.path.dirname(arg) 1446 if not os.path.exists(basename): 1447 raise self.InvalidCmd('%s is not a valid path, please retry' % \ 1448 arg) 1449 elif has_path: 1450 raise self.InvalidCmd('only one path is allowed') 1451 else: 1452 args.remove(arg) 1453 args.insert(1, arg) 1454 has_path = True 1455 if not has_path: 1456 args.insert(1, pjoin(MG5DIR,'input','mg5_configuration.txt'))
1457 1458
1459 - def check_set(self, args, log=True):
1460 """ check the validity of the line""" 1461 1462 if len(args) == 1 and args[0] in ['complex_mass_scheme',\ 1463 'loop_optimized_output',\ 1464 'loop_color_flows',\ 1465 'low_mem_multicore_nlo_generation']: 1466 args.append('True') 1467 1468 if len(args) > 2 and '=' == args[1]: 1469 args.pop(1) 1470 1471 if len(args) < 2: 1472 self.help_set() 1473 raise self.InvalidCmd('set needs an option and an argument') 1474 1475 if args[1] == 'default': 1476 if args[0] in self.options_configuration: 1477 default = self.options_configuration[args[0]] 1478 elif args[0] in self.options_madgraph: 1479 default = self.options_madgraph[args[0]] 1480 elif args[0] in self.options_madevent: 1481 default = self.options_madevent[args[0]] 1482 else: 1483 raise self.InvalidCmd('%s doesn\'t have a valid default value' % args[0]) 1484 if log: 1485 logger.info('Pass parameter %s to it\'s default value: %s' % 1486 (args[0], default)) 1487 args[1] = str(default) 1488 1489 if args[0] not in self._set_options: 1490 if not args[0] in self.options and not args[0] in self.options: 1491 self.help_set() 1492 raise self.InvalidCmd('Possible options for set are %s' % \ 1493 self._set_options) 1494 1495 if args[0] in ['group_subprocesses']: 1496 if args[1].lower() not in ['false', 'true', 'auto']: 1497 raise self.InvalidCmd('%s needs argument False, True or Auto, got %s' % \ 1498 (args[0], args[1])) 1499 if args[0] in ['ignore_six_quark_processes']: 1500 if args[1] not in list(self._multiparticles.keys()) and args[1].lower() != 'false': 1501 raise self.InvalidCmd('ignore_six_quark_processes needs ' + \ 1502 'a multiparticle name as argument') 1503 1504 if args[0] in ['stdout_level']: 1505 if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] and \ 1506 not args[1].isdigit(): 1507 raise self.InvalidCmd('output_level needs ' + \ 1508 'a valid level') 1509 1510 if args[0] in ['timeout', 'max_npoint_for_channel', 'max_t_for_channel']: 1511 if not args[1].isdigit(): 1512 raise self.InvalidCmd('%s values should be a integer' % args[0]) 1513 1514 if args[0] in ['loop_optimized_output', 'loop_color_flows', 'low_mem_multicore_nlo_generation']: 1515 try: 1516 args[1] = banner_module.ConfigFile.format_variable(args[1], bool, args[0]) 1517 except Exception: 1518 raise self.InvalidCmd('%s needs argument True or False'%args[0]) 1519 1520 if args[0] in ['low_mem_multicore_nlo_generation']: 1521 if args[1]: 1522 if sys.version_info[0] == 2: 1523 if sys.version_info[1] == 6: 1524 raise Exception('python2.6 does not support such functionalities please use python2.7') 1525 #else: 1526 # raise Exception('python3.x does not support such functionalities please use python2.7') 1527 1528 1529 1530 1531 if args[0] in ['gauge']: 1532 if args[1] not in ['unitary','Feynman', 'axial']: 1533 raise self.InvalidCmd('gauge needs argument unitary, axial or Feynman.') 1534 1535 if args[0] in ['timeout']: 1536 if not args[1].isdigit(): 1537 raise self.InvalidCmd('timeout values should be a integer') 1538 1539 if args[0] in ['OLP']: 1540 if args[1] not in MadGraphCmd._OLP_supported: 1541 raise self.InvalidCmd('OLP value should be one of %s'\ 1542 %str(MadGraphCmd._OLP_supported)) 1543 1544 if args[0].lower() in ['ewscheme']: 1545 if not self._curr_model: 1546 raise self.InvalidCmd("ewscheme acts on the current model please load one first.") 1547 if args[1] not in ['external']: 1548 raise self.InvalidCmd('Only valid ewscheme is "external". To restore default, please re-import the model.') 1549 1550 if args[0] in ['output_dependencies']: 1551 if args[1] not in MadGraphCmd._output_dependencies_supported: 1552 raise self.InvalidCmd('output_dependencies value should be one of %s'\ 1553 %str(MadGraphCmd._output_dependencies_supported))
1554
1555 - def check_open(self, args):
1556 """ check the validity of the line """ 1557 1558 if len(args) != 1: 1559 self.help_open() 1560 raise self.InvalidCmd('OPEN command requires exactly one argument') 1561 1562 if args[0].startswith('./'): 1563 if not os.path.isfile(args[0]): 1564 raise self.InvalidCmd('%s: not such file' % args[0]) 1565 return True 1566 1567 # if special : create the path. 1568 if not self._done_export: 1569 if not os.path.isfile(args[0]): 1570 self.help_open() 1571 raise self.InvalidCmd('No command \"output\" or \"launch\" used. Impossible to associate this name to a file') 1572 else: 1573 return True 1574 1575 path = self._done_export[0] 1576 if os.path.isfile(pjoin(path,args[0])): 1577 args[0] = pjoin(path,args[0]) 1578 elif os.path.isfile(pjoin(path,'Cards',args[0])): 1579 args[0] = pjoin(path,'Cards',args[0]) 1580 elif os.path.isfile(pjoin(path,'HTML',args[0])): 1581 args[0] = pjoin(path,'HTML',args[0]) 1582 # special for card with _default define: copy the default and open it 1583 elif '_card.dat' in args[0]: 1584 name = args[0].replace('_card.dat','_card_default.dat') 1585 if os.path.isfile(pjoin(path,'Cards', name)): 1586 files.cp(path + '/Cards/' + name, path + '/Cards/'+ args[0]) 1587 args[0] = pjoin(path,'Cards', args[0]) 1588 else: 1589 raise self.InvalidCmd('No default path for this file') 1590 elif not os.path.isfile(args[0]): 1591 raise self.InvalidCmd('No default path for this file')
1592 1593
1594 - def check_output(self, args, default='madevent'):
1595 """ check the validity of the line""" 1596 1597 if args and args[0] in self._export_formats: 1598 self._export_format = args.pop(0) 1599 elif args: 1600 # check for PLUGIN format 1601 output_cls = misc.from_plugin_import(self.plugin_path, 'new_output', 1602 args[0], warning=True, 1603 info='Output will be done with PLUGIN: %(plug)s') 1604 if output_cls: 1605 self._export_format = 'plugin' 1606 self._export_plugin = output_cls 1607 args.pop(0) 1608 else: 1609 self._export_format = default 1610 else: 1611 self._export_format = default 1612 1613 if not self._curr_model: 1614 text = 'No model found. Please import a model first and then retry.' 1615 raise self.InvalidCmd(text) 1616 1617 if self._model_v4_path and \ 1618 (self._export_format not in self._v4_export_formats): 1619 text = " The Model imported (MG4 format) does not contain enough\n " 1620 text += " information for this type of output. In order to create\n" 1621 text += " output for " + args[0] + ", you have to use a UFO model.\n" 1622 text += " Those model can be imported with MG5> import model NAME." 1623 logger.warning(text) 1624 raise self.InvalidCmd('') 1625 1626 if self._export_format == 'aloha': 1627 return 1628 1629 1630 if not self._curr_amps: 1631 text = 'No processes generated. Please generate a process first.' 1632 raise self.InvalidCmd(text) 1633 1634 if args and args[0][0] != '-': 1635 # This is a path 1636 path = args.pop(0) 1637 forbiden_chars = ['>','<',';','&'] 1638 for char in forbiden_chars: 1639 if char in path: 1640 raise self.InvalidCmd('%s is not allowed in the output path' % char) 1641 # Check for special directory treatment 1642 if path == 'auto' and self._export_format in \ 1643 ['madevent', 'standalone', 'standalone_cpp', 'matchbox_cpp', 'madweight', 1644 'matchbox', 'plugin']: 1645 self.get_default_path() 1646 if '-noclean' not in args and os.path.exists(self._export_dir): 1647 args.append('-noclean') 1648 elif path != 'auto': 1649 if path in ['HELAS', 'tests', 'MadSpin', 'madgraph', 'mg5decay', 'vendor']: 1650 if os.getcwd() == MG5DIR: 1651 raise self.InvalidCmd("This name correspond to a buildin MG5 directory. Please choose another name") 1652 self._export_dir = path 1653 elif path == 'auto': 1654 if self.options['pythia8_path']: 1655 self._export_dir = self.options['pythia8_path'] 1656 else: 1657 self._export_dir = '.' 1658 else: 1659 if self._export_format != 'pythia8': 1660 # No valid path 1661 self.get_default_path() 1662 if '-noclean' not in args and os.path.exists(self._export_dir): 1663 args.append('-noclean') 1664 1665 else: 1666 if self.options['pythia8_path']: 1667 self._export_dir = self.options['pythia8_path'] 1668 else: 1669 self._export_dir = '.' 1670 1671 self._export_dir = os.path.realpath(self._export_dir)
1672 1673
1674 - def check_compute_widths(self, args):
1675 """ check and format calculate decay width: 1676 Expected format: NAME [other names] [--options] 1677 # fill the options if not present. 1678 # NAME can be either (anti-)particle name, multiparticle, pid 1679 """ 1680 1681 if len(args)<1: 1682 self.help_compute_widths() 1683 raise self.InvalidCmd('''compute_widths requires at least the name of one particle. 1684 If you want to compute the width of all particles, type \'compute_widths all\'''') 1685 1686 particles = set() 1687 options = {'path':None, 'output':None, 1688 'min_br':None, 'body_decay':4.0025, 'precision_channel':0.01, 1689 'nlo':False} 1690 # check that the firsts argument is valid 1691 1692 for i,arg in enumerate(args): 1693 if arg.startswith('--'): 1694 if arg.startswith('--nlo'): 1695 options['nlo'] =True 1696 continue 1697 elif not '=' in arg: 1698 raise self.InvalidCmd('Options required an equal (and then the value)') 1699 arg, value = arg.split('=',1) 1700 if arg[2:] not in options: 1701 raise self.InvalidCmd('%s not valid options' % arg) 1702 options[arg[2:]] = value 1703 continue 1704 # check for pid 1705 if arg.isdigit(): 1706 p = self._curr_model.get_particle(int(arg)) 1707 if not p: 1708 raise self.InvalidCmd('Model doesn\'t have pid %s for any particle' % arg) 1709 particles.add(abs(int(arg))) 1710 elif arg in self._multiparticles: 1711 particles.update([abs(id) for id in self._multiparticles[args[0]]]) 1712 else: 1713 if not self._curr_model['case_sensitive']: 1714 arg = arg.lower() 1715 for p in self._curr_model['particles']: 1716 if p['name'] == arg or p['antiname'] == arg: 1717 particles.add(abs(p.get_pdg_code())) 1718 break 1719 else: 1720 if arg == 'all': 1721 #sometimes the multiparticle all is not define 1722 particles.update([abs(p.get_pdg_code()) 1723 for p in self._curr_model['particles']]) 1724 else: 1725 raise self.InvalidCmd('%s invalid particle name' % arg) 1726 1727 if options['path'] and not os.path.isfile(options['path']): 1728 1729 if os.path.exists(pjoin(MG5DIR, options['path'])): 1730 options['path'] = pjoin(MG5DIR, options['path']) 1731 elif self._model_v4_path and os.path.exists(pjoin(self._model_v4_path, options['path'])): 1732 options['path'] = pjoin(self._curr_model_v4_path, options['path']) 1733 elif os.path.exists(pjoin(self._curr_model.path, options['path'])): 1734 options['path'] = pjoin(self._curr_model.path, options['path']) 1735 1736 if os.path.isdir(options['path']) and os.path.isfile(pjoin(options['path'], 'param_card.dat')): 1737 options['path'] = pjoin(options['path'], 'param_card.dat') 1738 elif not os.path.isfile(options['path']): 1739 raise self.InvalidCmd('%s is not a valid path' % args[2]) 1740 # check that the path is indeed a param_card: 1741 if madevent_interface.MadEventCmd.detect_card_type(options['path']) != 'param_card.dat': 1742 raise self.InvalidCmd('%s should be a path to a param_card' % options['path']) 1743 1744 if not options['path']: 1745 param_card_text = self._curr_model.write_param_card() 1746 if not options['output']: 1747 dirpath = self._curr_model.get('modelpath') 1748 options['path'] = pjoin(dirpath, 'param_card.dat') 1749 else: 1750 options['path'] = options['output'] 1751 ff = open(options['path'],'w') 1752 ff.write(param_card_text) 1753 ff.close() 1754 if not options['output']: 1755 options['output'] = options['path'] 1756 1757 if not options['min_br']: 1758 options['min_br'] = (float(options['body_decay']) % 1) / 5 1759 return particles, options
1760 1761 1762 check_decay_diagram = check_compute_widths 1763
1764 - def get_default_path(self):
1765 """Set self._export_dir to the default (\'auto\') path""" 1766 1767 if self._export_format in ['madevent', 'standalone']: 1768 # Detect if this script is launched from a valid copy of the Template, 1769 # if so store this position as standard output directory 1770 if 'TemplateVersion.txt' in os.listdir('.'): 1771 #Check for ./ 1772 self._export_dir = os.path.realpath('.') 1773 return 1774 elif 'TemplateVersion.txt' in os.listdir('..'): 1775 #Check for ../ 1776 self._export_dir = os.path.realpath('..') 1777 return 1778 elif self.stdin != sys.stdin: 1779 #Check for position defined by the input files 1780 input_path = os.path.realpath(self.stdin.name).split(os.path.sep) 1781 print("Not standard stdin, use input path") 1782 if input_path[-2] == 'Cards': 1783 self._export_dir = os.path.sep.join(input_path[:-2]) 1784 if 'TemplateVersion.txt' in self._export_dir: 1785 return 1786 1787 1788 if self._export_format == 'NLO': 1789 name_dir = lambda i: 'PROCNLO_%s_%s' % \ 1790 (self._curr_model['name'], i) 1791 auto_path = lambda i: pjoin(self.writing_dir, 1792 name_dir(i)) 1793 elif self._export_format.startswith('madevent'): 1794 name_dir = lambda i: 'PROC_%s_%s' % \ 1795 (self._curr_model['name'], i) 1796 auto_path = lambda i: pjoin(self.writing_dir, 1797 name_dir(i)) 1798 elif self._export_format.startswith('standalone'): 1799 name_dir = lambda i: 'PROC_SA_%s_%s' % \ 1800 (self._curr_model['name'], i) 1801 auto_path = lambda i: pjoin(self.writing_dir, 1802 name_dir(i)) 1803 elif self._export_format == 'madweight': 1804 name_dir = lambda i: 'PROC_MW_%s_%s' % \ 1805 (self._curr_model['name'], i) 1806 auto_path = lambda i: pjoin(self.writing_dir, 1807 name_dir(i)) 1808 elif self._export_format == 'standalone_cpp': 1809 name_dir = lambda i: 'PROC_SA_CPP_%s_%s' % \ 1810 (self._curr_model['name'], i) 1811 auto_path = lambda i: pjoin(self.writing_dir, 1812 name_dir(i)) 1813 elif self._export_format in ['matchbox_cpp', 'matchbox']: 1814 name_dir = lambda i: 'PROC_MATCHBOX_%s_%s' % \ 1815 (self._curr_model['name'], i) 1816 auto_path = lambda i: pjoin(self.writing_dir, 1817 name_dir(i)) 1818 elif self._export_format in ['plugin']: 1819 name_dir = lambda i: 'PROC_PLUGIN_%s_%s' % \ 1820 (self._curr_model['name'], i) 1821 auto_path = lambda i: pjoin(self.writing_dir, 1822 name_dir(i)) 1823 elif self._export_format == 'pythia8': 1824 if self.options['pythia8_path']: 1825 self._export_dir = self.options['pythia8_path'] 1826 else: 1827 self._export_dir = '.' 1828 return 1829 else: 1830 self._export_dir = '.' 1831 return 1832 for i in range(500): 1833 if os.path.isdir(auto_path(i)): 1834 continue 1835 else: 1836 self._export_dir = auto_path(i) 1837 break 1838 if not self._export_dir: 1839 raise self.InvalidCmd('Can\'t use auto path,' + \ 1840 'more than 500 dirs already')
1841
1842 1843 #=============================================================================== 1844 # CheckValidForCmdWeb 1845 #=============================================================================== 1846 -class CheckValidForCmdWeb(CheckValidForCmd):
1847 """ Check the validity of input line for web entry 1848 (no explicit path authorized)""" 1849
1850 - class WebRestriction(MadGraph5Error):
1851 """class for WebRestriction"""
1852
1853 - def check_draw(self, args):
1854 """check the validity of line 1855 syntax: draw FILEPATH [option=value] 1856 """ 1857 raise self.WebRestriction('direct call to draw is forbidden on the web')
1858
1859 - def check_display(self, args):
1860 """ check the validity of line in web mode """ 1861 1862 if args[0] == 'mg5_variable': 1863 raise self.WebRestriction('Display internal variable is forbidden on the web') 1864 1865 CheckValidForCmd.check_history(self, args)
1866
1867 - def check_check(self, args):
1868 """ Not authorize for the Web""" 1869 1870 raise self.WebRestriction('Check call is forbidden on the web')
1871
1872 - def check_history(self, args):
1873 """check the validity of line 1874 No Path authorize for the Web""" 1875 1876 CheckValidForCmd.check_history(self, args) 1877 1878 if len(args) == 2 and args[1] not in ['.', 'clean']: 1879 raise self.WebRestriction('Path can\'t be specify on the web.')
1880 1881
1882 - def check_import(self, args):
1883 """check the validity of line 1884 No Path authorize for the Web""" 1885 1886 if not args: 1887 raise self.WebRestriction('import requires at least one option') 1888 1889 if args[0] not in self._import_formats: 1890 args[:] = ['command', './proc_card_mg5.dat'] 1891 elif args[0] == 'proc_v4': 1892 args[:] = [args[0], './proc_card.dat'] 1893 elif args[0] == 'command': 1894 args[:] = [args[0], './proc_card_mg5.dat'] 1895 1896 CheckValidForCmd.check_import(self, args)
1897
1898 - def check_install(self, args):
1899 """ No possibility to install new software on the web """ 1900 if args == ['update','--mode=mg5_start']: 1901 return 1902 1903 raise self.WebRestriction('Impossible to install program on the cluster')
1904
1905 - def check_load(self, args):
1906 """ check the validity of the line 1907 No Path authorize for the Web""" 1908 1909 CheckValidForCmd.check_load(self, args) 1910 1911 if len(args) == 2: 1912 if args[0] != 'model': 1913 raise self.WebRestriction('only model can be loaded online') 1914 if 'model.pkl' not in args[1]: 1915 raise self.WebRestriction('not valid pkl file: wrong name') 1916 if not os.path.realpath(args[1]).startswith(pjoin(MG4DIR, \ 1917 'Models')): 1918 raise self.WebRestriction('Wrong path to load model')
1919
1920 - def check_save(self, args):
1921 """ not authorize on web""" 1922 raise self.WebRestriction('\"save\" command not authorize online')
1923
1924 - def check_open(self, args):
1925 """ not authorize on web""" 1926 raise self.WebRestriction('\"open\" command not authorize online')
1927
1928 - def check_output(self, args, default='madevent'):
1929 """ check the validity of the line""" 1930 1931 # first pass to the default 1932 CheckValidForCmd.check_output(self, args, default=default) 1933 args[:] = ['.', '-f'] 1934 1935 self._export_dir = os.path.realpath(os.getcwd()) 1936 # Check that we output madevent 1937 if 'madevent' != self._export_format: 1938 raise self.WebRestriction('only available output format is madevent (at current stage)')
1939
1940 #=============================================================================== 1941 # CompleteForCmd 1942 #=============================================================================== 1943 -class CompleteForCmd(cmd.CompleteCmd):
1944 """ The Series of help routine for the MadGraphCmd""" 1945 1946
1947 - def nlo_completion(self,args,text,line,allowed_loop_mode=None):
1948 """ complete the nlo settings within square brackets. It uses the 1949 allowed_loop_mode for the proposed mode if specified, otherwise, it 1950 uses self._nlo_modes_for_completion""" 1951 1952 # We are now editing the loop related options 1953 # Automatically allow for QCD perturbation if in the sm because the 1954 # loop_sm would then automatically be loaded 1955 nlo_modes = allowed_loop_mode if not allowed_loop_mode is None else \ 1956 self._nlo_modes_for_completion 1957 if isinstance(self._curr_model,loop_base_objects.LoopModel): 1958 pert_couplings_allowed = ['all']+self._curr_model['perturbation_couplings'] 1959 else: 1960 pert_couplings_allowed = [] 1961 if self._curr_model.get('name').startswith('sm'): 1962 pert_couplings_allowed = pert_couplings_allowed + ['QCD'] 1963 # Find wether the loop mode is already set or not 1964 loop_specs = line[line.index('[')+1:] 1965 try: 1966 loop_orders = loop_specs[loop_specs.index('=')+1:] 1967 except ValueError: 1968 loop_orders = loop_specs 1969 possibilities = [] 1970 possible_orders = [order for order in pert_couplings_allowed if \ 1971 order not in loop_orders] 1972 1973 # Simplify obvious loop completion 1974 single_completion = '' 1975 if len(nlo_modes)==1: 1976 single_completion = '%s= '%nlo_modes[0] 1977 if len(possible_orders)==1: 1978 single_completion = single_completion + possible_orders[0] + ' ] ' 1979 # Automatically add a space if not present after [ or = 1980 if text.endswith('['): 1981 if single_completion != '': 1982 return self.list_completion(text, ['[ '+single_completion]) 1983 else: 1984 return self.list_completion(text,['[ ']) 1985 1986 if text.endswith('='): 1987 return self.list_completion(text,[' ']) 1988 1989 if args[-1]=='[': 1990 possibilities = possibilities + ['%s= '%mode for mode in nlo_modes] 1991 if single_completion != '': 1992 return self.list_completion(text, [single_completion]) 1993 else: 1994 if len(possible_orders)==1: 1995 return self.list_completion(text, [poss+' %s ] '%\ 1996 possible_orders[0] for poss in possibilities]) 1997 return self.list_completion(text, possibilities) 1998 1999 if len(possible_orders)==1: 2000 possibilities.append(possible_orders[0]+' ] ') 2001 else: 2002 possibilities.extend(possible_orders) 2003 if any([(order in loop_orders) for order in pert_couplings_allowed]): 2004 possibilities.append(']') 2005 return self.list_completion(text, possibilities)
2006
2007 - def model_completion(self, text, process, line, categories = True, \ 2008 allowed_loop_mode = None, 2009 formatting=True):
2010 """ complete the line with model information. If categories is True, 2011 it will use completion with categories. If allowed_loop_mode is 2012 specified, it will only complete with these loop modes.""" 2013 2014 # First check if we are within squared brackets so that specific 2015 # input for NLO settings must be completed 2016 args = self.split_arg(process) 2017 if len(args) > 2 and '>' in line and '[' in line and not ']' in line: 2018 return self.nlo_completion(args,text,line, allowed_loop_mode = \ 2019 allowed_loop_mode) 2020 2021 while ',' in process: 2022 process = process[process.index(',')+1:] 2023 args = self.split_arg(process) 2024 couplings = [] 2025 2026 # Do no complete the @ for the process number. 2027 if len(args) > 1 and args[-1]=='@': 2028 return 2029 2030 # Automatically allow for QCD perturbation if in the sm because the 2031 # loop_sm would then automatically be loaded 2032 if isinstance(self._curr_model,loop_base_objects.LoopModel): 2033 pert_couplings_allowed = ['all'] + self._curr_model['perturbation_couplings'] 2034 else: 2035 pert_couplings_allowed = [] 2036 if self._curr_model.get('name').startswith('sm'): 2037 pert_couplings_allowed = pert_couplings_allowed + ['QCD'] 2038 2039 # Remove possible identical names 2040 particles = list(set(self._particle_names + list(self._multiparticles.keys()))) 2041 n_part_entered = len([1 for a in args if a in particles]) 2042 2043 # Force '>' if two initial particles. 2044 if n_part_entered == 2 and args[-1] != '>': 2045 return self.list_completion(text, '>') 2046 2047 # Add non-particle names 2048 syntax = [] 2049 couplings = [] 2050 if len(args) > 0 and args[-1] != '>' and n_part_entered > 0: 2051 syntax.append('>') 2052 if '>' in args and args.index('>') < len(args) - 1: 2053 couplings.extend(sum([[c+"<=", c+"==", c+">",c+'^2<=',c+'^2==',c+'^2>' ] for c in \ 2054 self._couplings+['WEIGHTED']],[])) 2055 syntax.extend(['@','$','/','>',',']) 2056 if '[' not in line and ',' not in line and len(pert_couplings_allowed)>0: 2057 syntax.append('[') 2058 2059 # If information for the virtuals has been specified already, do not 2060 # propose syntax or particles input anymore 2061 if '[' in line: 2062 syntax = [] 2063 particles = [] 2064 # But still allow for defining the process id 2065 couplings.append('@') 2066 2067 if not categories: 2068 # The direct completion (might be needed for some completion using 2069 # this function but adding some other completions (like in check)). 2070 # For those, it looks ok in the categorie mode on my mac, but if 2071 # someone sees wierd result on Linux systems, then use the 2072 # default completion for these features. 2073 return self.list_completion(text, particles+syntax+couplings) 2074 else: 2075 # A more elaborate one with categories 2076 poss_particles = self.list_completion(text, particles) 2077 poss_syntax = self.list_completion(text, syntax) 2078 poss_couplings = self.list_completion(text, couplings) 2079 possibilities = {} 2080 if poss_particles != []: possibilities['Particles']=poss_particles 2081 if poss_syntax != []: possibilities['Syntax']=poss_syntax 2082 if poss_couplings != []: possibilities['Coupling orders']=poss_couplings 2083 if len(list(possibilities.keys()))==1: 2084 return self.list_completion(text, list(possibilities.values())[0]) 2085 else: 2086 return self.deal_multiple_categories(possibilities, formatting)
2087
2088 - def complete_generate(self, text, line, begidx, endidx, formatting=True):
2089 "Complete the generate command" 2090 2091 # Return list of particle names and multiparticle names, as well as 2092 # coupling orders and allowed symbols 2093 args = self.split_arg(line[0:begidx]) 2094 2095 valid_sqso_operators=['==','<=','>'] 2096 2097 if any(line.endswith('^2 %s '%op) for op in valid_sqso_operators): 2098 return 2099 if args[-1].endswith('^2'): 2100 return self.list_completion(text,valid_sqso_operators) 2101 match_op = [o for o in valid_sqso_operators if o.startswith(args[-1])] 2102 if len(args)>2 and args[-2].endswith('^2') and len(match_op)>0: 2103 if args[-1] in valid_sqso_operators: 2104 return self.list_completion(text,' ') 2105 if len(match_op)==1: 2106 return self.list_completion(text,[match_op[0][len(args[-1]):]]) 2107 else: 2108 return self.list_completion(text,match_op) 2109 if len(args) > 2 and args[-1] == '@' or ( args[-1].endswith('=') and \ 2110 (not '[' in line or ('[' in line and ']' in line))): 2111 return 2112 2113 try: 2114 return self.model_completion(text, ' '.join(args[1:]),line, formatting) 2115 except Exception as error: 2116 print(error)
2117 2118 #if len(args) > 1 and args[-1] != '>': 2119 # couplings = ['>'] 2120 #if '>' in args and args.index('>') < len(args) - 1: 2121 # couplings = [c + "=" for c in self._couplings] + ['@','$','/','>'] 2122 #return self.list_completion(text, self._particle_names + \ 2123 # self._multiparticles.keys() + couplings) 2124
2125 - def complete_convert(self, text, line, begidx, endidx,formatting=True):
2126 "Complete the compute_widths command" 2127 2128 args = self.split_arg(line[0:begidx]) 2129 2130 # Format 2131 if len(args) == 1: 2132 return self.list_completion(text, ['model']) 2133 elif line[begidx-1] == os.path.sep: 2134 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)]) 2135 return self.path_completion(text, current_dir) 2136 else: 2137 return self.path_completion(text)
2138 2139
2140 - def complete_compute_widths(self, text, line, begidx, endidx,formatting=True):
2141 "Complete the compute_widths command" 2142 2143 args = self.split_arg(line[0:begidx]) 2144 2145 if args[-1] in ['--path=', '--output=']: 2146 completion = {'path': self.path_completion(text)} 2147 elif line[begidx-1] == os.path.sep: 2148 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)]) 2149 if current_dir.startswith('--path='): 2150 current_dir = current_dir[7:] 2151 if current_dir.startswith('--output='): 2152 current_dir = current_dir[9:] 2153 completion = {'path': self.path_completion(text, current_dir)} 2154 else: 2155 completion = {} 2156 completion['options'] = self.list_completion(text, 2157 ['--path=', '--output=', '--min_br=0.\$', 2158 '--precision_channel=0.\$', '--body_decay=', '--nlo']) 2159 completion['particles'] = self.model_completion(text, '', line) 2160 2161 return self.deal_multiple_categories(completion,formatting)
2162 2163 complete_decay_diagram = complete_compute_widths 2164
2165 - def complete_add(self, text, line, begidx, endidx, formatting):
2166 "Complete the add command" 2167 2168 args = self.split_arg(line[0:begidx]) 2169 2170 # Format 2171 if len(args) == 1: 2172 return self.list_completion(text, self._add_opts) 2173 2174 if args[1] == 'process': 2175 return self.complete_generate(text, " ".join(args[1:]), begidx, endidx) 2176 2177 elif args[1] == 'model': 2178 completion_categories = self.complete_import(text, line, begidx, endidx, 2179 allow_restrict=False, formatting=False) 2180 completion_categories['options'] = self.list_completion(text,['--modelname=','--recreate']) 2181 return self.deal_multiple_categories(completion_categories, formatting)
2182
2183 - def complete_customize_model(self, text, line, begidx, endidx):
2184 "Complete the customize_model command" 2185 2186 args = self.split_arg(line[0:begidx]) 2187 2188 # Format 2189 if len(args) == 1: 2190 return self.list_completion(text, ['--save='])
2191 2192
2193 - def complete_check(self, text, line, begidx, endidx, formatting=True):
2194 "Complete the check command" 2195 2196 out = {} 2197 args = self.split_arg(line[0:begidx]) 2198 2199 # Format 2200 if len(args) == 1: 2201 return self.list_completion(text, self._check_opts) 2202 2203 2204 cms_check_mode = len(args) >= 2 and args[1]=='cms' 2205 2206 cms_options = ['--name=','--tweak=','--seed=','--offshellness=', 2207 '--lambdaCMS=','--show_plot=','--report=','--lambda_plot_range=','--recompute_width=', 2208 '--CTModeRun=','--helicity=','--reduction=','--cms=','--diff_lambda_power=', 2209 '--loop_filter=','--resonances='] 2210 2211 options = ['--energy='] 2212 if cms_options: 2213 options.extend(cms_options) 2214 2215 # Directory continuation 2216 if args[-1].endswith(os.path.sep): 2217 return self.path_completion(text, pjoin(*[a for a in args \ 2218 if a.endswith(os.path.sep)])) 2219 # autocompletion for particles/couplings 2220 model_comp = self.model_completion(text, ' '.join(args[2:]),line, 2221 categories = True, allowed_loop_mode=['virt']) 2222 2223 model_comp_and_path = self.deal_multiple_categories(\ 2224 {'Process completion': self.model_completion(text, ' '.join(args[2:]), 2225 line, categories = False, allowed_loop_mode=['virt']), 2226 'Param_card.dat path completion:':self.path_completion(text), 2227 'options': self.list_completion(text,options)}, formatting) 2228 2229 #Special rules for check cms completion 2230 if cms_check_mode: 2231 # A couple of useful value completions 2232 if line[-1]!=' ' and line[-2]!='\\' and not '--' in line[begidx:endidx] \ 2233 and args[-1].startswith('--') and '=' in args[-1]: 2234 examples = { 2235 '--tweak=': 2236 ['default','alltweaks',"['default','allwidths->1.1*all_withds&seed333(Increased_widths_and_seed_333)','logp->logm&logm->logp(inverted_logs)']"], 2237 '--lambdaCMS=': 2238 ['(1.0e-2,5)',"[float('1.0e-%d'%exp)\\ for\\ exp\\ in\\ range(8)]","[1.0,0.5,0.001]"], 2239 '--lambda_plot_range=': 2240 [' [1e-05,1e-02]','[0.01,1.0]'], 2241 '--reduction=': 2242 ['1','1|2|3|4','1|2','3'], 2243 '--cms=': 2244 ['QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS', 2245 'NP&QED&QCD,aewm1->10.0/lambdaCMS&as->0.1*lambdaCMS&newExpansionParameter->newExpansionParameter*lambdaCMS'], 2246 '--loop_filter=': 2247 ['None','n>3','n<4 and 6 in loop_pdgs and 3<=id<=7'], 2248 '--resonances=': 2249 ['1','all','(24,(3,4))','[(24,(3,4)),(24,(4,5))]'], 2250 '--analyze=': 2251 ['my_default_run.pkl', 2252 'default_run.pkl,increased_widths.pkl(Increased_widths),logs_modified.pkl(Inverted_logs),seed_668.pkl(Different_seed)'] 2253 } 2254 for name, example in examples.items(): 2255 if args[-1].startswith(name): 2256 return self.deal_multiple_categories( 2257 {"Examples of completion for option '%s'"%args[-1].split('=')[0]: 2258 # ['%d: %s'%(i+1,ex) for i, ex in enumerate(example)]}, 2259 ['%s'%ex for i, ex in enumerate(example)]},formatting, 2260 forceCategory=True) 2261 if args[-1]=='--recompute_width=': 2262 return self.list_completion(text, 2263 ['never','first_time','always','auto']) 2264 elif args[-1]=='--show_plot=': 2265 return self.list_completion(text,['True','False']) 2266 elif args[-1]=='--report=': 2267 return self.list_completion(text,['concise','full']) 2268 elif args[-1]=='--CTModeRun=': 2269 return self.list_completion(text,['-1','1','2','3','4']) 2270 else: 2271 return text 2272 if len(args)==2 or len(args)==3 and args[-1]=='-reuse': 2273 return self.deal_multiple_categories( 2274 {'Process completion': self.model_completion(text, ' '.join(args[2:]), 2275 line, categories = False, allowed_loop_mode=['virt']), 2276 'Param_card.dat path completion:': self.path_completion(text), 2277 'reanalyze result on disk / save output:':self.list_completion( 2278 text,['-reuse','--analyze='])}, 2279 formatting) 2280 elif not any(arg.startswith('--') for arg in args): 2281 if '>' in args: 2282 return self.deal_multiple_categories({'Process completion': 2283 self.model_completion(text, ' '.join(args[2:]), 2284 line, categories = False, allowed_loop_mode=['virt']), 2285 'options': self.list_completion(text,options)}, 2286 formatting) 2287 else: 2288 return self.deal_multiple_categories({'Process completion': 2289 self.model_completion(text, ' '.join(args[2:]), 2290 line, categories = False, allowed_loop_mode=['virt'])}, 2291 formatting) 2292 else: 2293 return self.list_completion(text,options) 2294 2295 if len(args) == 2: 2296 return model_comp_and_path 2297 elif len(args) == 3: 2298 try: 2299 int(args[2]) 2300 except ValueError: 2301 return model_comp 2302 else: 2303 return model_comp_and_path 2304 elif len(args) > 3: 2305 return model_comp
2306 2307
2308 - def complete_tutorial(self, text, line, begidx, endidx):
2309 "Complete the tutorial command" 2310 2311 # Format 2312 if len(self.split_arg(line[0:begidx])) == 1: 2313 return self.list_completion(text, self._tutorial_opts)
2314
2315 - def complete_define(self, text, line, begidx, endidx):
2316 """Complete particle information""" 2317 return self.model_completion(text, line[6:],line)
2318
2319 - def complete_display(self, text, line, begidx, endidx):
2320 "Complete the display command" 2321 2322 args = self.split_arg(line[0:begidx]) 2323 # Format 2324 if len(args) == 1: 2325 return self.list_completion(text, self._display_opts) 2326 2327 if len(args) == 2 and args[1] == 'checks': 2328 return self.list_completion(text, ['failed']) 2329 2330 if len(args) == 2 and args[1] == 'particles': 2331 return self.model_completion(text, line[begidx:],line)
2332
2333 - def complete_draw(self, text, line, begidx, endidx):
2334 "Complete the draw command" 2335 2336 args = self.split_arg(line[0:begidx]) 2337 2338 # Directory continuation 2339 if args[-1].endswith(os.path.sep): 2340 return self.path_completion(text, 2341 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2342 only_dirs = True) 2343 # Format 2344 if len(args) == 1: 2345 return self.path_completion(text, '.', only_dirs = True) 2346 2347 2348 #option 2349 if len(args) >= 2: 2350 opt = ['horizontal', 'external=', 'max_size=', 'add_gap=', 2351 'non_propagating', '--'] 2352 return self.list_completion(text, opt)
2353
2354 - def complete_launch(self, text, line, begidx, endidx,formatting=True):
2355 """ complete the launch command""" 2356 args = self.split_arg(line[0:begidx]) 2357 2358 # Directory continuation 2359 if args[-1].endswith(os.path.sep): 2360 return self.path_completion(text, 2361 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2362 only_dirs = True) 2363 # Format 2364 if len(args) == 1: 2365 out = {'Path from ./': self.path_completion(text, '.', only_dirs = True)} 2366 if MG5DIR != os.path.realpath('.'): 2367 out['Path from %s' % MG5DIR] = self.path_completion(text, 2368 MG5DIR, only_dirs = True, relative=False) 2369 if MG4DIR and MG4DIR != os.path.realpath('.') and MG4DIR != MG5DIR: 2370 out['Path from %s' % MG4DIR] = self.path_completion(text, 2371 MG4DIR, only_dirs = True, relative=False) 2372 2373 2374 #option 2375 if len(args) >= 2: 2376 out={} 2377 2378 if line[0:begidx].endswith('--laststep='): 2379 opt = ['parton', 'pythia', 'pgs','delphes','auto'] 2380 out['Options'] = self.list_completion(text, opt, line) 2381 else: 2382 opt = ['--cluster', '--multicore', '-i', '--name=', '-f','-m', '-n', 2383 '-p','--parton','--interactive', '--laststep=parton', '--laststep=pythia', 2384 '--laststep=pgs', '--laststep=delphes','--laststep=auto'] 2385 out['Options'] = self.list_completion(text, opt, line) 2386 2387 2388 return self.deal_multiple_categories(out,formatting)
2389
2390 - def complete_load(self, text, line, begidx, endidx):
2391 "Complete the load command" 2392 2393 args = self.split_arg(line[0:begidx]) 2394 2395 # Format 2396 if len(args) == 1: 2397 return self.list_completion(text, self._save_opts) 2398 2399 # Directory continuation 2400 if args[-1].endswith(os.path.sep): 2401 return self.path_completion(text, 2402 pjoin(*[a for a in args if \ 2403 a.endswith(os.path.sep)])) 2404 2405 # Filename if directory is not given 2406 if len(args) == 2: 2407 return self.path_completion(text)
2408
2409 - def complete_save(self, text, line, begidx, endidx):
2410 "Complete the save command" 2411 2412 args = self.split_arg(line[0:begidx]) 2413 2414 # Format 2415 if len(args) == 1: 2416 return self.list_completion(text, self._save_opts) 2417 2418 # Directory continuation 2419 if args[-1].endswith(os.path.sep): 2420 return self.path_completion(text, 2421 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2422 only_dirs = True) 2423 2424 # Filename if directory is not given 2425 if len(args) == 2: 2426 return self.path_completion(text) + self.list_completion(text, ['global'])
2427 2428 @cmd.debug()
2429 - def complete_open(self, text, line, begidx, endidx):
2430 """ complete the open command """ 2431 2432 args = self.split_arg(line[0:begidx]) 2433 2434 # Directory continuation 2435 if os.path.sep in args[-1] + text: 2436 return self.path_completion(text, 2437 pjoin(*[a for a in args if \ 2438 a.endswith(os.path.sep)])) 2439 2440 possibility = [] 2441 if self._done_export: 2442 path = self._done_export[0] 2443 possibility = ['index.html'] 2444 if os.path.isfile(pjoin(path,'README')): 2445 possibility.append('README') 2446 if os.path.isdir(pjoin(path,'Cards')): 2447 possibility += [f for f in os.listdir(pjoin(path,'Cards')) 2448 if f.endswith('.dat')] 2449 if os.path.isdir(pjoin(path,'HTML')): 2450 possibility += [f for f in os.listdir(pjoin(path,'HTML')) 2451 if f.endswith('.html') and 'default' not in f] 2452 else: 2453 possibility.extend(['./','../']) 2454 if os.path.exists('MG5_debug'): 2455 possibility.append('MG5_debug') 2456 if os.path.exists('ME5_debug'): 2457 possibility.append('ME5_debug') 2458 2459 return self.list_completion(text, possibility)
2460 2461 @cmd.debug()
2462 - def complete_output(self, text, line, begidx, endidx, 2463 possible_options = ['f', 'noclean', 'nojpeg'], 2464 possible_options_full = ['-f', '-noclean', '-nojpeg', '--noeps=True']):
2465 "Complete the output command" 2466 2467 possible_format = self._export_formats 2468 #don't propose directory use by MG_ME 2469 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS', 2470 'Calculators', 'MadAnalysis', 'SimpleAnalysis', 2471 'mg5', 'DECAY', 'EventConverter', 'Models', 2472 'ExRootAnalysis', 'HELAS', 'Transfer_Fct', 'aloha', 2473 'matchbox', 'matchbox_cpp', 'tests'] 2474 2475 #name of the run =>proposes old run name 2476 args = self.split_arg(line[0:begidx]) 2477 if len(args) >= 1: 2478 2479 if len(args) > 1 and args[1] == 'pythia8': 2480 possible_options_full = list(possible_options_full) + ['--version=8.1','--version=8.2'] 2481 2482 if len(args) > 1 and args[1] == 'aloha': 2483 try: 2484 return self.aloha_complete_output(text, line, begidx, endidx) 2485 except Exception as error: 2486 print(error) 2487 # Directory continuation 2488 if args[-1].endswith(os.path.sep): 2489 return [name for name in self.path_completion(text, 2490 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2491 only_dirs = True) if name not in forbidden_names] 2492 # options 2493 if args[-1][0] == '-' or len(args) > 1 and args[-2] == '-': 2494 return self.list_completion(text, possible_options) 2495 2496 if len(args) > 2: 2497 return self.list_completion(text, possible_options_full) 2498 # Formats 2499 if len(args) == 1: 2500 format = possible_format + ['.' + os.path.sep, '..' + os.path.sep, 'auto'] 2501 return self.list_completion(text, format) 2502 2503 # directory names 2504 content = [name for name in self.path_completion(text, '.', only_dirs = True) \ 2505 if name not in forbidden_names] 2506 content += ['auto'] 2507 content += possible_options_full 2508 return self.list_completion(text, content)
2509
2510 - def aloha_complete_output(self, text, line, begidx, endidx,formatting=True):
2511 "Complete the output aloha command" 2512 args = self.split_arg(line[0:begidx]) 2513 completion_categories = {} 2514 2515 forbidden_names = ['MadGraphII', 'Template', 'pythia-pgs', 'CVS', 2516 'Calculators', 'MadAnalysis', 'SimpleAnalysis', 2517 'mg5', 'DECAY', 'EventConverter', 'Models', 2518 'ExRootAnalysis', 'Transfer_Fct', 'aloha', 2519 'apidoc','vendor'] 2520 2521 2522 # options 2523 options = ['--format=Fortran', '--format=Python','--format=gpu','--format=CPP','--output='] 2524 options = self.list_completion(text, options) 2525 if options: 2526 completion_categories['options'] = options 2527 2528 if args[-1] == '--output=' or args[-1].endswith(os.path.sep): 2529 # Directory continuation 2530 completion_categories['path'] = [name for name in self.path_completion(text, 2531 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2532 only_dirs = True) if name not in forbidden_names] 2533 2534 else: 2535 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 2536 wf_opt = [] 2537 amp_opt = [] 2538 opt_conjg = [] 2539 for lor in ufomodel.all_lorentz: 2540 amp_opt.append('%s_0' % lor.name) 2541 for i in range(len(lor.spins)): 2542 wf_opt.append('%s_%i' % (lor.name,i+1)) 2543 if i % 2 == 0 and lor.spins[i] == 2: 2544 opt_conjg.append('%sC%i_%i' % (lor.name,i //2 +1,i+1)) 2545 completion_categories['amplitude routines'] = self.list_completion(text, amp_opt) 2546 completion_categories['Wavefunctions routines'] = self.list_completion(text, wf_opt) 2547 completion_categories['conjugate_routines'] = self.list_completion(text, opt_conjg) 2548 2549 return self.deal_multiple_categories(completion_categories,formatting)
2550
2551 - def complete_set(self, text, line, begidx, endidx):
2552 "Complete the set command" 2553 #misc.sprint([text,line,begidx, endidx]) 2554 args = self.split_arg(line[0:begidx]) 2555 2556 # Format 2557 if len(args) == 1: 2558 opts = list(set(list(self.options.keys()) + self._set_options)) 2559 return self.list_completion(text, opts) 2560 2561 if len(args) == 2: 2562 if args[1] in ['group_subprocesses', 'complex_mass_scheme',\ 2563 'loop_optimized_output', 'loop_color_flows',\ 2564 'low_mem_multicore_nlo_generation']: 2565 return self.list_completion(text, ['False', 'True', 'default']) 2566 elif args[1] in ['ignore_six_quark_processes']: 2567 return self.list_completion(text, list(self._multiparticles.keys())) 2568 elif args[1].lower() == 'ewscheme': 2569 return self.list_completion(text, ["external"]) 2570 elif args[1] == 'gauge': 2571 return self.list_completion(text, ['unitary', 'Feynman','default', 'axial']) 2572 elif args[1] == 'OLP': 2573 return self.list_completion(text, MadGraphCmd._OLP_supported) 2574 elif args[1] == 'output_dependencies': 2575 return self.list_completion(text, 2576 MadGraphCmd._output_dependencies_supported) 2577 elif args[1] == 'stdout_level': 2578 return self.list_completion(text, ['DEBUG','INFO','WARNING','ERROR', 2579 'CRITICAL','default']) 2580 elif args[1] == 'fortran_compiler': 2581 return self.list_completion(text, ['f77','g77','gfortran','default']) 2582 elif args[1] == 'cpp_compiler': 2583 return self.list_completion(text, ['g++', 'c++', 'clang', 'default']) 2584 elif args[1] == 'nb_core': 2585 return self.list_completion(text, [str(i) for i in range(100)] + ['default'] ) 2586 elif args[1] == 'run_mode': 2587 return self.list_completion(text, [str(i) for i in range(3)] + ['default']) 2588 elif args[1] == 'cluster_type': 2589 return self.list_completion(text, list(cluster.from_name.keys()) + ['default']) 2590 elif args[1] == 'cluster_queue': 2591 return [] 2592 elif args[1] == 'automatic_html_opening': 2593 return self.list_completion(text, ['False', 'True', 'default']) 2594 else: 2595 # directory names 2596 second_set = [name for name in self.path_completion(text, '.', only_dirs = True)] 2597 return self.list_completion(text, second_set + ['default']) 2598 elif len(args) >2 and args[-1].endswith(os.path.sep): 2599 return self.path_completion(text, 2600 pjoin(*[a for a in args if a.endswith(os.path.sep)]), 2601 only_dirs = True)
2602
2603 - def complete_import(self, text, line, begidx, endidx, allow_restrict=True, 2604 formatting=True):
2605 "Complete the import command" 2606 2607 args=self.split_arg(line[0:begidx]) 2608 2609 # Format 2610 if len(args) == 1: 2611 opt = self.list_completion(text, self._import_formats) 2612 if opt: 2613 return opt 2614 mode = 'all' 2615 elif args[1] in self._import_formats: 2616 mode = args[1] 2617 else: 2618 args.insert(1, 'all') 2619 mode = 'all' 2620 2621 completion_categories = {} 2622 # restriction continuation (for UFO) 2623 if mode in ['model', 'all'] and '-' in text: 2624 # deal with - in readline splitting (different on some computer) 2625 path = '-'.join([part for part in text.split('-')[:-1]]) 2626 # remove the final - for the model name 2627 # find the different possibilities 2628 all_name = self.find_restrict_card(path, no_restrict=False) 2629 all_name += self.find_restrict_card(path, no_restrict=False, 2630 base_dir=pjoin(MG5DIR,'models')) 2631 2632 if os.environ['PYTHONPATH']: 2633 for modeldir in os.environ['PYTHONPATH'].split(':'): 2634 if not modeldir: 2635 continue 2636 all_name += self.find_restrict_card(path, no_restrict=False, 2637 base_dir=modeldir) 2638 all_name = list(set(all_name)) 2639 # select the possibility according to the current line 2640 all_name = [name+' ' for name in all_name if name.startswith(text) 2641 and name.strip() != text] 2642 2643 2644 if all_name: 2645 completion_categories['Restricted model'] = all_name 2646 2647 # Path continuation 2648 if os.path.sep in args[-1]: 2649 if mode.startswith('model') or mode == 'all': 2650 # Directory continuation 2651 try: 2652 cur_path = pjoin(*[a for a in args \ 2653 if a.endswith(os.path.sep)]) 2654 except Exception as error: 2655 pass 2656 else: 2657 all_dir = self.path_completion(text, cur_path, only_dirs = True) 2658 if mode in ['model_v4','all']: 2659 completion_categories['Path Completion'] = all_dir 2660 # Only UFO model here 2661 new = [] 2662 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path, online=False)) 2663 for name in all_dir] 2664 if data: 2665 completion_categories['Path Completion'] = all_dir + new 2666 else: 2667 try: 2668 cur_path = pjoin(*[a for a in args \ 2669 if a.endswith(os.path.sep)]) 2670 except Exception: 2671 pass 2672 else: 2673 all_path = self.path_completion(text, cur_path) 2674 if mode == 'all': 2675 new = [] 2676 data = [new.__iadd__(self.find_restrict_card(name, base_dir=cur_path, online=False)) 2677 for name in all_path] 2678 if data: 2679 completion_categories['Path Completion'] = data[0] 2680 else: 2681 completion_categories['Path Completion'] = all_path 2682 2683 # Model directory name if directory is not given 2684 if (len(args) == 2): 2685 is_model = True 2686 if mode == 'model': 2687 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) 2688 mod_name = lambda name: name 2689 elif mode == 'model_v4': 2690 file_cond = lambda p : (os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) 2691 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat'))) 2692 mod_name = lambda name :(name[-3:] != '_v4' and name or name[:-3]) 2693 elif mode == 'all': 2694 mod_name = lambda name: name 2695 file_cond = lambda p : os.path.exists(pjoin(MG5DIR,'models',p,'particles.py')) \ 2696 or os.path.exists(pjoin(MG5DIR,'models',p,'particles.dat')) \ 2697 or os.path.exists(pjoin(self._mgme_dir,'Models',p,'particles.dat')) 2698 else: 2699 cur_path = pjoin(*[a for a in args \ 2700 if a.endswith(os.path.sep)]) 2701 all_path = self.path_completion(text, cur_path) 2702 completion_categories['model name'] = all_path 2703 is_model = False 2704 2705 if is_model and os.path.sep not in text: 2706 model_list = [mod_name(name) for name in \ 2707 self.path_completion(text, 2708 pjoin(MG5DIR,'models'), 2709 only_dirs = True) \ 2710 if file_cond(name)] 2711 if mode == 'model' and 'PYTHONPATH' in os.environ: 2712 for modeldir in os.environ['PYTHONPATH'].split(':'): 2713 if not modeldir or not os.path.exists(modeldir): 2714 continue 2715 model_list += [name for name in self.path_completion(text, 2716 modeldir, only_dirs=True) 2717 if os.path.exists(pjoin(modeldir,name, 'particles.py'))] 2718 if mode == 'model': 2719 model_list += [name for name in list(self._online_model.keys())+self._online_model2 2720 if name.startswith(text)] 2721 2722 if mode == 'model_v4': 2723 completion_categories['model name'] = model_list 2724 elif allow_restrict: 2725 # need to update the list with the possible restriction 2726 all_name = [] 2727 for model_name in model_list: 2728 all_name += self.find_restrict_card(model_name, 2729 base_dir=pjoin(MG5DIR,'models')) 2730 else: 2731 all_name = model_list 2732 2733 #avoid duplication 2734 all_name = list(set(all_name)) 2735 2736 if mode == 'all': 2737 cur_path = pjoin(*[a for a in args \ 2738 if a.endswith(os.path.sep)]) 2739 all_path = self.path_completion(text, cur_path) 2740 completion_categories['model name'] = all_path + all_name 2741 elif mode == 'model': 2742 completion_categories['model name'] = all_name 2743 elif os.path.sep in text: 2744 try: 2745 cur_path = pjoin(*[a for a in args \ 2746 if a.endswith(os.path.sep)]) 2747 except Exception: 2748 cur_path = os.getcwd() 2749 all_path = self.path_completion(text, cur_path) 2750 completion_categories['model name'] = all_path 2751 2752 # Options 2753 if mode == 'all' and len(args)>1: 2754 mode = self.find_import_type(args[2]) 2755 2756 if len(args) >= 3 and mode.startswith('model') and not '-modelname' in line: 2757 if not text and not completion_categories: 2758 return ['--modelname'] 2759 elif not (os.path.sep in args[-1] and line[-1] != ' '): 2760 completion_categories['options'] = self.list_completion(text, ['--modelname','-modelname','--noprefix']) 2761 if len(args) >= 3 and mode.startswith('banner') and not '--no_launch' in line: 2762 completion_categories['options'] = self.list_completion(text, ['--no_launch']) 2763 2764 return self.deal_multiple_categories(completion_categories,formatting)
2765 2766 _online_model = {'2HDM':[], 2767 'loop_qcd_qed_sm':['full','no_widths','with_b_mass ', 'with_b_mass_no_widths'], 2768 'loop_qcd_qed_sm_Gmu':['ckm', 'full', 'no_widths'], 2769 '4Gen':[], 2770 'DY_SM':[], 2771 'EWdim6':['full'], 2772 'heft':['ckm','full', 'no_b_mass','no_masses','no_tau_mass','zeromass_ckm'], 2773 'nmssm':['full'], 2774 'SMScalars':['full'], 2775 'RS':[''], 2776 'sextet_diquarks':[''], 2777 'TopEffTh':[''], 2778 'triplet_diquarks':[''], 2779 'uutt_sch_4fermion':[''], 2780 'uutt_tch_scalar':[''] 2781 } 2782 _online_model2 = [] # fill by model on the db if user do "display modellist" 2783
2784 - def find_restrict_card(self, model_name, base_dir='./', no_restrict=True, 2785 online=True):
2786 """find the restriction file associate to a given model""" 2787 2788 # check if the model_name should be keeped as a possibility 2789 if no_restrict: 2790 output = [model_name] 2791 else: 2792 output = [] 2793 2794 local_model = os.path.exists(pjoin(base_dir, model_name, 'couplings.py')) 2795 # check that the model is a valid model 2796 if online and not local_model and model_name in self._online_model: 2797 output += ['%s-%s' % (model_name, tag) for tag in self._online_model[model_name]] 2798 return output 2799 2800 if not local_model: 2801 # not valid UFO model 2802 return output 2803 2804 if model_name.endswith(os.path.sep): 2805 model_name = model_name[:-1] 2806 2807 # look for _default and treat this case 2808 if os.path.exists(pjoin(base_dir, model_name, 'restrict_default.dat')): 2809 output.append('%s-full' % model_name) 2810 2811 # look for other restrict_file 2812 for name in os.listdir(pjoin(base_dir, model_name)): 2813 if name.startswith('restrict_') and not name.endswith('default.dat') \ 2814 and name.endswith('.dat'): 2815 tag = name[9:-4] #remove restrict and .dat 2816 while model_name.endswith(os.path.sep): 2817 model_name = model_name[:-1] 2818 output.append('%s-%s' % (model_name, tag)) 2819 2820 # return 2821 return output
2822
2823 - def complete_install(self, text, line, begidx, endidx):
2824 "Complete the import command" 2825 2826 args = self.split_arg(line[0:begidx]) 2827 # Format 2828 if len(args) == 1: 2829 return self.list_completion(text, self._install_opts + self._advanced_install_opts) 2830 elif len(args) and args[0] == 'update': 2831 return self.list_completion(text, ['-f','--timeout=']) 2832 elif len(args)>=2 and args[1] in self._advanced_install_opts: 2833 options = ['--keep_source','--logging='] 2834 if args[1]=='pythia8': 2835 options.append('--pythia8_tarball=') 2836 elif args[1]=='mg5amc_py8_interface': 2837 options.append('--mg5amc_py8_interface_tarball=') 2838 elif args[1] in ['MadAnalysis5','MadAnalysis']: 2839 #options.append('--no_MA5_further_install') 2840 options.append('--no_root_in_MA5') 2841 options.append('--update') 2842 options.append('--madanalysis5_tarball=') 2843 for prefix in ['--with', '--veto']: 2844 for prog in ['fastjet', 'delphes', 'delphesMA5tune']: 2845 options.append('%s_%s' % (prefix, prog)) 2846 2847 for opt in options[:]: 2848 if any(a.startswith(opt) for a in args): 2849 options.remove(opt) 2850 return self.list_completion(text, options) 2851 else: 2852 return self.list_completion(text, [])
2853
2854 #=============================================================================== 2855 # MadGraphCmd 2856 #=============================================================================== 2857 -class MadGraphCmd(HelpToCmd, CheckValidForCmd, CompleteForCmd, CmdExtended):
2858 """The command line processor of MadGraph""" 2859 2860 writing_dir = '.' 2861 2862 # Options and formats available 2863 _display_opts = ['particles', 'interactions', 'processes', 'diagrams', 2864 'diagrams_text', 'multiparticles', 'couplings', 'lorentz', 2865 'checks', 'parameters', 'options', 'coupling_order','variable', 2866 'modellist'] 2867 _add_opts = ['process', 'model'] 2868 _save_opts = ['model', 'processes', 'options'] 2869 _tutorial_opts = ['aMCatNLO', 'stop', 'MadLoop', 'MadGraph5'] 2870 _switch_opts = ['mg5','aMC@NLO','ML5'] 2871 _check_opts = ['full', 'timing', 'stability', 'profile', 'permutation', 2872 'gauge','lorentz', 'brs', 'cms'] 2873 _import_formats = ['model_v4', 'model', 'proc_v4', 'command', 'banner'] 2874 _install_opts = ['Delphes', 'MadAnalysis4', 'ExRootAnalysis', 2875 'update', 'Golem95', 'QCDLoop', 'maddm', 'maddump', 2876 'looptools', 'MadSTR'] 2877 2878 # The targets below are installed using the HEPToolsInstaller.py script 2879 _advanced_install_opts = ['pythia8','zlib','boost','lhapdf6','lhapdf5','collier', 2880 'hepmc','mg5amc_py8_interface','ninja','oneloop','MadAnalysis5'] 2881 2882 _install_opts.extend(_advanced_install_opts) 2883 2884 _v4_export_formats = ['madevent', 'standalone', 'standalone_msP','standalone_msF', 2885 'matrix', 'standalone_rw', 'madweight'] 2886 _export_formats = _v4_export_formats + ['standalone_cpp', 'pythia8', 'aloha', 2887 'matchbox_cpp', 'matchbox'] 2888 _set_options = ['group_subprocesses', 2889 'ignore_six_quark_processes', 2890 'stdout_level', 2891 'fortran_compiler', 2892 'cpp_compiler', 2893 'loop_optimized_output', 2894 'complex_mass_scheme', 2895 'gauge', 2896 'EWscheme', 2897 'max_npoint_for_channel', 2898 'max_t_for_channel', 2899 'zerowidth_tchannel', 2900 'default_unset_couplings'] 2901 _valid_nlo_modes = ['all','real','virt','sqrvirt','tree','noborn','LOonly'] 2902 _valid_sqso_types = ['==','<=','=','>'] 2903 _valid_amp_so_types = ['=','<=', '==', '>'] 2904 _OLP_supported = ['MadLoop', 'GoSam'] 2905 _output_dependencies_supported = ['external', 'internal','environment_paths'] 2906 2907 # The three options categories are treated on a different footage when a 2908 # set/save configuration occur. current value are kept in self.options 2909 options_configuration = {'pythia8_path': './HEPTools/pythia8', 2910 'hwpp_path': './herwigPP', 2911 'thepeg_path': './thepeg', 2912 'hepmc_path': './hepmc', 2913 'madanalysis_path': './MadAnalysis', 2914 'madanalysis5_path':'./HEPTools/madanalysis5/madanalysis5', 2915 'pythia-pgs_path':'./pythia-pgs', 2916 'td_path':'./td', 2917 'delphes_path':'./Delphes', 2918 'exrootanalysis_path':'./ExRootAnalysis', 2919 'syscalc_path': './SysCalc', 2920 'timeout': 60, 2921 'web_browser':None, 2922 'eps_viewer':None, 2923 'text_editor':None, 2924 'fortran_compiler':None, 2925 'f2py_compiler':None, 2926 'f2py_compiler_py2':None, 2927 'f2py_compiler_py3':None, 2928 'cpp_compiler':None, 2929 'auto_update':7, 2930 'cluster_type': 'condor', 2931 'cluster_queue': None, 2932 'cluster_status_update': (600, 30), 2933 'fastjet':'fastjet-config', 2934 'golem':'auto', 2935 'samurai':None, 2936 'ninja':'./HEPTools/lib', 2937 'collier':'./HEPTools/lib', 2938 'lhapdf':'lhapdf-config', 2939 'lhapdf_py2': None, 2940 'lhapdf_py3': None, 2941 'applgrid':'applgrid-config', 2942 'amcfast':'amcfast-config', 2943 'cluster_temp_path':None, 2944 'mg5amc_py8_interface_path': './HEPTools/MG5aMC_PY8_interface', 2945 'cluster_local_path': None, 2946 'OLP': 'MadLoop', 2947 'cluster_nb_retry':1, 2948 'cluster_retry_wait':300, 2949 'cluster_size':100, 2950 'output_dependencies':'external', 2951 'crash_on_error':False 2952 } 2953 2954 options_madgraph= {'group_subprocesses': 'Auto', 2955 'ignore_six_quark_processes': False, 2956 'low_mem_multicore_nlo_generation': False, 2957 'complex_mass_scheme': False, 2958 'gauge':'unitary', 2959 'stdout_level':None, 2960 'loop_optimized_output':True, 2961 'loop_color_flows':False, 2962 'max_npoint_for_channel': 0, # 0 means automaticly adapted 2963 'default_unset_couplings': 99, # 99 means infinity 2964 'max_t_for_channel': 99, # means no restrictions 2965 'zerowidth_tchannel': True, 2966 } 2967 2968 options_madevent = {'automatic_html_opening':True, 2969 'run_mode':2, 2970 'nb_core': None, 2971 'notification_center': True 2972 } 2973 2974 2975 # Variables to store object information 2976 _curr_model = None #base_objects.Model() 2977 _curr_amps = diagram_generation.AmplitudeList() 2978 _curr_proc_defs = base_objects.ProcessDefinitionList() 2979 _curr_matrix_elements = helas_objects.HelasMultiProcess() 2980 _curr_helas_model = None 2981 _curr_exporter = None 2982 _done_export = False 2983 _curr_decaymodel = None 2984 2985 helporder = ['Main commands', 'Documented commands'] 2986 2987
2988 - def preloop(self):
2989 """Initializing before starting the main loop""" 2990 2991 self.prompt = 'MG5_aMC>' 2992 if madgraph.ReadWrite: # prevent on read-only disk 2993 self.do_install('update --mode=mg5_start') 2994 2995 # By default, load the UFO Standard Model 2996 logger.info("Loading default model: sm") 2997 self.exec_cmd('import model sm', printcmd=False, precmd=True) 2998 2999 # preloop mother 3000 CmdExtended.preloop(self)
3001 3002
3003 - def __init__(self, mgme_dir = '', *completekey, **stdin):
3004 """ add a tracker of the history """ 3005 3006 CmdExtended.__init__(self, *completekey, **stdin) 3007 3008 # Set MG/ME directory path 3009 if mgme_dir: 3010 if os.path.isdir(pjoin(mgme_dir, 'Template')): 3011 self._mgme_dir = mgme_dir 3012 logger.info('Setting MG/ME directory to %s' % mgme_dir) 3013 else: 3014 logger.warning('Warning: Directory %s not valid MG/ME directory' % \ 3015 mgme_dir) 3016 self._mgme_dir = MG4DIR 3017 3018 # check that make_opts exists 3019 make_opts = pjoin(MG5DIR, 'Template','LO','Source','make_opts') 3020 make_opts_source = pjoin(MG5DIR, 'Template','LO','Source','.make_opts') 3021 if not os.path.exists(make_opts): 3022 shutil.copy(make_opts_source, make_opts) 3023 elif os.path.getmtime(make_opts) < os.path.getmtime(make_opts_source): 3024 shutil.copy(make_opts_source, make_opts) 3025 3026 # Variables to store state information 3027 self._multiparticles = {} 3028 self.options = {} 3029 self._generate_info = "" # store the first generated process 3030 self._model_v4_path = None 3031 self._export_dir = None 3032 self._export_format = 'madevent' 3033 self._mgme_dir = MG4DIR 3034 self._cuttools_dir=str(os.path.join(self._mgme_dir,'vendor','CutTools')) 3035 self._iregi_dir=str(os.path.join(self._mgme_dir,'vendor','IREGI','src')) 3036 self._comparisons = None 3037 self._cms_checks = [] 3038 self._nlo_modes_for_completion = ['all','virt','real','LOonly'] 3039 3040 # Load the configuration file,i.e.mg5_configuration.txt 3041 self.set_configuration()
3042
3043 - def setup(self):
3044 """ Actions to carry when switching to this interface """ 3045 3046 # Refresh all the interface stored value as things like generated 3047 # processes and amplitudes are not to be reused in between different 3048 # interfaces 3049 # Clear history, amplitudes and matrix elements when a model is imported 3050 # Remove previous imports, generations and outputs from history 3051 self.history.clean(remove_bef_last='import',keep_switch=True) 3052 # Reset amplitudes and matrix elements 3053 self._done_export=False 3054 self._curr_amps = diagram_generation.AmplitudeList() 3055 self._curr_proc_defs = base_objects.ProcessDefinitionList() 3056 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 3057 3058 self._v4_export_formats = ['madevent', 'standalone','standalone_msP','standalone_msF', 3059 'matrix', 'standalone_rw'] 3060 self._export_formats = self._v4_export_formats + ['standalone_cpp', 'pythia8'] 3061 self._nlo_modes_for_completion = ['all','virt','real']
3062
3063 - def do_quit(self, line):
3064 """Not in help: Do quit""" 3065 3066 if self._done_export and \ 3067 os.path.exists(pjoin(self._done_export[0],'RunWeb')): 3068 os.remove(pjoin(self._done_export[0],'RunWeb')) 3069 3070 value = super(MadGraphCmd, self).do_quit(line) 3071 if madgraph.ReadWrite: #prevent to run on Read Only disk 3072 self.do_install('update --mode=mg5_end') 3073 misc.EasterEgg('quit') 3074 3075 3076 return value
3077 3078 # Add a process to the existing multiprocess definition 3079 # Generate a new amplitude
3080 - def do_add(self, line):
3081 """Generate an amplitude for a given process and add to 3082 existing amplitudes 3083 or merge two model 3084 """ 3085 3086 args = self.split_arg(line) 3087 3088 3089 warning_duplicate = True 3090 if '--no_warning=duplicate' in args: 3091 warning_duplicate = False 3092 args.remove('--no_warning=duplicate') 3093 3094 diagram_filter = False 3095 if '--diagram_filter' in args: 3096 diagram_filter = True 3097 args.remove('--diagram_filter') 3098 3099 standalone_only = False 3100 if '--standalone' in args: 3101 standalone_only = True 3102 args.remove('--standalone') 3103 3104 # Check the validity of the arguments 3105 self.check_add(args) 3106 3107 if args[0] == 'model': 3108 return self.add_model(args[1:]) 3109 3110 # special option for 1->N to avoid generation of kinematically forbidden 3111 #decay. 3112 if args[-1].startswith('--optimize'): 3113 optimize = True 3114 args.pop() 3115 else: 3116 optimize = False 3117 3118 if args[0] == 'process': 3119 # Rejoin line 3120 line = ' '.join(args[1:]) 3121 3122 # store the first process (for the perl script) 3123 if not self._generate_info: 3124 self._generate_info = line 3125 3126 # Reset Helas matrix elements 3127 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 3128 3129 # Extract process from process definition 3130 if ',' in line: 3131 if ']' in line or '[' in line: 3132 error_msg=\ 3133 """The '[' and ']' syntax cannot be used in cunjunction with decay chains. 3134 This implies that with decay chains: 3135 > Squared coupling order limitations are not available. 3136 > Loop corrections cannot be considered.""" 3137 raise MadGraph5Error(error_msg) 3138 else: 3139 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 3140 myprocdef, line = self.extract_decay_chain_process(line, proc_number=nb_proc) 3141 # Redundant with above, but not completely as in the future 3142 # one might think of allowing the core process to be 3143 # corrected by loops. 3144 if myprocdef.are_decays_perturbed(): 3145 raise MadGraph5Error("Decay processes cannot be perturbed.") 3146 # The two limitations below have some redundancy, but once 3147 # again, they might be relieved (one at a time or together) 3148 # int he future. 3149 if myprocdef.decays_have_squared_orders() or \ 3150 myprocdef['squared_orders']!={}: 3151 raise MadGraph5Error("Decay processes cannot specify "+\ 3152 "squared orders constraints.") 3153 if myprocdef.are_negative_orders_present(): 3154 raise MadGraph5Error("Decay processes cannot include negative"+\ 3155 " coupling orders constraints.") 3156 else: 3157 nb_proc = len([l for l in self.history if l.startswith(('generate','add process'))]) 3158 myprocdef = self.extract_process(line, proc_number=nb_proc) 3159 3160 3161 3162 # Check that we have something 3163 if not myprocdef: 3164 raise self.InvalidCmd("Empty or wrong format process, please try again.") 3165 # Check that we have the same number of initial states as 3166 # existing processes 3167 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 3168 myprocdef.get_ninitial() and not standalone_only: 3169 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 3170 3171 #Check that we do not have situation like z{T} z 3172 if not myprocdef.check_polarization(): 3173 logger.critical("Not Supported syntax:\n"+ \ 3174 " Syntax like p p > Z{T} Z are ambiguious" +\ 3175 " Behavior is not guarantee to be stable within future version of the code." + \ 3176 " Furthemore, you can have issue with symmetry factor (we do not guarantee [differential] cross-section."+\ 3177 " We suggest you to abort this computation") 3178 ans = self.ask('Do you want to continue', 'no',['yes','no']) 3179 if ans == 'no': 3180 raise self.InvalidCmd("Not supported syntax of type p p > Z{T} Z") 3181 3182 3183 3184 3185 self._curr_proc_defs.append(myprocdef) 3186 3187 # Negative coupling order contraints can be given on at most one 3188 # coupling order (and either in squared orders or orders, not both) 3189 if len([1 for val in list(myprocdef.get('orders').values())+\ 3190 list(myprocdef.get('squared_orders').values()) if val<0])>1: 3191 raise MadGraph5Error("Negative coupling order constraints"+\ 3192 " can only be given on one type of coupling and either on"+\ 3193 " squared orders or amplitude orders, not both.") 3194 3195 if myprocdef.get_ninitial() ==1 and myprocdef.get('squared_orders'): 3196 logger.warning('''Computation of interference term with decay is not 100% validated. 3197 Please check carefully your result. 3198 One suggestion is also to compare the generation of your process with and without 3199 set group_subprocesses True 3200 (to write Before the generate command) 3201 ''') 3202 3203 cpu_time1 = time.time() 3204 3205 # Generate processes 3206 if self.options['group_subprocesses'] == 'Auto': 3207 collect_mirror_procs = True 3208 else: 3209 collect_mirror_procs = self.options['group_subprocesses'] 3210 ignore_six_quark_processes = \ 3211 self.options['ignore_six_quark_processes'] if \ 3212 "ignore_six_quark_processes" in self.options \ 3213 else [] 3214 3215 myproc = diagram_generation.MultiProcess(myprocdef, 3216 collect_mirror_procs = collect_mirror_procs, 3217 ignore_six_quark_processes = ignore_six_quark_processes, 3218 optimize=optimize, diagram_filter=diagram_filter) 3219 3220 3221 for amp in myproc.get('amplitudes'): 3222 if amp not in self._curr_amps: 3223 self._curr_amps.append(amp) 3224 elif warning_duplicate: 3225 raise self.InvalidCmd("Duplicate process %s found. Please check your processes." % \ 3226 amp.nice_string_processes()) 3227 3228 # Reset _done_export, since we have new process 3229 self._done_export = False 3230 3231 cpu_time2 = time.time() 3232 3233 nprocs = len(myproc.get('amplitudes')) 3234 ndiags = sum([amp.get_number_of_diagrams() for \ 3235 amp in myproc.get('amplitudes')]) 3236 3237 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 3238 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 3239 ndiags = sum([amp.get_number_of_diagrams() for \ 3240 amp in self._curr_amps]) 3241 logger.info("Total: %i processes with %i diagrams" % \ 3242 (len(self._curr_amps), ndiags))
3243
3244 - def add_model(self, args):
3245 """merge two model""" 3246 3247 model_path = args[0] 3248 recreate = ('--recreate' in args) 3249 if recreate: 3250 args.remove('--recreate') 3251 keep_decay = ('--keep_decay' in args) 3252 if keep_decay: 3253 args.remove('--keep_decay') 3254 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')] 3255 if output_dir: 3256 output_dir = output_dir[0] 3257 recreate = True 3258 restrict_name = '' 3259 args.remove('--output=%s' % output_dir) 3260 else: 3261 name = os.path.basename(self._curr_model.get('modelpath')) 3262 restrict_name = self._curr_model.get('restrict_name') 3263 output_dir = pjoin(MG5DIR, 'models', '%s__%s' % (name, 3264 os.path.basename(model_path))) 3265 3266 if os.path.exists(output_dir): 3267 if recreate: 3268 shutil.rmtree(output_dir) 3269 else: 3270 logger.info('Model already created! Loading it from %s' % output_dir) 3271 oldmodel = self._curr_model.get('modelpath') 3272 new_model_name = output_dir 3273 if restrict_name: 3274 new_model_name = '%s-%s' % (output_dir, restrict_name) 3275 try: 3276 self.exec_cmd('import model %s' % new_model_name, errorhandling=False, 3277 printcmd=False, precmd=True, postcmd=True) 3278 except Exception as error: 3279 logger.debug('fail to load model %s with error:\n %s' % (output_dir, error)) 3280 logger.warning('Fail to load the model. Restore previous model') 3281 self.exec_cmd('import model %s' % oldmodel, errorhandling=False, 3282 printcmd=False, precmd=True, postcmd=True) 3283 raise Exception('Invalid Model! Please retry with the option \'--recreate\'.') 3284 else: 3285 return 3286 3287 #Need to do the work!!! 3288 import models.usermod as usermod 3289 base_model = copy.deepcopy(usermod.UFOModel(self._curr_model.get('modelpath'))) 3290 3291 identify = dict(tuple(a.split('=')) for a in args if '=' in a) 3292 base_model.add_model(path=model_path, identify_particles=identify) 3293 base_model.write(output_dir) 3294 3295 if keep_decay and os.path.exists(pjoin(self._curr_model.get('modelpath'), 'decays.py')): 3296 base_model.mod_file(pjoin(pjoin(self._curr_model.get('modelpath'), 'decays.py')), 3297 pjoin(pjoin(output_dir, 'decays.py'))) 3298 3299 new_model_name = output_dir 3300 if restrict_name: 3301 new_model_name = '%s-%s' % (output_dir, restrict_name) 3302 3303 if 'modelname' in self.history.get('full_model_line'): 3304 opts = '--modelname' 3305 else: 3306 opts='' 3307 self.exec_cmd('import model %s %s' % (new_model_name, opts), errorhandling=False, 3308 printcmd=False, precmd=True, postcmd=True)
3309 3310
3311 - def do_convert(self, line):
3312 """convert model FULLPATH 3313 modify (in place) the UFO model to make it compatible with both python2 and python3 3314 """ 3315 3316 args = self.split_arg(line) 3317 if hasattr(self, 'do_convert_%s' % args[0]): 3318 getattr(self, 'do_convert_%s' % args[0])(args[1:])
3319
3320 - def do_convert_model(self, args):
3321 "Not in help: shortcut for convert model" 3322 3323 if not os.path.isdir(args[0]): 3324 raise Exception( 'model to convert need to provide a full path') 3325 model_dir = args[0] 3326 3327 answer = self.ask('model conversion to support both py2 and py3 are done in place.\n They are NO guarantee of success.\n It can make the model to stop working under PY2 as well.\n Do you want to proceed?', 3328 'y', ['y','n']) 3329 if answer != 'y': 3330 return 3331 3332 #Object_library (.iteritems() -> .items()) 3333 text = open(pjoin(model_dir, 'object_library.py')).read() 3334 text = text.replace('.iteritems()', '.items()') 3335 text = open(pjoin(model_dir, 'object_library.py'),'w').write(text) 3336 3337 # write_param_card.dat -> copy the one of the sm model 3338 files.cp(pjoin(MG5DIR, 'models','sm','write_param_card.py'), 3339 pjoin(model_dir, 'write_param_card.py')) 3340 3341 # __init__.py check that function_library and object_library are imported 3342 text = open(pjoin(model_dir, '__init__.py')).read() 3343 mod = False 3344 to_check = ['object_library', 'function_library'] 3345 for lib in to_check: 3346 if 'import %s' % lib in text: 3347 continue 3348 mod = True 3349 text = "import %s \n" % lib + text 3350 if mod: 3351 open(pjoin(model_dir, '__init__.py'),'w').write(text)
3352 3353 3354 3355 3356 3357 # Define a multiparticle label
3358 - def do_define(self, line, log=True):
3359 """Define a multiparticle""" 3360 3361 self.avoid_history_duplicate('define %s' % line, ['define']) 3362 if not self._curr_model: 3363 self.do_import('model sm') 3364 self.history.append('define %s' % line) 3365 if not self._curr_model['case_sensitive']: 3366 # Particle names lowercase 3367 line = line.lower() 3368 # Make sure there are spaces around =, | and / 3369 line = line.replace("=", " = ") 3370 line = line.replace("|", " | ") 3371 line = line.replace("/", " / ") 3372 args = self.split_arg(line) 3373 # check the validity of the arguments 3374 self.check_define(args) 3375 3376 label = args[0] 3377 remove_ids = [] 3378 try: 3379 remove_index = args.index("/") 3380 except ValueError: 3381 pass 3382 else: 3383 remove_ids = args[remove_index + 1:] 3384 args = args[:remove_index] 3385 3386 pdg_list = self.extract_particle_ids(args[1:]) 3387 remove_list = self.extract_particle_ids(remove_ids) 3388 pdg_list = [p for p in pdg_list if p not in remove_list] 3389 3390 self.optimize_order(pdg_list) 3391 self._multiparticles[label] = pdg_list 3392 if log: 3393 logger.info("Defined multiparticle %s" % \ 3394 self.multiparticle_string(label))
3395 3396 # Display
3397 - def do_display(self, line, output=sys.stdout):
3398 """Display current internal status""" 3399 3400 args = self.split_arg(line) 3401 #check the validity of the arguments 3402 self.check_display(args) 3403 3404 if args[0] == 'diagrams': 3405 self.draw(' '.join(args[1:])) 3406 3407 if args[0] == 'particles' and len(args) == 1: 3408 propagating_particle = [] 3409 nb_unpropagating = 0 3410 for particle in self._curr_model['particles']: 3411 if particle.get('propagating'): 3412 propagating_particle.append(particle) 3413 else: 3414 nb_unpropagating += 1 3415 3416 print("Current model contains %i particles:" % \ 3417 len(propagating_particle)) 3418 part_antipart = [part for part in propagating_particle \ 3419 if not part['self_antipart']] 3420 part_self = [part for part in propagating_particle \ 3421 if part['self_antipart']] 3422 for part in part_antipart: 3423 print(part['name'] + '/' + part['antiname'], end=' ') 3424 print('') 3425 for part in part_self: 3426 print(part['name'], end=' ') 3427 print('') 3428 if nb_unpropagating: 3429 print('In addition of %s un-physical particle mediating new interactions.' \ 3430 % nb_unpropagating) 3431 3432 elif args[0] == 'particles': 3433 for arg in args[1:]: 3434 if arg.isdigit() or (arg[0] == '-' and arg[1:].isdigit()): 3435 particle = self._curr_model.get_particle(abs(int(arg))) 3436 else: 3437 particle = self._curr_model['particles'].find_name(arg) 3438 if not particle: 3439 raise self.InvalidCmd('no particle %s in current model' % arg) 3440 3441 print("Particle %s has the following properties:" % particle.get_name()) 3442 print(str(particle)) 3443 3444 elif args[0] == 'interactions' and len(args) == 1: 3445 text = "Current model contains %i interactions\n" % \ 3446 len(self._curr_model['interactions']) 3447 for i, inter in enumerate(self._curr_model['interactions']): 3448 text += str(i+1) + ':' 3449 for part in inter['particles']: 3450 if part['is_part']: 3451 text += part['name'] 3452 else: 3453 text += part['antiname'] 3454 text += " " 3455 text += " ".join(order + '=' + str(inter['orders'][order]) \ 3456 for order in inter['orders']) 3457 text += '\n' 3458 pydoc.pager(text) 3459 3460 elif args[0] == 'interactions' and len(args)==2 and args[1].isdigit(): 3461 for arg in args[1:]: 3462 if int(arg) > len(self._curr_model['interactions']): 3463 raise self.InvalidCmd('no interaction %s in current model' % arg) 3464 if int(arg) == 0: 3465 print('Special interactions which identify two particles') 3466 else: 3467 print("Interactions %s has the following property:" % arg) 3468 print(self._curr_model['interactions'][int(arg)-1]) 3469 3470 elif args[0] == 'interactions': 3471 request_part = args[1:] 3472 text = '' 3473 for i, inter in enumerate(self._curr_model['interactions']): 3474 present_part = [part['is_part'] and part['name'] or part['antiname'] 3475 for part in inter['particles'] 3476 if (part['is_part'] and part['name'] in request_part) or 3477 (not part['is_part'] and part['antiname'] in request_part)] 3478 if len(present_part) < len(request_part): 3479 continue 3480 # check that all particles are selected at least once 3481 if set(present_part) != set(request_part): 3482 continue 3483 # check if a particle is asked more than once 3484 if len(request_part) > len(set(request_part)): 3485 for p in request_part: 3486 if request_part.count(p) > present_part.count(p): 3487 continue 3488 3489 name = str(i+1) + ' : ' 3490 for part in inter['particles']: 3491 if part['is_part']: 3492 name += part['name'] 3493 else: 3494 name += part['antiname'] 3495 name += " " 3496 text += "\nInteractions %s has the following property:\n" % name 3497 text += str(self._curr_model['interactions'][i]) 3498 3499 text += '\n' 3500 print(name) 3501 if text =='': 3502 text += 'No matching for any interactions' 3503 pydoc.pager(text) 3504 3505 3506 elif args[0] == 'parameters' and len(args) == 1: 3507 text = "Current model contains %i parameters\n" % \ 3508 sum([len(part) for part in 3509 self._curr_model['parameters'].values()]) 3510 keys = list(self._curr_model['parameters'].keys()) 3511 def key_sort(x, y): 3512 if ('external',) == x: 3513 return -1 3514 elif ('external',) == y: 3515 return +1 3516 elif len(x) < len(y): 3517 return -1 3518 else: 3519 return 1
3520 keys.sort(key_sort) 3521 for key in keys: 3522 item = self._curr_model['parameters'][key] 3523 text += '\nparameter type: %s\n' % str(key) 3524 for value in item: 3525 if hasattr(value, 'expr'): 3526 if value.value is not None: 3527 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3528 else: 3529 text+= ' %s = %s\n' % (value.name, value.expr) 3530 else: 3531 if value.value is not None: 3532 text+= ' %s = %s\n' % (value.name, value.value) 3533 else: 3534 text+= ' %s \n' % (value.name) 3535 pydoc.pager(text) 3536 3537 elif args[0] == 'processes': 3538 for amp in self._curr_amps: 3539 print(amp.nice_string_processes()) 3540 3541 elif args[0] == 'diagrams_text': 3542 text = "\n".join([amp.nice_string() for amp in self._curr_amps]) 3543 pydoc.pager(text) 3544 3545 elif args[0] == 'multiparticles': 3546 print('Multiparticle labels:') 3547 for key in self._multiparticles: 3548 print(self.multiparticle_string(key)) 3549 3550 elif args[0] == 'coupling_order': 3551 hierarchy = list(self._curr_model['order_hierarchy'].items()) 3552 #self._curr_model.get_order_hierarchy().items() 3553 def order(first, second): 3554 if first[1] < second[1]: 3555 return -1 3556 else: 3557 return 1
3558 hierarchy.sort(order) 3559 for order in hierarchy: 3560 print(' %s : weight = %s' % order) 3561 3562 elif args[0] == 'couplings' and len(args) == 1: 3563 if self._model_v4_path: 3564 print('No couplings information available in V4 model') 3565 return 3566 text = '' 3567 text = "Current model contains %i couplings\n" % \ 3568 sum([len(part) for part in 3569 self._curr_model['couplings'].values()]) 3570 keys = list(self._curr_model['couplings'].keys()) 3571 def key_sort(x, y): 3572 if ('external',) == x: 3573 return -1 3574 elif ('external',) == y: 3575 return +1 3576 elif len(x) < len(y): 3577 return -1 3578 else: 3579 return 1 3580 keys.sort(key_sort) 3581 for key in keys: 3582 item = self._curr_model['couplings'][key] 3583 text += '\ncouplings type: %s\n' % str(key) 3584 for value in item: 3585 if value.value is not None: 3586 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3587 else: 3588 text+= ' %s = %s\n' % (value.name, value.expr) 3589 3590 pydoc.pager(text) 3591 3592 elif args[0] == 'couplings': 3593 if self._model_v4_path: 3594 print('No couplings information available in V4 model') 3595 return 3596 3597 try: 3598 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3599 print('Note that this is the UFO informations.') 3600 print(' "display couplings" present the actual definition') 3601 print('prints the current states of mode') 3602 print(eval('ufomodel.couplings.%s.nice_string()'%args[1])) 3603 except Exception: 3604 raise self.InvalidCmd('no couplings %s in current model' % args[1]) 3605 3606 elif args[0] == 'lorentz': 3607 print('in lorentz') 3608 if self._model_v4_path: 3609 print('No lorentz information available in V4 model') 3610 return 3611 elif len(args) == 1: 3612 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3613 print(dir(ufomodel.lorentz)) 3614 return 3615 try: 3616 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3617 print(getattr(ufomodel.lorentz, args[1]).nice_string()) 3618 except Exception as error: 3619 raise 3620 logger.info(str(error)) 3621 raise self.InvalidCmd('no lorentz %s in current model' % args[1]) 3622 3623 elif args[0] == 'checks': 3624 outstr = '' 3625 if self._comparisons: 3626 comparisons = self._comparisons[0] 3627 if len(args) > 1 and args[1] == 'failed': 3628 comparisons = [c for c in comparisons if not c['passed']] 3629 outstr += "Process check results:" 3630 for comp in comparisons: 3631 outstr += "\n%s:" % comp['process'].nice_string() 3632 outstr += "\n Phase space point: (px py pz E)" 3633 for i, p in enumerate(comp['momenta']): 3634 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p) 3635 outstr += "\n Permutation values:" 3636 outstr += "\n " + str(comp['values']) 3637 if comp['passed']: 3638 outstr += "\n Process passed (rel. difference %.9e)" % \ 3639 comp['difference'] 3640 else: 3641 outstr += "\n Process failed (rel. difference %.9e)" % \ 3642 comp['difference'] 3643 3644 used_aloha = sorted(self._comparisons[1]) 3645 if used_aloha: 3646 outstr += "\nChecked ALOHA routines:" 3647 for aloha in used_aloha: 3648 aloha_str = aloha[0] 3649 if aloha[1]: 3650 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]]) 3651 aloha_str += "_%d" % aloha[2] 3652 outstr += "\n" + aloha_str 3653 3654 outstr += '\n' 3655 for cms_check in self._cms_checks: 3656 outstr += '*'*102+'\n' 3657 outstr += 'Complex Mass Scheme check:\n' 3658 outstr += ' -> check %s\n'%cms_check['line'] 3659 outstr += '*'*102+'\n' 3660 tmp_options = copy.copy(cms_check['options']) 3661 tmp_options['show_plot']=False 3662 outstr += process_checks.output_complex_mass_scheme( 3663 cms_check['cms_result'], cms_check['output_path'], 3664 tmp_options, self._curr_model) + '\n' 3665 outstr += '*'*102+'\n\n' 3666 pydoc.pager(outstr) 3667 3668 elif args[0] == 'options': 3669 if len(args) == 1: 3670 to_print = lambda name: True 3671 else: 3672 to_print = lambda name: any(poss in name for poss in args[1:]) 3673 3674 outstr = " MadGraph5_aMC@NLO Options \n" 3675 outstr += " ---------------- \n" 3676 keys = list(self.options_madgraph.keys()) 3677 keys.sort() 3678 for key in keys: 3679 if not to_print(key): 3680 continue 3681 default = self.options_madgraph[key] 3682 value = self.options[key] 3683 if value == default: 3684 outstr += " %25s \t:\t%s\n" % (key,value) 3685 else: 3686 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3687 outstr += "\n" 3688 outstr += " MadEvent Options \n" 3689 outstr += " ---------------- \n" 3690 keys = list(self.options_madevent.keys()) 3691 keys.sort() 3692 for key in keys: 3693 if not to_print(key): 3694 continue 3695 default = self.options_madevent[key] 3696 value = self.options[key] 3697 if value == default: 3698 outstr += " %25s \t:\t%s\n" % (key,value) 3699 else: 3700 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3701 outstr += "\n" 3702 outstr += " Configuration Options \n" 3703 outstr += " --------------------- \n" 3704 keys = list(self.options_configuration.keys()) 3705 keys.sort() 3706 for key in keys: 3707 if not to_print(key): 3708 continue 3709 default = self.options_configuration[key] 3710 value = self.options[key] 3711 if value == default: 3712 outstr += " %25s \t:\t%s\n" % (key,value) 3713 else: 3714 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3715 3716 output.write(outstr) 3717 elif args[0] in ["variable"]: 3718 super(MadGraphCmd, self).do_display(line, output) 3719 3720 elif args[0] in ["modellist", "model_list"]: 3721 outstr = [] 3722 template = """%-30s | %-60s | %-25s """ 3723 outstr.append(template % ('name', 'restriction', 'comment')) 3724 outstr.append('*'*150) 3725 already_done = [] 3726 #local model #use 3727 3728 if 'PYTHONPATH' in os.environ: 3729 pythonpath = os.environ['PYTHONPATH'].split(':') 3730 else: 3731 pythonpath = [] 3732 3733 for base in [pjoin(MG5DIR,'models')] + pythonpath: 3734 if not os.path.exists(base): 3735 continue 3736 file_cond = lambda p : os.path.exists(pjoin(base,p,'particles.py')) 3737 mod_name = lambda name: name 3738 3739 model_list = [mod_name(name) for name in \ 3740 self.path_completion('', 3741 base, 3742 only_dirs = True) \ 3743 if file_cond(name)] 3744 3745 for model_name in model_list: 3746 if model_name in already_done: 3747 continue 3748 all_name = self.find_restrict_card(model_name, 3749 base_dir=base, 3750 online=False) 3751 already_done.append(model_name) 3752 restrict = [name[len(model_name):] for name in all_name 3753 if len(name)>len(model_name)] 3754 3755 comment = 'from models directory' 3756 if base != pjoin(MG5DIR,'models'): 3757 comment = 'from PYTHONPATH: %s' % base 3758 lrestrict = ', '.join(restrict) 3759 if len(lrestrict) > 50: 3760 for i in range(-1,-len(restrict), -1): 3761 lrestrict = ', '.join(restrict[:i]) 3762 if len(lrestrict)<50: 3763 break 3764 outstr.append(template % (model_name, lrestrict, comment)) 3765 outstr.append(template % ('', ', '.join(restrict[i:]), '')) 3766 else: 3767 outstr.append(template % (model_name, ', '.join(restrict), comment)) 3768 outstr.append('*'*150) 3769 3770 # Still have to add the one with internal information 3771 for model_name in self._online_model: 3772 if model_name in already_done: 3773 continue 3774 restrict = [tag for tag in self._online_model[model_name]] 3775 comment = 'automatic download from MG5aMC server' 3776 outstr.append(template % (model_name, ','.join(restrict), comment)) 3777 already_done.append(model_name) 3778 3779 outstr.append('*'*150) 3780 # other downloadable model 3781 data = import_ufo.get_model_db() 3782 self._online_model2 = [] 3783 for line in data: 3784 model_name, path = line.decode().split() 3785 if model_name in already_done: 3786 continue 3787 if model_name.endswith('_v4'): 3788 continue 3789 3790 if 'feynrules' in path: 3791 comment = 'automatic download from FeynRules website' 3792 elif 'madgraph.phys' in path: 3793 comment = 'automatic download from MG5aMC server' 3794 else: 3795 comment = 'automatic download.' 3796 restrict = 'unknown' 3797 outstr.append(template % (model_name, restrict, comment)) 3798 self._online_model2.append(model_name) 3799 pydoc.pager('\n'.join(outstr)) 3800 3801
3802 - def multiparticle_string(self, key):
3803 """Returns a nicely formatted string for the multiparticle""" 3804 3805 if self._multiparticles[key] and \ 3806 isinstance(self._multiparticles[key][0], list): 3807 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\ 3808 get('particle_dict')[part_id].get_name() \ 3809 for part_id in id_list]) \ 3810 for id_list in self._multiparticles[key]])) 3811 else: 3812 return "%s = %s" % (key, " ".join([self._curr_model.\ 3813 get('particle_dict')[part_id].get_name() \ 3814 for part_id in self._multiparticles[key]]))
3815
3816 - def do_tutorial(self, line):
3817 """Activate/deactivate the tutorial mode.""" 3818 3819 args = self.split_arg(line) 3820 self.check_tutorial(args) 3821 tutorials = {'MadGraph5': logger_tuto, 3822 'aMCatNLO': logger_tuto_nlo, 3823 'MadLoop': logger_tuto_madloop} 3824 try: 3825 tutorials[args[0]].setLevel(logging.INFO) 3826 for mode in [m for m in tutorials.keys() if m != args[0]]: 3827 tutorials[mode].setLevel(logging.ERROR) 3828 except KeyError: 3829 logger_tuto.info("\n\tThanks for using the tutorial!") 3830 logger_tuto.setLevel(logging.ERROR) 3831 logger_tuto_nlo.info("\n\tThanks for using the aMC@NLO tutorial!") 3832 logger_tuto_nlo.setLevel(logging.ERROR) 3833 logger_tuto_madloop.info("\n\tThanks for using MadLoop tutorial!") 3834 logger_tuto_madloop.setLevel(logging.ERROR) 3835 3836 if not self._mgme_dir: 3837 logger_tuto.info(\ 3838 "\n\tWarning: To use all features in this tutorial, " + \ 3839 "please run from a" + \ 3840 "\n\t valid MG_ME directory.")
3841 3842 3843
3844 - def draw(self, line,selection='all',Dtype=''):
3845 """ draw the Feynman diagram for the given process. 3846 Dtype refers to born, real or loop""" 3847 3848 args = self.split_arg(line) 3849 # Check the validity of the arguments 3850 self.check_draw(args) 3851 3852 # Check if we plot a decay chain 3853 if any([isinstance(a, diagram_generation.DecayChainAmplitude) for \ 3854 a in self._curr_amps]) and not self._done_export: 3855 warn = 'WARNING: You try to draw decay chain diagrams without first running output.\n' 3856 warn += '\t The decay processes will be drawn separately' 3857 logger.warning(warn) 3858 3859 (options, args) = _draw_parser.parse_args(args) 3860 if madgraph.iolibs.drawing_eps.EpsDiagramDrawer.april_fool: 3861 options.horizontal = True 3862 options.external = True 3863 options.max_size = 0.3 3864 options.add_gap = 0.5 3865 options = draw_lib.DrawOption(options) 3866 start = time.time() 3867 3868 3869 3870 3871 # Collect amplitudes 3872 amplitudes = diagram_generation.AmplitudeList() 3873 3874 for amp in self._curr_amps: 3875 amplitudes.extend(amp.get_amplitudes()) 3876 3877 for amp in amplitudes: 3878 filename = pjoin(args[0], 'diagrams_' + \ 3879 amp.get('process').shell_string() + ".eps") 3880 3881 if selection=='all' and Dtype != 'loop': 3882 diags=amp.get('diagrams') 3883 elif selection=='born': 3884 diags=amp.get('born_diagrams') 3885 elif selection=='loop' or Dtype == 'loop': 3886 diags=base_objects.DiagramList([d for d in 3887 amp.get('loop_diagrams') if d.get('type')>0]) 3888 if len(diags) > 5000: 3889 logger.warning('Displaying only the first 5000 diagrams') 3890 diags = base_objects.DiagramList(diags[:5000]) 3891 3892 plot = draw.MultiEpsDiagramDrawer(diags, 3893 filename, 3894 model=self._curr_model, 3895 amplitude=amp, 3896 legend=amp.get('process').input_string(), 3897 diagram_type=Dtype) 3898 3899 3900 logger.info("Drawing " + \ 3901 amp.get('process').nice_string()) 3902 plot.draw(opt=options) 3903 logger.info("Wrote file " + filename) 3904 self.exec_cmd('open %s' % filename) 3905 3906 stop = time.time() 3907 logger.info('time to draw %s' % (stop - start))
3908 3909 # Perform checks
3910 - def do_check(self, line):
3911 """Check a given process or set of processes""" 3912 3913 def create_lambda_values_list(lower_bound, N): 3914 """ Returns a list of values spanning the range [1.0, lower_bound] with 3915 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered 3916 by N values uniformly distributed. For example, lower_bound=1e-2 3917 and N=5 returns: 3918 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]""" 3919 3920 lCMS_values = [1] 3921 exp = 0 3922 n = 0 3923 while lCMS_values[-1]>=lower_bound: 3924 n = (n+1) 3925 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N))) 3926 if lCMS_values[-1]==lCMS_values[-2]: 3927 lCMS_values.pop() 3928 exp = (n+1)//N 3929 3930 lCMS_values = lCMS_values[:-1] 3931 if lCMS_values[-1]!=lower_bound: 3932 lCMS_values.append(lower_bound) 3933 3934 return lCMS_values
3935 3936 ###### BEGIN do_check 3937 3938 args = self.split_arg(line) 3939 # Check args validity 3940 param_card = self.check_check(args) 3941 3942 options= {'events':None} # If the momentum needs to be picked from a event file 3943 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card): 3944 logger_check.info("Will use the param_card contained in the banner and the events associated") 3945 import madgraph.various.banner as banner 3946 options['events'] = param_card 3947 mybanner = banner.Banner(param_card) 3948 param_card = mybanner.charge_card('param_card') 3949 3950 aloha_lib.KERNEL.clean() 3951 # Back up the gauge for later 3952 gauge = str(self.options['gauge']) 3953 options['reuse'] = args[1]=="-reuse" 3954 args = args[:1]+args[2:] 3955 # For the stability check the user can specify the statistics (i.e 3956 # number of trial PS points) as a second argument 3957 if args[0] in ['stability', 'profile']: 3958 options['npoints'] = int(args[1]) 3959 args = args[:1]+args[2:] 3960 MLoptions={} 3961 i=-1 3962 CMS_options = {} 3963 while args[i].startswith('--'): 3964 option = args[i].split('=') 3965 if option[0] =='--energy': 3966 options['energy']=float(option[1]) 3967 elif option[0] == '--events' and option[1]: 3968 if option[1] == 'None': 3969 options['events'] = None 3970 elif not os.path.exists(option[1]): 3971 raise Exception('path %s does not exists' % option[1]) 3972 else: 3973 options['events'] = option[1] 3974 elif option[0] == '--skip_evt': 3975 options['skip_evt']=int(option[1]) 3976 elif option[0]=='--split_orders': 3977 options['split_orders']=int(option[1]) 3978 elif option[0]=='--helicity': 3979 try: 3980 options['helicity']=int(option[1]) 3981 except ValueError: 3982 raise self.InvalidCmd("The value of the 'helicity' option"+\ 3983 " must be an integer, not %s."%option[1]) 3984 elif option[0]=='--reduction': 3985 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')] 3986 elif option[0]=='--collier_mode': 3987 MLoptions['COLLIERMode']=int(option[1]) 3988 elif option[0]=='--collier_cache': 3989 MLoptions['COLLIERGlobalCache']=int(option[1]) 3990 elif option[0]=='--collier_req_acc': 3991 if option[1]!='auto': 3992 MLoptions['COLLIERRequiredAccuracy']=float(option[1]) 3993 elif option[0]=='--collier_internal_stability_test': 3994 MLoptions['COLLIERUseInternalStabilityTest']=eval(option[1]) 3995 elif option[0]=='--CTModeRun': 3996 try: 3997 MLoptions['CTModeRun']=int(option[1]) 3998 except ValueError: 3999 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\ 4000 " must be an integer, not %s."%option[1]) 4001 elif option[0]=='--offshellness': 4002 CMS_options['offshellness'] = float(option[1]) 4003 if CMS_options['offshellness']<=-1.0: 4004 raise self.InvalidCmd('Offshellness must be number larger or'+ 4005 ' equal to -1.0, not %f'%CMS_options['offshellness']) 4006 elif option[0]=='--analyze': 4007 options['analyze'] = option[1] 4008 elif option[0]=='--show_plot': 4009 options['show_plot'] = 'true' in option[1].lower() 4010 elif option[0]=='--report': 4011 options['report'] = option[1].lower() 4012 elif option[0]=='--seed': 4013 options['seed'] = int(option[1]) 4014 elif option[0]=='--name': 4015 if '.' in option[1]: 4016 raise self.InvalidCmd("Do not specify the extension in the"+ 4017 " name of the run") 4018 CMS_options['name'] = option[1] 4019 elif option[0]=='--resonances': 4020 if option[1]=='all': 4021 CMS_options['resonances'] = 'all' 4022 else: 4023 try: 4024 resonances=eval(option[1]) 4025 except: 4026 raise self.InvalidCmd("Could not evaluate 'resonances'"+ 4027 " option '%s'"%option[1]) 4028 if isinstance(resonances,int) and resonances>0: 4029 CMS_options['resonances'] = resonances 4030 elif isinstance(resonances,list) and all(len(res)==2 and 4031 isinstance(res[0],int) and all(isinstance(i, int) for i in 4032 res[1]) for res in resonances): 4033 CMS_options['resonances'] = resonances 4034 else: 4035 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+ 4036 " or and integer or a list of tuples of the form "+ 4037 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1]) 4038 elif option[0]=='--tweak': 4039 # Lists the sets of custom and widths modifications to apply 4040 value = option[1] 4041 # Set a shortcuts for applying all relevant tweaks 4042 if value=='alltweaks': 4043 value=str(['default','seed667(seed667)','seed668(seed668)', 4044 'allwidths->0.9*allwidths(widths_x_0.9)', 4045 'allwidths->0.99*allwidths(widths_x_0.99)', 4046 'allwidths->1.01*allwidths(widths_x_1.01)', 4047 'allwidths->1.1*allwidths(widths_x_1.1)', 4048 'logp->logm(logp2logm)','logm->logp(logm2logp)']) 4049 try: 4050 tweaks = eval(value) 4051 if isinstance(tweaks, str): 4052 tweaks = [value] 4053 elif not isinstance(tweaks,list): 4054 tweaks = [value] 4055 except: 4056 tweaks = [value] 4057 if not all(isinstance(t,str) for t in tweaks): 4058 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value) 4059 CMS_options['tweak'] = [] 4060 for tweakID, tweakset in enumerate(tweaks): 4061 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset) 4062 if specs: 4063 tweakset = specs.group('tweakset') 4064 name = specs.group('name') 4065 else: 4066 if tweakset!='default': 4067 name = 'tweak_%d'%(tweakID+1) 4068 else: 4069 name = '' 4070 new_tweak_set = {'custom':[],'params':{},'name':name} 4071 for tweak in tweakset.split('&'): 4072 if tweak=='default': 4073 continue 4074 if tweak.startswith('seed'): 4075 new_tweak_set['custom'].append(tweak) 4076 continue 4077 try: 4078 param, replacement = tweak.split('->') 4079 except ValueError: 4080 raise self.InvalidCmd("Tweak specification '%s'"%\ 4081 tweak+" is incorrect. It should be of"+\ 4082 " the form a->_any_function_of_(a,lambdaCMS).") 4083 if param in ['logp','logm','log'] and \ 4084 replacement in ['logp','logm','log']: 4085 new_tweak_set['custom'].append(tweak) 4086 continue 4087 try: 4088 # for safety prefix parameters, because 'as' for alphas 4089 # is a python reserved name for example 4090 orig_param, orig_replacement = param, replacement 4091 replacement = replacement.replace(param, 4092 '__tmpprefix__%s'%param) 4093 param = '__tmpprefix__%s'%param 4094 res = float(eval(replacement.lower(), 4095 {'lambdacms':1.0,param.lower():98.85})) 4096 except: 4097 raise self.InvalidCmd("The substitution expression "+ 4098 "'%s' for the tweaked parameter"%orig_replacement+ 4099 " '%s' could not be evaluated. It must be an "%orig_param+ 4100 "expression of the parameter and 'lambdaCMS'.") 4101 new_tweak_set['params'][param.lower()] = replacement.lower() 4102 CMS_options['tweak'].append(new_tweak_set) 4103 4104 elif option[0]=='--recompute_width': 4105 if option[1].lower() not in ['never','always','first_time','auto']: 4106 raise self.InvalidCmd("The option 'recompute_width' can "+\ 4107 "only be 'never','always', 'first_time' or 'auto' (default).") 4108 CMS_options['recompute_width'] = option[1] 4109 elif option[0]=='--loop_filter': 4110 # Specify a loop, filter. See functions get_loop_filter and 4111 # user_filter in loop_diagram_generation.LoopAmplitude for 4112 # information on usage. 4113 CMS_options['loop_filter'] = '='.join(option[1:]) 4114 elif option[0]=='--diff_lambda_power': 4115 #'secret' option to chose by which lambda power one should divide 4116 # the nwa-cms difference. Useful to set to 2 when doing the Born check 4117 # to see whether the NLO check will have sensitivity to the CMS 4118 # implementation 4119 try: 4120 CMS_options['diff_lambda_power']=float(option[1]) 4121 except ValueError: 4122 raise self.InvalidCmd("the '--diff_lambda_power' option"+\ 4123 " must be an integer or float, not '%s'."%option[1]) 4124 elif option[0]=='--lambda_plot_range': 4125 try: 4126 plot_range=eval(option[1]) 4127 except Exception as e: 4128 raise self.InvalidCmd("The plot range specified %s"%option[1]+\ 4129 " is not a valid syntax. Error:\n%s"%str(e)) 4130 if not isinstance(plot_range,(list,tuple)) or \ 4131 len(plot_range)!=2 or any(not isinstance(p,(float,int)) 4132 for p in plot_range): 4133 raise self.InvalidCmd("The plot range specified %s"\ 4134 %option[1]+" is invalid") 4135 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range]) 4136 elif option[0]=='--lambdaCMS': 4137 try: 4138 lambda_values = eval(option[1]) 4139 except SyntaxError: 4140 raise self.InvalidCmd("'%s' is not a correct"%option[1]+ 4141 " python expression for lambdaCMS values.") 4142 if isinstance(lambda_values,list): 4143 if lambda_values[0]!=1.0: 4144 raise self.InvalidCmd("The first value of the lambdaCMS values"+ 4145 " specified must be 1.0, not %s"%str(lambda_values)) 4146 for l in lambda_values: 4147 if not isinstance(l,float): 4148 raise self.InvalidCmd("All lambda CMS values must be"+ 4149 " float, not '%s'"%str(l)) 4150 elif isinstance(lambda_values,(tuple,float)): 4151 # Format here is then (lower_bound, N) were lower_bound is 4152 # the minimum lambdaCMS value that must be probed and the 4153 # integer N is the number of such values that must be 4154 # uniformly distributed in each intervale [1.0e-i,1.0e-(i+1)] 4155 if isinstance(lambda_values, float): 4156 # Use default of 10 for the number of lambda values 4157 lower_bound = lambda_values 4158 N = 10 4159 else: 4160 if isinstance(lambda_values[0],float) and \ 4161 isinstance(lambda_values[1],int): 4162 lower_bound = lambda_values[0] 4163 N = lambda_values[1] 4164 else: 4165 raise self.InvalidCmd("'%s' must be a "%option[1]+ 4166 "tuple with types (float, int).") 4167 lambda_values = create_lambda_values_list(lower_bound,N) 4168 else: 4169 raise self.InvalidCmd("'%s' must be an expression"%option[1]+ 4170 " for either a float, tuple or list.") 4171 lower_bound = lambda_values[-1] 4172 # and finally add 5 points for stability test on the last values 4173 # Depending on how the stab test will behave at NLO, we can 4174 # consider automatically adding the values below 4175 # for stab in range(1,6): 4176 # lambda_values.append((1.0+(stab/100.0))*lower_bound) 4177 4178 CMS_options['lambdaCMS'] = lambda_values 4179 elif option[0]=='--cms': 4180 try: 4181 CMS_expansion_orders, CMS_expansion_parameters = \ 4182 option[1].split(',') 4183 except ValueError: 4184 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 4185 args[i]+" is incorrect.") 4186 CMS_options['expansion_orders'] = [expansion_order for 4187 expansion_order in CMS_expansion_orders.split('&')] 4188 CMS_options['expansion_parameters'] = {} 4189 for expansion_parameter in CMS_expansion_parameters.split('&'): 4190 try: 4191 param, replacement = expansion_parameter.split('->') 4192 except ValueError: 4193 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 4194 expansion_parameter+" is incorrect. It should be of"+\ 4195 " the form a->_any_function_of_(a,lambdaCMS).") 4196 try: 4197 # for safety prefix parameters, because 'as' for alphas 4198 # is a python reserved name for example 4199 orig_param, orig_replacement = param, replacement 4200 replacement = replacement.replace(param, 4201 '__tmpprefix__%s'%param) 4202 param = '__tmpprefix__%s'%param 4203 res = float(eval(replacement.lower(), 4204 {'lambdacms':1.0,param.lower():98.85})) 4205 except: 4206 raise self.InvalidCmd("The substitution expression "+ 4207 "'%s' for CMS expansion parameter"%orig_replacement+ 4208 " '%s' could not be evaluated. It must be an "%orig_param+ 4209 "expression of the parameter and 'lambdaCMS'.") 4210 # Put everything lower case as it will be done when 4211 # accessing model variables 4212 CMS_options['expansion_parameters'][param.lower()]=\ 4213 replacement.lower() 4214 else: 4215 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0]) 4216 4217 i=i-1 4218 args = args[:i+1] 4219 4220 if args[0]=='options': 4221 # Simple printout of the check command options 4222 logger_check.info("Options for the command 'check' are:") 4223 logger_check.info("{:<20} {}".format(' name','default value')) 4224 logger_check.info("-"*40) 4225 for key, value in options.items(): 4226 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 4227 return 4228 4229 if args[0].lower()=='cmsoptions': 4230 # Simple printout of the special check cms options 4231 logger_check.info("Special options for the command 'check cms' are:") 4232 logger_check.info("{:<20} {}".format(' name','default value')) 4233 logger_check.info("-"*40) 4234 for key, value in CMS_options.items(): 4235 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 4236 return 4237 4238 # Set the seed here if not in cms check and if specified 4239 if args[0]!='cms' and options['seed']!=-1: 4240 # Not necessarily optimal as there could be additional call to 4241 # random() as the code develops, but at least it will encompass 4242 # everything in this way. 4243 logger_check.info('Setting random seed to %d.'%options['seed']) 4244 random.seed(options['seed']) 4245 4246 proc_line = " ".join(args[1:]) 4247 # Don't try to extract the process if just re-analyzing a saved run 4248 if not (args[0]=='cms' and options['analyze']!='None'): 4249 myprocdef = self.extract_process(proc_line) 4250 4251 # Check that we have something 4252 if not myprocdef: 4253 raise self.InvalidCmd("Empty or wrong format process, please try again.") 4254 # For the check command, only the mode 'virt' make sense. 4255 if myprocdef.get('NLO_mode')=='all': 4256 myprocdef.set('NLO_mode','virt') 4257 else: 4258 myprocdef = None 4259 4260 # If the test has to write out on disk, it should do so at the location 4261 # specified below where the user must be sure to have writing access. 4262 output_path = os.getcwd() 4263 4264 if args[0] in ['timing','stability', 'profile'] and not \ 4265 myprocdef.get('perturbation_couplings'): 4266 raise self.InvalidCmd("Only loop processes can have their "+ 4267 " timings or stability checked.") 4268 4269 if args[0]=='gauge' and \ 4270 not myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4271 raise self.InvalidCmd( 4272 """Feynman vs unitary gauge comparisons can only be done if there are no loop 4273 propagators affected by this gauge. Typically, either processes at tree level 4274 or including only QCD perturbations can be considered here.""") 4275 4276 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2: 4277 raise self.InvalidCmd("The current model does not allow for both "+\ 4278 "Feynman and unitary gauge.") 4279 4280 # Disable some loggers 4281 loggers = [logging.getLogger('madgraph.diagram_generation'), 4282 logging.getLogger('madgraph.loop_diagram_generation'), 4283 logging.getLogger('ALOHA'), 4284 logging.getLogger('madgraph.helas_objects'), 4285 logging.getLogger('madgraph.loop_exporter'), 4286 logging.getLogger('madgraph.export_v4'), 4287 logging.getLogger('cmdprint'), 4288 logging.getLogger('madgraph.model'), 4289 logging.getLogger('madgraph.base_objects')] 4290 old_levels = [log.level for log in loggers] 4291 for log in loggers: 4292 log.setLevel(logging.WARNING) 4293 4294 # run the check 4295 cpu_time1 = time.time() 4296 # Run matrix element generation check on processes 4297 4298 # The aloha python output has trouble when doing (tree level of course) 4299 # python output and that loop_mode is True at the beginning. 4300 # So as a temporary fix for the problem that after doing a check at NLO 4301 # then a check at LO will fail, I make sure I set it to False if the 4302 # process is a tree-level one 4303 if myprocdef: 4304 if myprocdef.get('perturbation_couplings')==[]: 4305 aloha.loop_mode = False 4306 4307 comparisons = [] 4308 gauge_result = [] 4309 gauge_result_no_brs = [] 4310 lorentz_result =[] 4311 nb_processes = 0 4312 timings = [] 4313 stability = [] 4314 profile_time = [] 4315 profile_stab = [] 4316 cms_results = [] 4317 4318 if "_cuttools_dir" in dir(self): 4319 CT_dir = self._cuttools_dir 4320 else: 4321 CT_dir ="" 4322 if "MLReductionLib" in MLoptions: 4323 if 1 in MLoptions["MLReductionLib"]: 4324 MLoptions["MLReductionLib"].remove(1) 4325 # directories for TIR 4326 TIR_dir={} 4327 if "_iregi_dir" in dir(self): 4328 TIR_dir['iregi_dir']=self._iregi_dir 4329 else: 4330 if "MLReductionLib" in MLoptions: 4331 if 3 in MLoptions["MLReductionLib"]: 4332 logger_check.warning('IREGI not available on your system; it will be skipped.') 4333 MLoptions["MLReductionLib"].remove(3) 4334 4335 4336 if "MLReductionLib" in MLoptions: 4337 if 2 in MLoptions["MLReductionLib"]: 4338 logger_check.warning('PJFRY not supported anymore; it will be skipped.') 4339 MLoptions["MLReductionLib"].remove(2) 4340 4341 if 'golem' in self.options and isinstance(self.options['golem'],str): 4342 TIR_dir['golem_dir']=self.options['golem'] 4343 else: 4344 if "MLReductionLib" in MLoptions: 4345 if 4 in MLoptions["MLReductionLib"]: 4346 logger_check.warning('GOLEM not available on your system; it will be skipped.') 4347 MLoptions["MLReductionLib"].remove(4) 4348 4349 if 'samurai' in self.options and isinstance(self.options['samurai'],str): 4350 TIR_dir['samurai_dir']=self.options['samurai'] 4351 else: 4352 if "MLReductionLib" in MLoptions: 4353 if 5 in MLoptions["MLReductionLib"]: 4354 logger_check.warning('Samurai not available on your system; it will be skipped.') 4355 MLoptions["MLReductionLib"].remove(5) 4356 4357 if 'collier' in self.options and isinstance(self.options['collier'],str): 4358 TIR_dir['collier_dir']=self.options['collier'] 4359 else: 4360 if "MLReductionLib" in MLoptions: 4361 if 7 in MLoptions["MLReductionLib"]: 4362 logger_check.warning('Collier not available on your system; it will be skipped.') 4363 MLoptions["MLReductionLib"].remove(7) 4364 4365 if 'ninja' in self.options and isinstance(self.options['ninja'],str): 4366 TIR_dir['ninja_dir']=self.options['ninja'] 4367 else: 4368 if "MLReductionLib" in MLoptions: 4369 if 6 in MLoptions["MLReductionLib"]: 4370 logger_check.warning('Ninja not available on your system; it will be skipped.') 4371 MLoptions["MLReductionLib"].remove(6) 4372 4373 if args[0] in ['timing']: 4374 timings = process_checks.check_timing(myprocdef, 4375 param_card = param_card, 4376 cuttools=CT_dir, 4377 tir=TIR_dir, 4378 options = options, 4379 cmd = self, 4380 output_path = output_path, 4381 MLOptions = MLoptions 4382 ) 4383 4384 if args[0] in ['stability']: 4385 stability=process_checks.check_stability(myprocdef, 4386 param_card = param_card, 4387 cuttools=CT_dir, 4388 tir=TIR_dir, 4389 options = options, 4390 output_path = output_path, 4391 cmd = self, 4392 MLOptions = MLoptions) 4393 4394 if args[0] in ['profile']: 4395 # In this case timing and stability will be checked one after the 4396 # other without re-generating the process. 4397 profile_time, profile_stab = process_checks.check_profile(myprocdef, 4398 param_card = param_card, 4399 cuttools=CT_dir, 4400 tir=TIR_dir, 4401 options = options, 4402 MLOptions = MLoptions, 4403 output_path = output_path, 4404 cmd = self) 4405 4406 if args[0] in ['gauge', 'full'] and \ 4407 len(self._curr_model.get('gauge')) == 2 and\ 4408 myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4409 4410 line = " ".join(args[1:]) 4411 myprocdef = self.extract_process(line) 4412 if gauge == 'unitary': 4413 myprocdef_unit = myprocdef 4414 self.do_set('gauge Feynman', log=False) 4415 myprocdef_feyn = self.extract_process(line) 4416 else: 4417 myprocdef_feyn = myprocdef 4418 self.do_set('gauge unitary', log=False) 4419 myprocdef_unit = self.extract_process(line) 4420 4421 nb_part_unit = len(myprocdef_unit.get('model').get('particles')) 4422 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles')) 4423 if nb_part_feyn == nb_part_unit: 4424 logger_check.error('No Goldstone present for this check!!') 4425 gauge_result_no_brs = process_checks.check_unitary_feynman( 4426 myprocdef_unit, myprocdef_feyn, 4427 param_card = param_card, 4428 options=options, 4429 cuttools=CT_dir, 4430 tir=TIR_dir, 4431 reuse = options['reuse'], 4432 output_path = output_path, 4433 cmd = self) 4434 4435 # restore previous settings 4436 self.do_set('gauge %s' % gauge, log=False) 4437 nb_processes += len(gauge_result_no_brs) 4438 4439 if args[0] in ['permutation', 'full']: 4440 comparisons = process_checks.check_processes(myprocdef, 4441 param_card = param_card, 4442 quick = True, 4443 cuttools=CT_dir, 4444 tir=TIR_dir, 4445 reuse = options['reuse'], 4446 cmd = self, 4447 output_path = output_path, 4448 options=options) 4449 nb_processes += len(comparisons[0]) 4450 4451 if args[0] in ['lorentz', 'full']: 4452 myprocdeff = copy.copy(myprocdef) 4453 lorentz_result = process_checks.check_lorentz(myprocdeff, 4454 param_card = param_card, 4455 cuttools=CT_dir, 4456 tir=TIR_dir, 4457 reuse = options['reuse'], 4458 cmd = self, 4459 output_path = output_path, 4460 options=options) 4461 nb_processes += len(lorentz_result) 4462 4463 if args[0] in ['brs', 'full']: 4464 gauge_result = process_checks.check_gauge(myprocdef, 4465 param_card = param_card, 4466 cuttools=CT_dir, 4467 tir=TIR_dir, 4468 reuse = options['reuse'], 4469 cmd = self, 4470 output_path = output_path, 4471 options=options) 4472 nb_processes += len(gauge_result) 4473 4474 # The CMS check is typically more complicated and slower than others 4475 # so we don't run it automatically with 'full'. 4476 if args[0] in ['cms']: 4477 4478 cms_original_setup = self.options['complex_mass_scheme'] 4479 process_line = " ".join(args[1:]) 4480 # Merge in the CMS_options to the options 4481 for key, value in CMS_options.items(): 4482 if key=='tweak': 4483 continue 4484 if key not in options: 4485 options[key] = value 4486 else: 4487 raise MadGraph5Error("Option '%s' is both in the option"%key+\ 4488 " and CMS_option dictionary.") 4489 4490 if options['analyze']=='None': 4491 cms_results = [] 4492 for tweak in CMS_options['tweak']: 4493 options['tweak']=tweak 4494 # Try to guess the save path and try to load it before running 4495 guessed_proc = myprocdef.get_process( 4496 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4497 if not leg.get('state')], 4498 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4499 if leg.get('state')]) 4500 save_path = process_checks.CMS_save_path('pkl', 4501 {'ordered_processes':[guessed_proc.base_string()], 4502 'perturbation_orders':guessed_proc.get('perturbation_couplings')}, 4503 self._curr_model, options, output_path=output_path) 4504 if os.path.isfile(save_path) and options['reuse']: 4505 cms_result = save_load_object.load_from_file(save_path) 4506 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"% 4507 (tweak['name'],save_path)) 4508 if cms_result is None: 4509 raise self.InvalidCmd('The complex mass scheme check result'+ 4510 " file below could not be read.\n %s"%save_path) 4511 else: 4512 cms_result = process_checks.check_complex_mass_scheme( 4513 process_line, 4514 param_card = param_card, 4515 cuttools=CT_dir, 4516 tir=TIR_dir, 4517 cmd = self, 4518 output_path = output_path, 4519 MLOptions = MLoptions, 4520 options=options) 4521 # Now set the correct save path 4522 save_path = process_checks.CMS_save_path('pkl', cms_result, 4523 self._curr_model, options, output_path=output_path) 4524 cms_results.append((cms_result,save_path,tweak['name'])) 4525 else: 4526 cms_result = save_load_object.load_from_file( 4527 options['analyze'].split(',')[0]) 4528 cms_results.append((cms_result,options['analyze'].split(',')[0], 4529 CMS_options['tweak'][0]['name'])) 4530 if cms_result is None: 4531 raise self.InvalidCmd('The complex mass scheme check result'+ 4532 " file below could not be read.\n %s" 4533 %options['analyze'].split(',')[0]) 4534 4535 # restore previous settings 4536 self.do_set('complex_mass_scheme %s'%str(cms_original_setup), 4537 log=False) 4538 # Use here additional key 'ordered_processes' 4539 nb_processes += len(cms_result['ordered_processes']) 4540 4541 cpu_time2 = time.time() 4542 logger_check.info("%i check performed in %s"% (nb_processes, 4543 misc.format_time(int(cpu_time2 - cpu_time1)))) 4544 4545 if args[0] in ['cms']: 4546 text = "Note that the complex mass scheme test in principle only\n" 4547 text+= "works for stable particles in final states.\n\ns" 4548 if args[0] not in ['timing','stability', 'profile', 'cms']: 4549 if self.options['complex_mass_scheme']: 4550 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n" 4551 text+= "results only for stable particles in final states.\n\ns" 4552 elif not myprocdef.get('perturbation_couplings'): 4553 text = "Note That all width have been set to zero for those checks\n\n" 4554 else: 4555 text = "\n" 4556 else: 4557 text ="\n" 4558 4559 if timings: 4560 text += 'Timing result for the '+('optimized' if \ 4561 self.options['loop_optimized_output'] else 'default')+' output:\n' 4562 4563 text += process_checks.output_timings(myprocdef, timings) 4564 if stability: 4565 text += 'Stability result for the '+('optimized' if \ 4566 self.options['loop_optimized_output'] else 'default')+' output:\n' 4567 text += process_checks.output_stability(stability,output_path) 4568 4569 if profile_time and profile_stab: 4570 text += 'Timing result '+('optimized' if \ 4571 self.options['loop_optimized_output'] else 'default')+':\n' 4572 text += process_checks.output_profile(myprocdef, profile_stab, 4573 profile_time, output_path, options['reuse']) + '\n' 4574 if lorentz_result: 4575 text += 'Lorentz invariance results:\n' 4576 text += process_checks.output_lorentz_inv(lorentz_result) + '\n' 4577 if gauge_result: 4578 text += 'Gauge results:\n' 4579 text += process_checks.output_gauge(gauge_result) + '\n' 4580 if gauge_result_no_brs: 4581 text += 'Gauge results (switching between Unitary/Feynman/axial gauge):\n' 4582 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n' 4583 if cms_results: 4584 text += 'Complex mass scheme results (varying width in the off-shell regions):\n' 4585 cms_result = cms_results[0][0] 4586 if len(cms_results)>1: 4587 analyze = [] 4588 for i, (cms_res, save_path, tweakname) in enumerate(cms_results): 4589 save_load_object.save_to_file(save_path, cms_res) 4590 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"% 4591 (tweakname,save_path)) 4592 if i==0: 4593 analyze.append(save_path) 4594 else: 4595 analyze.append('%s(%s)'%(save_path,tweakname)) 4596 options['analyze']=','.join(analyze) 4597 options['tweak'] = CMS_options['tweak'][0] 4598 4599 self._cms_checks.append({'line':line, 'cms_result':cms_result, 4600 'options':options, 'output_path':output_path}) 4601 text += process_checks.output_complex_mass_scheme(cms_result, 4602 output_path, options, self._curr_model, 4603 output='concise_text' if options['report']=='concise' else 'text')+'\n' 4604 4605 if comparisons and len(comparisons[0])>0: 4606 text += 'Process permutation results:\n' 4607 text += process_checks.output_comparisons(comparisons[0]) + '\n' 4608 self._comparisons = comparisons 4609 4610 # We use the reuse tag for an alternative way of skipping the pager. 4611 if len(text.split('\n'))>20 and not '-reuse' in line and text!='': 4612 if 'test_manager' not in sys.argv[0]: 4613 pydoc.pager(text) 4614 4615 # Restore diagram logger 4616 for i, log in enumerate(loggers): 4617 log.setLevel(old_levels[i]) 4618 4619 # Output the result to the interface directly if short enough or if it 4620 # was anyway not output to the pager 4621 if len(text.split('\n'))<=20 or options['reuse']: 4622 # Useful to really specify what logger is used for ML acceptance tests 4623 logging.getLogger('madgraph.check_cmd').info(text) 4624 else: 4625 logging.getLogger('madgraph.check_cmd').debug(text) 4626 4627 # clean the globals created. 4628 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL) 4629 if not options['reuse']: 4630 process_checks.clean_up(self._mgme_dir) 4631 4632
4633 - def clean_process(self):
4634 """ensure that all processes are cleaned from memory. 4635 typically called from import model and generate XXX command 4636 """ 4637 4638 aloha_lib.KERNEL.clean() 4639 # Reset amplitudes 4640 self._curr_amps = diagram_generation.AmplitudeList() 4641 # Reset Process definition 4642 self._curr_proc_defs = base_objects.ProcessDefinitionList() 4643 # Reset Helas matrix elements 4644 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4645 self._generate_info = "" 4646 # Reset _done_export, since we have new process 4647 self._done_export = False 4648 # Also reset _export_format and _export_dir 4649 self._export_format = None
4650 4651 4652 # Generate a new amplitude
4653 - def do_generate(self, line):
4654 """Main commands: Generate an amplitude for a given process""" 4655 4656 self.clean_process() 4657 self._generate_info = line 4658 4659 # Call add process 4660 args = self.split_arg(line) 4661 args.insert(0, 'process') 4662 self.do_add(" ".join(args))
4663
4664 - def extract_process(self, line, proc_number = 0, overall_orders = {}):
4665 """Extract a process definition from a string. Returns 4666 a ProcessDefinition.""" 4667 4668 orig_line = line 4669 # Check basic validity of the line 4670 if not len(re.findall('>\D', line)) in [1,2]: 4671 self.do_help('generate') 4672 raise self.InvalidCmd('Wrong use of \">\" special character.') 4673 4674 4675 # Perform sanity modifications on the lines: 4676 # Add a space before and after any > , $ / | [ ] 4677 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)") 4678 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line) 4679 4680 # Use regular expressions to extract s-channel propagators, 4681 # forbidden s-channel propagators/particles, coupling orders 4682 # and process number, starting from the back 4683 4684 # Start with process number (identified by "@") 4685 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4686 proc_number_re = proc_number_pattern.match(line) 4687 if proc_number_re: 4688 proc_number = int(proc_number_re.group(2)) 4689 line = proc_number_re.group(1)+ proc_number_re.group(3) 4690 #overall_order are already handle but it is better to pass the info to each group 4691 4692 # Now check for perturbation orders, specified in between squared brackets 4693 perturbation_couplings_pattern = \ 4694 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\ 4695 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 4696 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 4697 perturbation_couplings = "" 4698 LoopOption= 'tree' 4699 HasBorn= True 4700 if perturbation_couplings_re: 4701 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 4702 option=perturbation_couplings_re.group("option") 4703 if option: 4704 if option in self._valid_nlo_modes: 4705 LoopOption=option 4706 if option=='sqrvirt': 4707 LoopOption='virt' 4708 HasBorn=False 4709 elif option=='noborn': 4710 HasBorn=False 4711 else: 4712 raise self.InvalidCmd("NLO mode %s is not valid. "%option+\ 4713 "Valid modes are %s. "%str(self._valid_nlo_modes)) 4714 else: 4715 LoopOption='all' 4716 4717 line = perturbation_couplings_re.group("proc")+\ 4718 perturbation_couplings_re.group("rest") 4719 4720 ## Now check for orders/squared orders/constrained orders 4721 order_pattern = re.compile(\ 4722 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\ 4723 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*?(?P<after>.*)") 4724 order_re = order_pattern.match(line) 4725 squared_orders = {} 4726 orders = {} 4727 constrained_orders = {} 4728 ## The 'split_orders' (i.e. those for which individual matrix element 4729 ## evalutations must be provided for each corresponding order value) are 4730 ## defined from the orders specified in between [] and any order for 4731 ## which there are squared order constraints. 4732 split_orders = [] 4733 while order_re: 4734 type = order_re.group('type') 4735 if order_re.group('name').endswith('^2'): 4736 if type not in self._valid_sqso_types: 4737 raise self.InvalidCmd("Type of squared order "+\ 4738 "constraint '%s'"% type+" is not supported.") 4739 if type == '=': 4740 name = order_re.group('name') 4741 value = order_re.group('value') 4742 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4743 {'n':name, 'v': value}) 4744 type = "<=" 4745 squared_orders[order_re.group('name')[:-2]] = \ 4746 (int(order_re.group('value')),type) 4747 else: 4748 if type not in self._valid_amp_so_types: 4749 raise self.InvalidCmd("Amplitude order constraints can only be of type %s"%\ 4750 (', '.join(self._valid_amp_so_types))+", not '%s'."%type) 4751 name = order_re.group('name') 4752 value = int(order_re.group('value')) 4753 if type in ['=', '<=']: 4754 if type == '=' and value != 0: 4755 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4756 {'n':name, 'v': value}) 4757 orders[name] = value 4758 elif type == "==": 4759 constrained_orders[name] = (value, type) 4760 if name not in squared_orders: 4761 squared_orders[name] = (2 * value,'==') 4762 if True:#name not in orders: 4763 orders[name] = value 4764 4765 elif type == ">": 4766 constrained_orders[name] = (value, type) 4767 if name not in squared_orders: 4768 squared_orders[name] = (2 * value,'>') 4769 4770 line = '%s %s' % (order_re.group('before'),order_re.group('after')) 4771 order_re = order_pattern.match(line) 4772 4773 # handle the case where default is not 99 and some coupling defined 4774 if self.options['default_unset_couplings'] != 99 and \ 4775 (orders or squared_orders): 4776 4777 to_set = [name for name in self._curr_model.get('coupling_orders') 4778 if name not in orders and name not in squared_orders] 4779 if to_set: 4780 logger.info('the following coupling will be allowed up to the maximal value of %s: %s' % 4781 (self.options['default_unset_couplings'], ', '.join(to_set)), '$MG:BOLD') 4782 for name in to_set: 4783 orders[name] = int(self.options['default_unset_couplings']) 4784 4785 #only allow amplitue restrctions >/ == for LO/tree level 4786 if constrained_orders and LoopOption != 'tree': 4787 raise self.InvalidCmd("Amplitude order constraints (for not LO processes) can only be of type %s"%\ 4788 (', '.join(['<=']))+", not '%s'."%type) 4789 4790 # If the squared orders are defined but not the orders, assume 4791 # orders=sq_orders. In case the squared order has a negative value or is 4792 # defined with the '>' operato, then this order correspondingly set to 4793 # be maximal (99) since there is no way to know, during generation, if 4794 # the amplitude being contstructed will be leading or not. 4795 if orders=={} and squared_orders!={}: 4796 for order in squared_orders.keys(): 4797 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>': 4798 orders[order]=squared_orders[order][0] 4799 else: 4800 orders[order]=99 4801 4802 4803 if not self._curr_model['case_sensitive']: 4804 # Particle names lowercase 4805 line = line.lower() 4806 4807 # Now check for forbidden particles, specified using "/" 4808 slash = line.find("/") 4809 dollar = line.find("$") 4810 forbidden_particles = "" 4811 if slash > 0: 4812 if dollar > slash: 4813 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line) 4814 else: 4815 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line) 4816 if forbidden_particles_re: 4817 forbidden_particles = forbidden_particles_re.group(2) 4818 line = forbidden_particles_re.group(1) 4819 if len(forbidden_particles_re.groups()) > 2: 4820 line = line + forbidden_particles_re.group(3) 4821 4822 # Now check for forbidden schannels, specified using "$$" 4823 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line) 4824 forbidden_schannels = "" 4825 if forbidden_schannels_re: 4826 forbidden_schannels = forbidden_schannels_re.group(2) 4827 line = forbidden_schannels_re.group(1) 4828 4829 # Now check for forbidden onshell schannels, specified using "$" 4830 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line) 4831 forbidden_onsh_schannels = "" 4832 if forbidden_onsh_schannels_re: 4833 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2) 4834 line = forbidden_onsh_schannels_re.group(1) 4835 4836 # Now check for required schannels, specified using "> >" 4837 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line) 4838 required_schannels = "" 4839 if required_schannels_re: 4840 required_schannels = required_schannels_re.group(2) 4841 line = required_schannels_re.group(1) + ">" + \ 4842 required_schannels_re.group(3) 4843 4844 args = self.split_arg(line) 4845 4846 myleglist = base_objects.MultiLegList() 4847 state = False 4848 4849 # Extract process 4850 for part_name in args: 4851 if part_name == '>': 4852 if not myleglist: 4853 raise self.InvalidCmd("No final state particles") 4854 state = True 4855 continue 4856 4857 mylegids = [] 4858 polarization = [] 4859 if '{' in part_name: 4860 part_name, pol = part_name.split('{',1) 4861 pol, rest = pol.split('}',1) 4862 4863 no_dup_name = part_name 4864 while True: 4865 try: 4866 spin = self._curr_model.get_particle(no_dup_name).get('spin') 4867 break 4868 except AttributeError: 4869 if no_dup_name in self._multiparticles: 4870 spins = set([self._curr_model.get_particle(p).get('spin') for p in self._multiparticles[no_dup_name]]) 4871 if len(spins) > 1: 4872 raise self.InvalidCmd('Can not use polarised on multi-particles for multi-particles with various spin') 4873 else: 4874 spin = spins.pop() 4875 break 4876 elif no_dup_name[0].isdigit(): 4877 no_dup_name = no_dup_name[1:] 4878 else: 4879 raise 4880 if rest: 4881 raise self.InvalidCmd('A space is required after the "}" symbol to separate particles') 4882 ignore =False 4883 for i,p in enumerate(pol): 4884 if ignore or p==',': 4885 ignore= False 4886 continue 4887 if p in ['t','T']: 4888 if spin == 3: 4889 polarization += [1,-1] 4890 else: 4891 raise self.InvalidCmd('"T" (transverse) polarization are only supported for spin one particle.') 4892 elif p in ['l', 'L']: 4893 if spin == 3: 4894 logger.warning('"L" polarization is interpreted as Left for Longitudinal please use "0".') 4895 polarization += [-1] 4896 elif p in ['R','r']: 4897 polarization += [1] 4898 elif p in ["A",'a']: 4899 if spin == 3: 4900 polarization += [99] 4901 else: 4902 raise self.InvalidCmd('"A" (auxiliary) polarization are only supported for spin one particle.') 4903 elif p in ['+']: 4904 if i +1 < len(pol) and pol[i+1].isdigit(): 4905 p = int(pol[i+1]) 4906 if abs(p) > 3: 4907 raise self.InvalidCmd("polarization are between -3 and 3") 4908 polarization.append(p) 4909 ignore = True 4910 else: 4911 polarization += [1] 4912 elif p in ['-']: 4913 if i+1 < len(pol) and pol[i+1].isdigit(): 4914 p = int(pol[i+1]) 4915 if abs(p) > 3: 4916 raise self.InvalidCmd("polarization are between -3 and 3") 4917 polarization.append(-p) 4918 ignore = True 4919 else: 4920 polarization += [-1] 4921 elif p in [0,'0']: 4922 if spin in [1,2]: 4923 raise self.InvalidCmd('"0" (longitudinal) polarization are not supported for scalar/fermion.') 4924 else: 4925 polarization += [0] 4926 elif p.isdigit(): 4927 p = int(p) 4928 if abs(p) > 3: 4929 raise self.InvalidCmd("polarization are between -3 and 3") 4930 polarization.append(p) 4931 else: 4932 raise self.InvalidCmd('Invalid Polarization') 4933 4934 duplicate =1 4935 if part_name in self._multiparticles: 4936 if isinstance(self._multiparticles[part_name][0], list): 4937 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 4938 " which can be used only for required s-channels") 4939 mylegids.extend(self._multiparticles[part_name]) 4940 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit(): 4941 if int(part_name) in self._curr_model.get('particle_dict'): 4942 mylegids.append(int(part_name)) 4943 else: 4944 raise self.InvalidCmd("No pdg_code %s in model" % part_name) 4945 else: 4946 mypart = self._curr_model['particles'].get_copy(part_name) 4947 4948 if mypart: 4949 mylegids.append(mypart.get_pdg_code()) 4950 else: 4951 # check for duplication flag! 4952 if part_name[0].isdigit(): 4953 duplicate, part_name = int(part_name[0]), part_name[1:] 4954 if part_name in self._multiparticles: 4955 if isinstance(self._multiparticles[part_name][0], list): 4956 raise self.InvalidCmd(\ 4957 "Multiparticle %s is or-multiparticle" % part_name + \ 4958 " which can be used only for required s-channels") 4959 mylegids.extend(self._multiparticles[part_name]) 4960 else: 4961 mypart = self._curr_model['particles'].get_copy(part_name) 4962 mylegids.append(mypart.get_pdg_code()) 4963 4964 if mylegids: 4965 for _ in range(duplicate): 4966 myleglist.append(base_objects.MultiLeg({'ids':mylegids, 4967 'state':state, 4968 'polarization': polarization})) 4969 else: 4970 raise self.InvalidCmd("No particle %s in model" % part_name) 4971 4972 # Apply the keyword 'all' for perturbed coupling orders. 4973 if perturbation_couplings.lower() in ['all', 'loonly']: 4974 if perturbation_couplings.lower() in ['loonly']: 4975 LoopOption = 'LOonly' 4976 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings']) 4977 4978 4979 if [leg for leg in myleglist if leg.get('state') == True]: 4980 # We have a valid process 4981 # Extract perturbation orders 4982 perturbation_couplings_list = perturbation_couplings.split() 4983 if perturbation_couplings_list==['']: 4984 perturbation_couplings_list=[] 4985 # Correspondingly set 'split_order' from the squared orders and the 4986 # perturbation couplings list 4987 split_orders=list(set(perturbation_couplings_list+list(squared_orders.keys()))) 4988 try: 4989 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else 4990 self._curr_model.get('order_hierarchy') 4991 [elem if not elem.endswith('.sqrt') else elem[:-5]]) 4992 except KeyError: 4993 raise self.InvalidCmd("The loaded model does not defined a "+\ 4994 " coupling order hierarchy for these couplings: %s"%\ 4995 str([so for so in split_orders if so!='WEIGHTED' and so not 4996 in list(self._curr_model['order_hierarchy'].keys())])) 4997 4998 # If the loopOption is 'tree' then the user used the syntax 4999 # [tree= Orders] for the sole purpose of setting split_orders. We 5000 # then empty the perturbation_couplings_list at this stage. 5001 if LoopOption=='tree': 5002 perturbation_couplings_list = [] 5003 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']: 5004 if not isinstance(self._curr_model,loop_base_objects.LoopModel): 5005 raise self.InvalidCmd(\ 5006 "The current model does not allow for loop computations.") 5007 else: 5008 for pert_order in perturbation_couplings_list: 5009 if pert_order not in self._curr_model['perturbation_couplings']: 5010 raise self.InvalidCmd(\ 5011 "Perturbation order %s is not among" % pert_order + \ 5012 " the perturbation orders allowed for by the loop model.") 5013 if not self.options['loop_optimized_output'] and \ 5014 LoopOption not in ['tree','real'] and split_orders!=[]: 5015 logger.warning('The default output mode (loop_optimized_output'+\ 5016 ' = False) does not support evaluations for given powers of'+\ 5017 ' coupling orders. MadLoop output will therefore not be'+\ 5018 ' able to provide such quantities.') 5019 split_orders = [] 5020 5021 # Now extract restrictions 5022 forbidden_particle_ids = \ 5023 self.extract_particle_ids(forbidden_particles) 5024 if forbidden_particle_ids and \ 5025 isinstance(forbidden_particle_ids[0], list): 5026 raise self.InvalidCmd(\ 5027 "Multiparticle %s is or-multiparticle" % part_name + \ 5028 " which can be used only for required s-channels") 5029 forbidden_onsh_schannel_ids = \ 5030 self.extract_particle_ids(forbidden_onsh_schannels) 5031 forbidden_schannel_ids = \ 5032 self.extract_particle_ids(forbidden_schannels) 5033 if forbidden_onsh_schannel_ids and \ 5034 isinstance(forbidden_onsh_schannel_ids[0], list): 5035 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 5036 " which can be used only for required s-channels") 5037 if forbidden_schannel_ids and \ 5038 isinstance(forbidden_schannel_ids[0], list): 5039 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 5040 " which can be used only for required s-channels") 5041 required_schannel_ids = \ 5042 self.extract_particle_ids(required_schannels) 5043 if required_schannel_ids and not \ 5044 isinstance(required_schannel_ids[0], list): 5045 required_schannel_ids = [required_schannel_ids] 5046 5047 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()]) 5048 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1: 5049 raise self.InvalidCmd( 5050 "At most one negative squared order constraint can be specified.") 5051 5052 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()]) 5053 5054 out = base_objects.ProcessDefinition({'legs': myleglist, 5055 'model': self._curr_model, 5056 'id': proc_number, 5057 'orders': orders, 5058 'squared_orders':sqorders_values, 5059 'sqorders_types':sqorders_types, 5060 'constrained_orders': constrained_orders, 5061 'forbidden_particles': forbidden_particle_ids, 5062 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids, 5063 'forbidden_s_channels': forbidden_schannel_ids, 5064 'required_s_channels': required_schannel_ids, 5065 'overall_orders': overall_orders, 5066 'perturbation_couplings': perturbation_couplings_list, 5067 'has_born':HasBorn, 5068 'NLO_mode':LoopOption, 5069 'split_orders':split_orders 5070 }) 5071 return out
5072 # 'is_decay_chain': decay_process\ 5073 5074
5075 - def create_loop_induced(self, line, myprocdef=None):
5076 """ Routine to create the MultiProcess for the loop-induced case""" 5077 5078 args = self.split_arg(line) 5079 5080 warning_duplicate = True 5081 if '--no_warning=duplicate' in args: 5082 warning_duplicate = False 5083 args.remove('--no_warning=duplicate') 5084 5085 # Check the validity of the arguments 5086 self.check_add(args) 5087 if args[0] == 'process': 5088 args = args[1:] 5089 5090 # special option for 1->N to avoid generation of kinematically forbidden 5091 #decay. 5092 if args[-1].startswith('--optimize'): 5093 optimize = True 5094 args.pop() 5095 else: 5096 optimize = False 5097 5098 # Extract potential loop_filter 5099 loop_filter=None 5100 for arg in args: 5101 if arg.startswith('--loop_filter='): 5102 loop_filter = arg[14:] 5103 #if not isinstance(self, extended_cmd.CmdShell): 5104 # raise self.InvalidCmd, "loop_filter is not allowed in web mode" 5105 args = [a for a in args if not a.startswith('--loop_filter=')] 5106 5107 if not myprocdef: 5108 myprocdef = self.extract_process(' '.join(args)) 5109 5110 myprocdef.set('NLO_mode', 'noborn') 5111 5112 # store the first process (for the perl script) 5113 if not self._generate_info: 5114 self._generate_info = line 5115 5116 # Reset Helas matrix elements 5117 #self._curr_matrix_elements = helas_objects.HelasLoopInducedMultiProcess() 5118 5119 5120 # Check that we have the same number of initial states as 5121 # existing processes 5122 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 5123 myprocdef.get_ninitial(): 5124 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 5125 5126 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \ 5127 self._curr_amps[0]['has_born']): 5128 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process") 5129 5130 # Negative coupling order contraints can be given on at most one 5131 # coupling order (and either in squared orders or orders, not both) 5132 if len([1 for val in list(myprocdef.get('orders').values())+\ 5133 list(myprocdef.get('squared_orders').values()) if val<0])>1: 5134 raise MadGraph5Error("Negative coupling order constraints"+\ 5135 " can only be given on one type of coupling and either on"+\ 5136 " squared orders or amplitude orders, not both.") 5137 5138 cpu_time1 = time.time() 5139 5140 # Generate processes 5141 if self.options['group_subprocesses'] == 'Auto': 5142 collect_mirror_procs = True 5143 else: 5144 collect_mirror_procs = self.options['group_subprocesses'] 5145 ignore_six_quark_processes = \ 5146 self.options['ignore_six_quark_processes'] if \ 5147 "ignore_six_quark_processes" in self.options \ 5148 else [] 5149 5150 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 5151 5152 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef, 5153 collect_mirror_procs = collect_mirror_procs, 5154 ignore_six_quark_processes = ignore_six_quark_processes, 5155 optimize=optimize, 5156 loop_filter=loop_filter) 5157 5158 for amp in myproc.get('amplitudes'): 5159 if amp not in self._curr_amps: 5160 self._curr_amps.append(amp) 5161 if amp['has_born']: 5162 raise Exception 5163 elif warning_duplicate: 5164 raise self.InvalidCmd("Duplicate process %s found. Please check your processes." % \ 5165 amp.nice_string_processes()) 5166 5167 # Reset _done_export, since we have new process 5168 self._done_export = False 5169 5170 cpu_time2 = time.time() 5171 5172 nprocs = len(myproc.get('amplitudes')) 5173 ndiags = sum([amp.get_number_of_diagrams() for \ 5174 amp in myproc.get('amplitudes')]) 5175 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 5176 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 5177 ndiags = sum([amp.get_number_of_diagrams() for \ 5178 amp in self._curr_amps]) 5179 logger.info("Total: %i processes with %i diagrams" % \ 5180 (len(self._curr_amps), ndiags))
5181 5182 @staticmethod
5183 - def split_process_line(procline):
5184 """Takes a valid process and return 5185 a tuple (core_process, options). This removes 5186 - any NLO specifications. 5187 - any options 5188 [Used by MadSpin] 5189 """ 5190 5191 # remove the tag "[*]": this tag is used in aMC@LNO , 5192 # but it is not a valid syntax for LO 5193 line=procline 5194 pos1=line.find("[") 5195 if pos1>0: 5196 pos2=line.find("]") 5197 if pos2 >pos1: 5198 line=line[:pos1]+line[pos2+1:] 5199 # 5200 # Extract the options: 5201 # 5202 # A. Remove process number (identified by "@") 5203 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 5204 proc_number_re = proc_number_pattern.match(line) 5205 if proc_number_re: 5206 line = proc_number_re.group(1) + proc_number_re.group(3) 5207 5208 # B. search for the beginning of the option string 5209 pos=1000 5210 # start with order 5211 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$") 5212 order_re = order_pattern.match(line) 5213 if (order_re): 5214 pos_order=line.find(order_re.group(2)) 5215 if pos_order>0 and pos_order < pos : pos=pos_order 5216 5217 # then look for slash or dollar 5218 slash = line.find("/") 5219 if slash > 0 and slash < pos: pos=slash 5220 dollar = line.find("$") 5221 if dollar > 0 and dollar < pos: pos=dollar 5222 5223 if pos<1000: 5224 proc_option=line[pos:] 5225 line=line[:pos] 5226 else: 5227 proc_option="" 5228 5229 return line, proc_option
5230
5231 - def get_final_part(self, procline):
5232 """Takes a valid process and return 5233 a set of id of final states particles. [Used by MadSpin] 5234 """ 5235 5236 if not self._curr_model['case_sensitive']: 5237 procline = procline.lower() 5238 pids = self._curr_model.get('name2pdg') 5239 5240 # method. 5241 # 1) look for decay. 5242 # in presence of decay call this routine recursively and veto 5243 # the particles which are decayed 5244 5245 # Deal with decay chain 5246 if ',' in procline: 5247 core, decay = procline.split(',', 1) 5248 core_final = self.get_final_part(core) 5249 5250 #split the decay 5251 all_decays = decay.split(',') 5252 nb_level, tmp_decay = 0, '' 5253 decays = [] 5254 # deal with () 5255 for one_decay in all_decays: 5256 if '(' in one_decay: 5257 nb_level += 1 5258 if ')' in one_decay: 5259 nb_level -= 1 5260 5261 if nb_level: 5262 if tmp_decay: 5263 tmp_decay += ', %s' % one_decay 5264 else: 5265 tmp_decay = one_decay 5266 elif tmp_decay: 5267 final = '%s,%s' % (tmp_decay, one_decay) 5268 final = final.strip() 5269 assert final[0] == '(' and final[-1] == ')' 5270 final = final[1:-1] 5271 decays.append(final) 5272 tmp_decay = '' 5273 else: 5274 decays.append(one_decay) 5275 # remove from the final states all particles which are decayed 5276 for one_decay in decays: 5277 first = one_decay.split('>',1)[0].strip() 5278 if first in pids: 5279 pid = set([pids[first]]) 5280 elif first in self._multiparticles: 5281 pid = set(self._multiparticles[first]) 5282 else: 5283 raise Exception('invalid particle name: %s. ' % first) 5284 core_final.difference_update(pid) 5285 core_final.update(self.get_final_part(one_decay)) 5286 5287 return core_final 5288 5289 # NO DECAY CHAIN 5290 final = set() 5291 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline) 5292 particles = final_states.groups()[0] 5293 for particle in particles.split(): 5294 if '{' in particle: 5295 particle = particle.split('{')[0] 5296 if particle in pids: 5297 final.add(pids[particle]) 5298 elif particle in self._multiparticles: 5299 final.update(set(self._multiparticles[particle])) 5300 elif particle[0].isdigit(): 5301 if particle[1:] in pids: 5302 final.add(pids[particle[1:]]) 5303 elif particle in self._multiparticles: 5304 final.update(set(self._multiparticles[particle[1:]])) 5305 5306 return final
5307
5308 - def extract_particle_ids(self, args):
5309 """Extract particle ids from a list of particle names. If 5310 there are | in the list, this corresponds to an or-list, which 5311 is represented as a list of id lists. An or-list is used to 5312 allow multiple required s-channel propagators to be specified 5313 (e.g. Z/gamma).""" 5314 5315 if isinstance(args, six.string_types): 5316 args.replace("|", " | ") 5317 args = self.split_arg(args) 5318 all_ids = [] 5319 ids=[] 5320 for part_name in args: 5321 mypart = self._curr_model['particles'].get_copy(part_name) 5322 if mypart: 5323 ids.append([mypart.get_pdg_code()]) 5324 elif part_name in self._multiparticles: 5325 ids.append(self._multiparticles[part_name]) 5326 elif part_name == "|": 5327 # This is an "or-multiparticle" 5328 if ids: 5329 all_ids.append(ids) 5330 ids = [] 5331 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()): 5332 ids.append([int(part_name)]) 5333 else: 5334 raise self.InvalidCmd("No particle %s in model" % part_name) 5335 all_ids.append(ids) 5336 # Flatten id list, to take care of multiparticles and 5337 # or-multiparticles 5338 res_lists = [] 5339 for i, id_list in enumerate(all_ids): 5340 res_lists.extend(diagram_generation.expand_list_list(id_list)) 5341 # Trick to avoid duplication while keeping ordering 5342 for ilist, idlist in enumerate(res_lists): 5343 set_dict = {} 5344 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \ 5345 if i not in set_dict] 5346 5347 if len(res_lists) == 1: 5348 res_lists = res_lists[0] 5349 5350 return res_lists
5351
5352 - def optimize_order(self, pdg_list):
5353 """Optimize the order of particles in a pdg list, so that 5354 similar particles are next to each other. Sort according to: 5355 1. pdg > 0, 2. spin, 3. color, 4. mass > 0""" 5356 5357 if not pdg_list: 5358 return 5359 if not isinstance(pdg_list[0], int): 5360 return 5361 5362 model = self._curr_model 5363 pdg_list.sort(key = lambda i: i < 0) 5364 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion()) 5365 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'), 5366 reverse = True) 5367 pdg_list.sort(key = lambda i: \ 5368 model.get_particle(i).get('mass').lower() != 'zero')
5369
5370 - def extract_decay_chain_process(self, line, level_down=False, proc_number=0):
5371 """Recursively extract a decay chain process definition from a 5372 string. Returns a ProcessDefinition.""" 5373 5374 # Start with process number (identified by "@") and overall orders 5375 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*=\s*\d+\s*)*)$") 5376 proc_number_re = proc_number_pattern.match(line) 5377 overall_orders = {} 5378 if proc_number_re: 5379 proc_number = int(proc_number_re.group(2)) 5380 line = proc_number_re.group(1) 5381 if proc_number_re.group(3): 5382 order_pattern = re.compile("^(.*?)\s*(\w+)\s*=\s*(\d+)\s*$") 5383 order_line = proc_number_re.group(3) 5384 order_re = order_pattern.match(order_line) 5385 while order_re: 5386 overall_orders[order_re.group(2)] = int(order_re.group(3)) 5387 order_line = order_re.group(1) 5388 order_re = order_pattern.match(order_line) 5389 logger.info(line) 5390 5391 5392 index_comma = line.find(",") 5393 index_par = line.find(")") 5394 min_index = index_comma 5395 if index_par > -1 and (index_par < min_index or min_index == -1): 5396 min_index = index_par 5397 5398 if min_index > -1: 5399 core_process = self.extract_process(line[:min_index], proc_number, 5400 overall_orders) 5401 else: 5402 core_process = self.extract_process(line, proc_number, 5403 overall_orders) 5404 5405 #level_down = False 5406 5407 while index_comma > -1: 5408 line = line[index_comma + 1:] 5409 if not line.strip(): 5410 break 5411 index_par = line.find(')') 5412 # special cases: parenthesis but no , => remove the paranthesis! 5413 if line.lstrip()[0] == '(' and index_par !=-1 and \ 5414 not ',' in line[:index_par]: 5415 par_start = line.find('(') 5416 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:]) 5417 index_par = line.find(')') 5418 if line.lstrip()[0] == '(': 5419 # Go down one level in process hierarchy 5420 #level_down = True 5421 line = line.lstrip()[1:] 5422 # This is where recursion happens 5423 decay_process, line = \ 5424 self.extract_decay_chain_process(line, 5425 level_down=True) 5426 index_comma = line.find(",") 5427 index_par = line.find(')') 5428 else: 5429 index_comma = line.find(",") 5430 min_index = index_comma 5431 if index_par > -1 and \ 5432 (index_par < min_index or min_index == -1): 5433 min_index = index_par 5434 if min_index > -1: 5435 decay_process = self.extract_process(line[:min_index]) 5436 else: 5437 decay_process = self.extract_process(line) 5438 5439 core_process.get('decay_chains').append(decay_process) 5440 5441 if level_down: 5442 if index_par == -1: 5443 raise self.InvalidCmd("Missing ending parenthesis for decay process") 5444 5445 if index_par < index_comma: 5446 line = line[index_par + 1:] 5447 level_down = False 5448 break 5449 5450 if level_down: 5451 index_par = line.find(')') 5452 if index_par == -1: 5453 raise self.InvalidCmd("Missing ending parenthesis for decay process") 5454 line = line[index_par + 1:] 5455 5456 # Return the core process (ends recursion when there are no 5457 # more decays) 5458 return core_process, line
5459 5460 5461 # Import files
5462 - def do_import(self, line, force=False):
5463 """Main commands: Import files with external formats""" 5464 5465 args = self.split_arg(line) 5466 # Check argument's validity 5467 self.check_import(args) 5468 if args[0].startswith('model'): 5469 self._model_v4_path = None 5470 # Reset amplitudes and matrix elements 5471 self.clean_process() 5472 # Import model 5473 if args[0].endswith('_v4'): 5474 self._curr_model, self._model_v4_path = \ 5475 import_v4.import_model(args[1], self._mgme_dir) 5476 else: 5477 # avoid loading the qcd/qed model twice 5478 if (args[1].startswith('loop_qcd_qed_sm') or\ 5479 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\ 5480 self.options['gauge']!='Feynman': 5481 logger.info('Switching to Feynman gauge because '+\ 5482 'it is the only one supported by the model %s.'%args[1]) 5483 self._curr_model = None 5484 self.do_set('gauge Feynman',log=False) 5485 prefix = not '--noprefix' in args 5486 if prefix: 5487 aloha.aloha_prefix='mdl_' 5488 else: 5489 aloha.aloha_prefix='' 5490 5491 self._curr_model = import_ufo.import_model(args[1], prefix=prefix, 5492 complex_mass_scheme=self.options['complex_mass_scheme']) 5493 if os.path.sep in args[1] and "import" in self.history[-1]: 5494 self.history[-1] = 'import model %s' % self._curr_model.get('modelpath+restriction') 5495 5496 if self.options['gauge'] in ['unitary', 'axial']: 5497 if not force and isinstance(self._curr_model,\ 5498 loop_base_objects.LoopModel) and \ 5499 self._curr_model.get('perturbation_couplings') not in \ 5500 [[],['QCD']]: 5501 if 1 not in self._curr_model.get('gauge') : 5502 logger_stderr.warning('This model does not allow Feynman '+\ 5503 'gauge. You will only be able to do tree level '+\ 5504 'QCD loop cmputations with it.') 5505 else: 5506 logger.info('Change to the gauge to Feynman because '+\ 5507 'this loop model allows for more than just tree level'+\ 5508 ' and QCD perturbations.') 5509 self.do_set('gauge Feynman', log=False) 5510 return 5511 if 0 not in self._curr_model.get('gauge') : 5512 logger_stderr.warning('Change the gauge to Feynman since '+\ 5513 'the model does not allow unitary gauge') 5514 self.do_set('gauge Feynman', log=False) 5515 return 5516 else: 5517 if 1 not in self._curr_model.get('gauge') : 5518 logger_stderr.warning('Change the gauge to unitary since the'+\ 5519 ' model does not allow Feynman gauge.'+\ 5520 ' Please re-import the model') 5521 self._curr_model = None 5522 self.do_set('gauge unitary', log= False) 5523 return 5524 5525 if '-modelname' not in args: 5526 self._curr_model.pass_particles_name_in_mg_default() 5527 5528 # Do post-processing of model 5529 self.process_model() 5530 # Reset amplitudes and matrix elements and global checks 5531 self._curr_amps = diagram_generation.AmplitudeList() 5532 # Reset proc defs 5533 self._curr_proc_defs = base_objects.ProcessDefinitionList() 5534 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 5535 process_checks.store_aloha = [] 5536 5537 elif args[0] == 'command': 5538 5539 if not os.path.isfile(args[1]): 5540 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1]) 5541 else: 5542 # Check the status of export and try to use file position if no 5543 #self._export dir are define 5544 self.check_for_export_dir(args[1]) 5545 # Execute the card 5546 self.import_command_file(args[1]) 5547 5548 elif args[0] == 'banner': 5549 type = madevent_interface.MadEventCmd.detect_card_type(args[1]) 5550 if type != 'banner': 5551 raise self.InvalidCmd('The File should be a valid banner') 5552 ban = banner_module.Banner(args[1]) 5553 # Check that this is MG5 banner 5554 if 'mg5proccard' in ban: 5555 for line in ban['mg5proccard'].split('\n'): 5556 if line.startswith('#') or line.startswith('<'): 5557 continue 5558 self.exec_cmd(line) 5559 else: 5560 raise self.InvalidCmd('Only MG5 banner are supported') 5561 5562 if not self._done_export: 5563 self.exec_cmd('output . -f') 5564 5565 ban.split(self._done_export[0]) 5566 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards')) 5567 if '--no_launch' not in args: 5568 self.exec_cmd('launch') 5569 5570 elif args[0] == 'proc_v4': 5571 5572 if len(args) == 1 and self._export_dir: 5573 proc_card = pjoin(self._export_dir, 'Cards', \ 5574 'proc_card.dat') 5575 elif len(args) == 2: 5576 proc_card = args[1] 5577 # Check the status of export and try to use file position is no 5578 # self._export dir are define 5579 self.check_for_export_dir(os.path.realpath(proc_card)) 5580 else: 5581 raise MadGraph5Error('No default directory in output') 5582 5583 5584 #convert and excecute the card 5585 self.import_mg4_proc_card(proc_card)
5586
5587 - def remove_pointless_decay(self, param_card):
5588 """ For simple decay chain: remove diagram that are not in the BR. 5589 param_card should be a ParamCard instance.""" 5590 5591 assert isinstance(param_card, check_param_card.ParamCard) 5592 5593 # Collect amplitudes 5594 amplitudes = diagram_generation.AmplitudeList() 5595 for amp in self._curr_amps: 5596 amplitudes.extend(amp.get_amplitudes()) 5597 5598 decay_tables = param_card['decay'].decay_table 5599 to_remove = [] 5600 for amp in amplitudes: 5601 mother = [l.get('id') for l in amp['process'].get('legs') \ 5602 if not l.get('state')] 5603 if 1 == len(mother): 5604 try: 5605 decay_table = decay_tables[abs(mother[0])] 5606 except KeyError: 5607 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0])) 5608 continue # No BR for this particle -> accept all. 5609 # create the tuple associate to the decay mode 5610 child = [l.get('id') for l in amp['process'].get('legs') \ 5611 if l.get('state')] 5612 if not mother[0] > 0: 5613 child = [x if self._curr_model.get_particle(x)['self_antipart'] 5614 else -x for x in child] 5615 child.sort() 5616 child.insert(0, len(child)) 5617 #check if the decay is present or not: 5618 if tuple(child) not in list(decay_table.keys()): 5619 to_remove.append(amp) 5620 5621 def remove_amp(amps): 5622 for amp in amps[:]: 5623 if amp in to_remove: 5624 amps.remove(amp) 5625 if isinstance(amp, diagram_generation.DecayChainAmplitude): 5626 remove_amp(amp.get('decay_chains')) 5627 for decay in amp.get('decay_chains'): 5628 remove_amp(decay.get('amplitudes'))
5629 remove_amp(self._curr_amps) 5630 5631
5632 - def import_ufo_model(self, model_name):
5633 """ import the UFO model """ 5634 5635 self._curr_model = import_ufo.import_model(model_name)
5636
5637 - def process_model(self):
5638 """Set variables _particle_names and _couplings for tab 5639 completion, define multiparticles""" 5640 5641 # Set variables for autocomplete 5642 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\ 5643 if p.get('propagating')] + \ 5644 [p.get('antiname') for p in self._curr_model.get('particles') \ 5645 if p.get('propagating')] 5646 5647 self._couplings = list(set(sum([list(i.get('orders').keys()) for i in \ 5648 self._curr_model.get('interactions')], []))) 5649 5650 self.add_default_multiparticles()
5651 5652
5653 - def import_mg4_proc_card(self, filepath):
5654 """ read a V4 proc card, convert it and run it in mg5""" 5655 5656 # change the status of this line in the history -> pass in comment 5657 if self.history and self.history[-1].startswith('import proc_v4'): 5658 self.history[-1] = '#%s' % self.history[-1] 5659 5660 # read the proc_card.dat 5661 reader = files.read_from_file(filepath, import_v4.read_proc_card_v4) 5662 if not reader: 5663 raise self.InvalidCmd('\"%s\" is not a valid path' % filepath) 5664 5665 if self._mgme_dir: 5666 # Add comment to history 5667 self.exec_cmd("# Import the model %s" % reader.model, precmd=True) 5668 line = self.exec_cmd('import model_v4 %s -modelname' % \ 5669 (reader.model), precmd=True) 5670 else: 5671 logging.error('No MG_ME installation detected') 5672 return 5673 5674 5675 # Now that we have the model we can split the information 5676 lines = reader.extract_command_lines(self._curr_model) 5677 for line in lines: 5678 self.exec_cmd(line, precmd=True) 5679 5680 return
5681
5682 - def add_default_multiparticles(self):
5683 """ add default particle from file interface.multiparticles_default.txt 5684 """ 5685 5686 defined_multiparticles = list(self._multiparticles.keys()) 5687 removed_multiparticles = [] 5688 # First check if the defined multiparticles are allowed in the 5689 # new model 5690 5691 for key in list(self._multiparticles.keys()): 5692 try: 5693 for part in self._multiparticles[key]: 5694 self._curr_model.get('particle_dict')[part] 5695 except Exception: 5696 del self._multiparticles[key] 5697 defined_multiparticles.remove(key) 5698 removed_multiparticles.append(key) 5699 5700 # Now add default multiparticles 5701 for line in open(pjoin(MG5DIR, 'input', \ 5702 'multiparticles_default.txt')): 5703 if line.startswith('#'): 5704 continue 5705 try: 5706 if not self._curr_model['case_sensitive']: 5707 multipart_name = line.lower().split()[0] 5708 else: 5709 multipart_name = line.split()[0] 5710 if multipart_name not in self._multiparticles: 5711 #self.do_define(line) 5712 self.exec_cmd('define %s' % line, printcmd=False, precmd=True) 5713 except self.InvalidCmd as why: 5714 logger.warning('impossible to set default multiparticles %s because %s' % 5715 (line.split()[0],why)) 5716 if self.history[-1] == 'define %s' % line.strip(): 5717 self.history.pop(-1) 5718 else: 5719 misc.sprint([self.history[-1], 'define %s' % line.strip()]) 5720 5721 scheme = "old" 5722 for qcd_container in ['p', 'j']: 5723 if qcd_container not in self._multiparticles: 5724 continue 5725 multi = self._multiparticles[qcd_container] 5726 b = self._curr_model.get_particle(5) 5727 if not b: 5728 break 5729 5730 if 5 in multi: 5731 if b['mass'] != 'ZERO': 5732 multi.remove(5) 5733 multi.remove(-5) 5734 scheme = 4 5735 elif b['mass'] == 'ZERO': 5736 multi.append(5) 5737 multi.append(-5) 5738 scheme = 5 5739 5740 if scheme in [4,5]: 5741 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme) 5742 for container in ['p', 'j']: 5743 if container in defined_multiparticles: 5744 defined_multiparticles.remove(container) 5745 self.history.append("define p = %s # pass to %s flavors" % \ 5746 (' ' .join([repr(i) for i in self._multiparticles['p']]), 5747 scheme) 5748 ) 5749 self.history.append("define j = p") 5750 5751 5752 if defined_multiparticles: 5753 if 'all' in defined_multiparticles: 5754 defined_multiparticles.remove('all') 5755 logger.info("Kept definitions of multiparticles %s unchanged" % \ 5756 " / ".join(defined_multiparticles)) 5757 5758 for removed_part in removed_multiparticles: 5759 if removed_part in self._multiparticles: 5760 removed_multiparticles.remove(removed_part) 5761 5762 if removed_multiparticles: 5763 logger.info("Removed obsolete multiparticles %s" % \ 5764 " / ".join(removed_multiparticles)) 5765 5766 # add all tag 5767 line = [] 5768 for part in self._curr_model.get('particles'): 5769 line.append('%s %s' % (part.get('name'), part.get('antiname'))) 5770 line = 'all =' + ' '.join(line) 5771 self.do_define(line)
5772
5773 - def advanced_install(self, tool_to_install, 5774 HepToolsInstaller_web_address=None, 5775 additional_options=[]):
5776 """ Uses the HEPToolsInstaller.py script maintened online to install 5777 HEP tools with more complicated dependences. 5778 Additional options will be added to the list when calling HEPInstaller""" 5779 5780 # prevent border effects 5781 add_options = list(additional_options) 5782 5783 # Always refresh the installer if already present 5784 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')): 5785 if HepToolsInstaller_web_address is None: 5786 raise MadGraph5Error("The option 'HepToolsInstaller_web_address'"+\ 5787 " must be specified in function advanced_install"+\ 5788 " if the installers are not already downloaded.") 5789 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')): 5790 os.mkdir(pjoin(MG5DIR,'HEPTools')) 5791 elif not HepToolsInstaller_web_address is None: 5792 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5793 if not HepToolsInstaller_web_address is None: 5794 logger.info('Downloading the HEPToolInstaller at:\n %s'% 5795 HepToolsInstaller_web_address) 5796 # Guess if it is a local or web address 5797 if '//' in HepToolsInstaller_web_address: 5798 misc.wget(HepToolsInstaller_web_address, 5799 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'), 5800 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'), 5801 cwd=MG5DIR) 5802 else: 5803 # If it is a local tarball, then just copy it 5804 shutil.copyfile(HepToolsInstaller_web_address, 5805 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5806 5807 # Untar the file 5808 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'], 5809 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w')) 5810 5811 # Remove the tarball 5812 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5813 5814 5815 # FOR DEBUGGING ONLY, Take HEPToolsInstaller locally 5816 if '--local' in add_options: 5817 add_options.remove('--local') 5818 logger.warning('you are using a local installer. This is intended for debugging only!') 5819 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5820 shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir, 5821 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5822 5823 # Potential change in naming convention 5824 name_map = {'lhapdf6_py3': 'lhapdf6'} 5825 try: 5826 tool = name_map[tool_to_install] 5827 except: 5828 tool = tool_to_install 5829 5830 # Compiler options 5831 compiler_options = [] 5832 if self.options['cpp_compiler'] is not None: 5833 compiler_options.append('--cpp_compiler=%s'% 5834 self.options['cpp_compiler']) 5835 compiler_options.append('--cpp_standard_lib=%s'% 5836 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler'])) 5837 elif misc.which('g++'): 5838 compiler_options.append('--cpp_standard_lib=%s'% 5839 misc.detect_cpp_std_lib_dependence('g++')) 5840 else: 5841 compiler_options.append('--cpp_standard_lib=%s'% 5842 misc.detect_cpp_std_lib_dependence(None)) 5843 5844 if not self.options['fortran_compiler'] is None: 5845 compiler_options.append('--fortran_compiler=%s'% 5846 self.options['fortran_compiler']) 5847 5848 if 'heptools_install_dir' in self.options: 5849 prefix = self.options['heptools_install_dir'] 5850 config_file = '~/.mg5/mg5_configuration.txt' 5851 else: 5852 prefix = pjoin(MG5DIR, 'HEPTools') 5853 config_file = '' 5854 5855 # Add the path of pythia8 if known and the MG5 path 5856 if tool=='mg5amc_py8_interface': 5857 #add_options.append('--mg5_path=%s'%MG5DIR) 5858 # Warn about the soft dependency to gnuplot 5859 if misc.which('gnuplot') is None: 5860 logger.warning("==========") 5861 logger.warning("The optional dependency 'gnuplot' for the tool"+\ 5862 " 'mg5amc_py8_interface' was not found. We recommend that you"+\ 5863 " install it so as to be able to view the plots related to "+\ 5864 " merging with Pythia 8.") 5865 logger.warning("==========") 5866 if self.options['pythia8_path']: 5867 add_options.append( 5868 '--with_pythia8=%s'%self.options['pythia8_path']) 5869 5870 # Special rules for certain tools 5871 if tool=='madanalysis5': 5872 add_options.append('--mg5_path=%s'%MG5DIR) 5873 if not any(opt.startswith(('--with_fastjet', '--veto_fastjet')) for opt in add_options): 5874 fastjet_config = misc.which(self.options['fastjet']) 5875 if fastjet_config: 5876 add_options.append('--with_fastjet=%s'%fastjet_config) 5877 5878 if self.options['delphes_path'] and os.path.isdir( 5879 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))): 5880 add_options.append('--with_delphes3=%s'%\ 5881 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))) 5882 5883 if tool=='pythia8': 5884 # All what's below is to handle the lhapdf dependency of Pythia8 5885 lhapdf_config = misc.which(self.options['lhapdf']) 5886 lhapdf_version = None 5887 if lhapdf_config is None: 5888 lhapdf_version = None 5889 else: 5890 try: 5891 version = misc.Popen( 5892 [lhapdf_config,'--version'], stdout=subprocess.PIPE) 5893 lhapdf_version = int(version.stdout.read().decode()[0]) 5894 if lhapdf_version not in [5,6]: 5895 raise 5896 except: 5897 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+ 5898 " sure '%s --version ' runs properly."%lhapdf_config) 5899 5900 if lhapdf_version is None: 5901 answer = self.ask(question= 5902 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+ 5903 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >", 5904 default='y',text_format='33;32') 5905 if not answer.lower() in ['y','']: 5906 lhapdf_path = None 5907 else: 5908 self.advanced_install('lhapdf6', 5909 additional_options=add_options) 5910 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6') 5911 lhapdf_version = 6 5912 else: 5913 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\ 5914 lhapdf_config),os.path.pardir)) 5915 if lhapdf_version is None: 5916 logger.warning('You decided not to link the Pythia8 installation'+ 5917 ' to LHAPDF. Beware that only built-in PDF sets can be used then.') 5918 else: 5919 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version) 5920 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN') 5921 lhapdf_option = [] 5922 if lhapdf_version is None: 5923 lhapdf_option.append('--with_lhapdf6=OFF') 5924 lhapdf_option.append('--with_lhapdf5=OFF') 5925 elif lhapdf_version==5: 5926 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path) 5927 lhapdf_option.append('--with_lhapdf6=OFF') 5928 elif lhapdf_version==6: 5929 lhapdf_option.append('--with_lhapdf5=OFF') 5930 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path) 5931 # Make sure each otion in add_options appears only once 5932 add_options = list(set(add_options)) 5933 # And that the option '--force' is placed last. 5934 add_options = [opt for opt in add_options if opt!='--force']+\ 5935 (['--force'] if '--force' in add_options else []) 5936 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5937 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8', 5938 '--prefix=%s' % prefix] 5939 + lhapdf_option + compiler_options + add_options) 5940 else: 5941 logger.info('Now installing %s. Be patient...'%tool) 5942 # Make sure each otion in add_options appears only once 5943 add_options.append('--mg5_path=%s'%MG5DIR) 5944 add_options = list(set(add_options)) 5945 add_options.append('--mg5_path=%s'%MG5DIR) 5946 # And that the option '--force' is placed last. 5947 add_options = [opt for opt in add_options if opt!='--force']+\ 5948 (['--force'] if '--force' in add_options else []) 5949 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5950 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'% 5951 prefix] + compiler_options + add_options) 5952 5953 if return_code == 0: 5954 logger.info("%s successfully installed in %s."%( 5955 tool_to_install, prefix),'$MG:color:GREEN') 5956 5957 if tool=='madanalysis5': 5958 if not any(o.startswith(('--with_','--veto_','--update')) for o in add_options): 5959 logger.info(' To install recasting capabilities of madanalysis5 and/or', '$MG:BOLD') 5960 logger.info(' to allow delphes analysis at parton level.','$MG:BOLD') 5961 logger.info(' Please run \'install MadAnalysis5 --with_delphes --update\':', '$MG:BOLD') 5962 5963 elif return_code == 66: 5964 answer = self.ask(question= 5965 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, prefix)+ 5966 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >""" 5967 ,default='y',text_format='33;32') 5968 if not answer.lower() in ['y','']: 5969 logger.info("Installation of %s aborted."%tool_to_install, 5970 '$MG:color:GREEN') 5971 return 5972 else: 5973 return self.advanced_install(tool_to_install, 5974 additional_options=add_options+['--force']) 5975 else: 5976 if tool=='madanalysis5' and '--update' not in add_options and \ 5977 ('--no_MA5_further_install' not in add_options or 5978 '--no_root_in_MA5' in add_options): 5979 if not __debug__: 5980 logger.warning('Default installation of Madanalys5 failed.') 5981 logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.") 5982 logger.warning("This will however limit MA5 applicability for hadron-level analysis.") 5983 logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.") 5984 for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']: 5985 if option not in add_options: 5986 add_options.append(option) 5987 self.advanced_install('madanalysis5', 5988 HepToolsInstaller_web_address=HepToolsInstaller_web_address, 5989 additional_options=add_options) 5990 else: 5991 logger.critical("Default installation of Madanalys5 failed, we suggest you try again with the options '--no_MA5_further_install --no_root_in_MA5'.") 5992 raise self.InvalidCmd("Installation of %s failed."%tool_to_install) 5993 5994 # Post-installation treatment 5995 if tool == 'pythia8': 5996 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 5997 self.exec_cmd('save options %s pythia8_path' % config_file, printcmd=False, log=False) 5998 # Automatically re-install the mg5amc_py8_interface after a fresh 5999 # Pythia8 installation 6000 self.advanced_install('mg5amc_py8_interface', 6001 additional_options=add_options+['--force']) 6002 elif tool == 'lhapdf6': 6003 if six.PY3: 6004 self.options['lhapdf_py3'] = pjoin(prefix,'lhapdf6_py3','bin', 'lhapdf-config') 6005 self.exec_cmd('save options %s lhapdf_py3' % config_file) 6006 else: 6007 self.options['lhapdf_py2'] = pjoin(prefix,'lhapdf6','bin', 'lhapdf-config') 6008 self.exec_cmd('save options %s lhapdf_py2' % config_file) 6009 elif tool == 'lhapdf5': 6010 self.options['lhapdf'] = pjoin(prefix,'lhapdf5','bin', 'lhapdf-config') 6011 self.exec_cmd('save options %s lhapdf' % config_file, printcmd=False, log=False) 6012 elif tool == 'madanalysis5': 6013 self.options['madanalysis5_path'] = pjoin(prefix, 'madanalysis5','madanalysis5') 6014 self.exec_cmd('save options madanalysis5_path', printcmd=False, log=False) 6015 elif tool == 'mg5amc_py8_interface': 6016 # At this stage, pythia is guaranteed to be installed 6017 if self.options['pythia8_path'] in ['',None,'None']: 6018 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 6019 self.options['mg5amc_py8_interface_path'] = pjoin(prefix, 'MG5aMC_PY8_interface') 6020 self.exec_cmd('save options %s mg5amc_py8_interface_path' % config_file, 6021 printcmd=False, log=False) 6022 elif tool == 'collier': 6023 self.options['collier'] = pjoin(prefix,'lib') 6024 self.exec_cmd('save options %s collier' % config_file, printcmd=False, log=False) 6025 elif tool == 'ninja': 6026 if not misc.get_ninja_quad_prec_support(pjoin( 6027 prefix,'ninja','lib')): 6028 logger.warning( 6029 """Successful installation of Ninja, but without support for quadruple precision 6030 arithmetics. If you want to enable this (hence improving the treatment of numerically 6031 unstable points in the loop matrix elements) you can try to reinstall Ninja with: 6032 MG5aMC>install ninja 6033 After having made sure to have selected a C++ compiler in the 'cpp' option of 6034 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""") 6035 self.options['ninja'] = pjoin(prefix,'lib') 6036 self.exec_cmd('save options %s ninja' % config_file, printcmd=False, log=False) 6037 elif '%s_path' % tool in self.options: 6038 self.options['%s_path' % tool] = pjoin(prefix, tool) 6039 self.exec_cmd('save options %s %s_path' % (config_file,tool), printcmd=False, log=False) 6040 6041 # Now warn the user if he didn't add HEPTools first in his environment 6042 # variables. 6043 path_to_be_set = [] 6044 if sys.platform == "darwin": 6045 library_variables = ["DYLD_LIBRARY_PATH"] 6046 else: 6047 library_variables = ["LD_LIBRARY_PATH"] 6048 for variable in library_variables: 6049 if (variable not in os.environ) or \ 6050 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\ 6051 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6052 path_to_be_set.append((variable, 6053 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib')))) 6054 for variable in ["PATH"]: 6055 if (variable not in os.environ) or \ 6056 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\ 6057 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6058 path_to_be_set.append((variable, 6059 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin')))) 6060 if (variable not in os.environ) or \ 6061 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\ 6062 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6063 path_to_be_set.append((variable, 6064 os.path.abspath(pjoin(MG5DIR,'HEPTools','include')))) 6065 6066 if len(path_to_be_set)>0: 6067 shell_type = misc.get_shell_type() 6068 if shell_type in ['bash',None]: 6069 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.bashrc"%\ 6070 (r'\n'.join('export %s=%s%s'% 6071 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 6072 elif shell_type=='tcsh': 6073 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.cshrc"%\ 6074 (r'\n'.join('setenv %s %s%s'% 6075 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 6076 6077 logger.debug("==========") 6078 logger.debug("We recommend that you add to the following paths"+\ 6079 " to your environment variables, so that you are guaranteed that"+\ 6080 " at runtime, MG5_aMC will use the tools you have just installed"+\ 6081 " and not some other versions installed elsewhere on your system.\n"+\ 6082 "You can do so by running the following command in your terminal:" 6083 "\n %s"%modification_line) 6084 logger.debug("==========") 6085 6086 # Return true for successful installation 6087 return True
6088 6089 install_plugin = ['maddm', 'maddump', 'MadSTR'] 6090 install_ad = {'pythia-pgs':['arXiv:0603175'], 6091 'Delphes':['arXiv:1307.6346'], 6092 'Delphes2':['arXiv:0903.2225'], 6093 'SysCalc':['arXiv:1801.08401'], 6094 'Golem95':['arXiv:0807.0605'], 6095 'QCDLoop':['arXiv:0712.1851'], 6096 'pythia8':['arXiv:1410.3012'], 6097 'lhapdf6':['arXiv:1412.7420'], 6098 'lhapdf5':['arXiv:0605240'], 6099 'hepmc':['CPC 134 (2001) 41-46'], 6100 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'], 6101 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'], 6102 'MadAnalysis5':['arXiv:1206.1599'], 6103 'MadAnalysis':['arXiv:1206.1599'], 6104 'collier':['arXiv:1604.06792'], 6105 'oneloop':['arXiv:1007.4716'], 6106 'maddm':['arXiv:1804.00444'], 6107 'maddump':['arXiv:1812.06771'], 6108 'MadSTR':['arXiv:1612.00440']} 6109 6110 install_server = ['http://madgraph.phys.ucl.ac.be/package_info.dat', 6111 'http://madgraph.physics.illinois.edu/package_info.dat'] 6112 install_name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes', 6113 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs', 6114 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'madanalysis5', 6115 'MadAnalysis4':'MadAnalysis', 6116 'SysCalc':'SysCalc', 'Golem95': 'golem95', 6117 'lhapdf6' : 'lhapdf6' if six.PY2 else 'lhapdf6_py3', 6118 'QCDLoop':'QCDLoop','MadAnalysis5':'madanalysis5', 6119 'maddm':'maddm' 6120 } 6121
6122 - def do_install(self, line, paths=None, additional_options=[]):
6123 """Install optional package from the MG suite. 6124 The argument 'additional_options' will be passed to the advanced_install 6125 functions. If it contains the option '--force', then the advanced_install 6126 function will overwrite any existing installation of the tool without 6127 warnings. 6128 """ 6129 6130 # Make sure to avoid any border effect on custom_additional_options 6131 add_options = list(additional_options) 6132 6133 args = self.split_arg(line) 6134 #check the validity of the arguments 6135 install_options = self.check_install(args) 6136 6137 if sys.platform == "darwin": 6138 program = "curl" 6139 else: 6140 program = "wget" 6141 6142 # special command for auto-update 6143 if args[0] == 'update': 6144 self.install_update(['update']+install_options['update_options'],wget=program) 6145 return 6146 elif args[0] == 'looptools': 6147 self.install_reduction_library(force=True) 6148 return 6149 6150 6151 plugin = self.install_plugin 6152 6153 advertisements = self.install_ad 6154 6155 6156 if args[0] in advertisements: 6157 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6158 # logger.info('{:^80}'.format("You are installing '%s', please cite ref(s):"%args[0]), '$MG:BOLD') 6159 # logger.info('{:^80}'.format(', '.join(advertisements[args[0]])), '$MG:color:GREEN') 6160 # logger.info('{:^80}'.format("when using results produced with this tool."), '$MG:BOLD') 6161 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6162 logger.info(" You are installing '%s', please cite ref(s): \033[92m%s\033[0m. " % (args[0], ', '.join(advertisements[args[0]])), '$MG:BOLD') 6163 6164 source = None 6165 # Load file with path of the different program: 6166 import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error 6167 if paths: 6168 path = paths 6169 else: 6170 path = {} 6171 6172 data_path = self.install_server 6173 6174 # Force here to choose one particular server 6175 if any(a.startswith('--source=') for a in args): 6176 source = [a[9:] for a in args if a.startswith('--source=')][-1] 6177 if source == 'uiuc': 6178 r = [1] 6179 elif source == 'ucl': 6180 r = [0] 6181 else: 6182 if source[-1].isdigit() or source[-1] == '/': 6183 source += '/package_info.dat' 6184 data_path.append(source) 6185 r = [2] 6186 else: 6187 r = random.randint(0,1) 6188 r = [r, (1-r)] 6189 if 'MG5aMC_WWW' in os.environ and os.environ['MG5aMC_WWW']: 6190 data_path.append(os.environ['MG5aMC_WWW']+'/package_info.dat') 6191 r.insert(0, 2) 6192 6193 6194 6195 for index in r: 6196 cluster_path = data_path[index] 6197 try: 6198 data = six.moves.urllib.request.urlopen(cluster_path) 6199 except Exception as error: 6200 misc.sprint(str(error), cluster_path) 6201 continue 6202 if data.getcode() != 200: 6203 continue 6204 6205 break 6206 6207 else: 6208 raise MadGraph5Error('''Impossible to connect any of us servers. 6209 Please check your internet connection or retry later''') 6210 for wwwline in data: 6211 split = wwwline.decode().split() 6212 if len(split)!=2: 6213 if '--source' not in line: 6214 source = {0:'uiuc',1:'ucl'}[index] 6215 return self.do_install(line+' --source='+source, paths=paths, additional_options=additional_options) 6216 path[split[0]] = split[1] 6217 6218 ################################################################################ 6219 # TEMPORARY HACK WHERE WE ADD ENTRIES TO WHAT WILL BE EVENTUALLY ON THE WEB 6220 ################################################################################ 6221 # path['XXX'] = 'YYY' 6222 ################################################################################ 6223 6224 if args[0] == 'Delphes': 6225 args[0] = 'Delphes3' 6226 6227 6228 try: 6229 name = self.install_name 6230 name = name[args[0]] 6231 except KeyError: 6232 name = args[0] 6233 if args[0] == 'MadAnalysis4': 6234 args[0] = 'MadAnalysis' 6235 elif args[0] in ['madstr', 'madSTR']: 6236 args[0] = 'MadSTR' 6237 name = 'MadSTR' 6238 6239 if args[0] in self._advanced_install_opts: 6240 # Now launch the advanced installation of the tool args[0] 6241 # path['HEPToolsInstaller'] is the online adress where to downlaod 6242 # the installers if necessary. 6243 # Specify the path of the MG5_aMC_interface 6244 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \ 6245 'MG5aMC_PY8_interface' in path else 'NA' 6246 add_options.append('--mg5amc_py8_interface_tarball=%s'%\ 6247 MG5aMC_PY8_interface_path) 6248 add_options.extend(install_options['options_for_HEPToolsInstaller']) 6249 if not any(opt.startswith('--logging=') for opt in add_options): 6250 add_options.append('--logging=%d' % logger.level) 6251 6252 6253 return self.advanced_install(name, path['HEPToolsInstaller'], 6254 additional_options = add_options) 6255 6256 6257 if args[0] == 'Delphes': 6258 args[0] = 'Delphes3' 6259 6260 6261 #check outdated install 6262 substitution={'Delphes2':'Delphes','pythia-pgs':'pythia8'} 6263 if args[0] in substitution: 6264 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\ 6265 " You should consider installing and using %s, with:\n"%substitution[args[0]]+ 6266 " > install %s"%substitution[args[0]]) 6267 6268 try: 6269 os.system('rm -rf %s' % pjoin(MG5DIR, name)) 6270 except Exception: 6271 pass 6272 6273 if args[0] not in path: 6274 if not source: 6275 if index ==1: 6276 othersource = 'ucl' 6277 else: 6278 othersource = 'uiuc' 6279 # try with the mirror 6280 misc.sprint('try other mirror', othersource, ' '.join(args)) 6281 return self.do_install('%s --source=%s' % (' '.join(args), othersource), 6282 paths, additional_options) 6283 else: 6284 if 'xxx' in advertisements[name][0]: 6285 logger.warning("Program not yet released. Please try later") 6286 else: 6287 raise Exception("Online server are corrupted. No tarball available for %s" % name) 6288 return 6289 6290 # Load that path 6291 logger.info('Downloading %s' % path[args[0]]) 6292 misc.wget(path[args[0]], '%s.tgz' % name, cwd=MG5DIR) 6293 6294 # Untar the file 6295 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6296 stdout=open(os.devnull, 'w')) 6297 6298 if returncode: 6299 raise MadGraph5Error('Fail to download correctly the File. Stop') 6300 6301 6302 # Check that the directory has the correct name 6303 if not os.path.exists(pjoin(MG5DIR, name)): 6304 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith( 6305 name.lower()) and not n.endswith('gz')] 6306 if not created_name: 6307 raise MadGraph5Error('The file was not loaded correctly. Stop') 6308 else: 6309 created_name = created_name[0] 6310 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name)) 6311 6312 if hasattr(self, 'post_install_%s' %name): 6313 return getattr(self, 'post_install_%s' %name)() 6314 6315 logger.info('compile %s. This might take a while.' % name) 6316 6317 # Modify Makefile for pythia-pgs on Mac 64 bit 6318 if args[0] == "pythia-pgs" and sys.maxsize > 2**32: 6319 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 6320 text = open(path).read() 6321 text = text.replace('MBITS=32','MBITS=64') 6322 open(path, 'w').writelines(text) 6323 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')): 6324 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')) 6325 6326 make_flags = [] #flags for the compilation 6327 # Compile the file 6328 # Check for F77 compiler 6329 if 'FC' not in os.environ or not os.environ['FC']: 6330 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None': 6331 compiler = self.options['fortran_compiler'] 6332 elif misc.which('gfortran'): 6333 compiler = 'gfortran' 6334 elif misc.which('g77'): 6335 compiler = 'g77' 6336 else: 6337 raise self.InvalidCmd('Require g77 or Gfortran compiler') 6338 6339 path = None 6340 base_compiler= ['FC=g77','FC=gfortran'] 6341 if args[0] == "pythia-pgs": 6342 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 6343 elif args[0] == 'MadAnalysis': 6344 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile') 6345 if path: 6346 text = open(path).read() 6347 for base in base_compiler: 6348 text = text.replace(base,'FC=%s' % compiler) 6349 open(path, 'w').writelines(text) 6350 os.environ['FC'] = compiler 6351 6352 # For Golem95, use autotools. 6353 if name == 'golem95': 6354 # Run the configure script 6355 ld_path = misc.Popen(['./configure', 6356 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']], 6357 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0].decode() 6358 6359 6360 # For QCDLoop, use autotools. 6361 if name == 'QCDLoop': 6362 # Run the configure script 6363 ld_path = misc.Popen(['./configure', 6364 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'], 6365 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 6366 stdout=subprocess.PIPE).communicate()[0].decode() 6367 6368 # For Delphes edit the makefile to add the proper link to correct library 6369 if args[0] == 'Delphes3': 6370 #change in the makefile 6371 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) 6372 # to 6373 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,/Applications/root_v6.04.08/lib/ 6374 rootsys = os.environ['ROOTSYS'] 6375 text = open(pjoin(MG5DIR, 'Delphes','Makefile')).read() 6376 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)', 6377 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys) 6378 open(pjoin(MG5DIR, 'Delphes','Makefile'),'w').write(text) 6379 6380 # For SysCalc link to lhapdf 6381 if name == 'SysCalc': 6382 if self.options['lhapdf']: 6383 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'], 6384 stdout=subprocess.PIPE).communicate()[0].decode() 6385 ld_path = ld_path.replace('\n','') 6386 if 'LD_LIBRARY_PATH' not in os.environ: 6387 os.environ['LD_LIBRARY_PATH'] = ld_path 6388 elif not os.environ['LD_LIBRARY_PATH']: 6389 os.environ['LD_LIBRARY_PATH'] = ld_path 6390 elif ld_path not in os.environ['LD_LIBRARY_PATH']: 6391 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path 6392 if self.options['lhapdf'] != 'lhapdf-config': 6393 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']): 6394 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH']) 6395 else: 6396 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6') 6397 if self.options['cpp_compiler']: 6398 make_flags.append('CXX=%s' % self.options['cpp_compiler']) 6399 6400 6401 if name in plugin: 6402 logger.info('no compilation needed for plugin. Loading plugin information') 6403 try: 6404 shutil.rmtree(pjoin(MG5DIR, 'PLUGIN', name)) 6405 except Exception: 6406 pass 6407 shutil.move(pjoin(os.path.join(MG5DIR, name)), os.path.join(MG5DIR, 'PLUGIN', name)) 6408 # read the __init__.py to check if we need to add a new executable 6409 try: 6410 __import__('PLUGIN.%s' % name, globals(), locals(), [], -1) 6411 plugin = sys.modules['PLUGIN.%s' % name] 6412 new_interface = plugin.new_interface 6413 new_output = plugin.new_output 6414 latest_validated_version = plugin.latest_validated_version 6415 minimal_mg5amcnlo_version = plugin.minimal_mg5amcnlo_version 6416 maximal_mg5amcnlo_version = plugin.maximal_mg5amcnlo_version 6417 except Exception as error: 6418 raise Exception('Plugin %s fail to be loaded. Please contact the author of the PLUGIN\n Error %s' % (name, error)) 6419 6420 logger.info('Plugin %s correctly interfaced. Latest official validition for MG5aMC version %s.' % (name, '.'.join(repr(i) for i in latest_validated_version))) 6421 if new_interface: 6422 ff = open(pjoin(MG5DIR, 'bin', '%s.py' % name) , 'w') 6423 if __debug__: 6424 text = '''#! /usr/bin/env python 6425 import os 6426 import sys 6427 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 6428 exe_path = os.path.join(root_path,'bin','mg5_aMC') 6429 sys.argv.pop(0) 6430 os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 6431 '''.format(name) 6432 else: 6433 text = '''#! /usr/bin/env python 6434 import os 6435 import sys 6436 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 6437 exe_path = os.path.join(root_path,'bin','mg5_aMC') 6438 sys.argv.pop(0) 6439 os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 6440 '''.format(name) 6441 ff.write(text) 6442 ff.close() 6443 import stat 6444 os.chmod(pjoin(MG5DIR, 'bin', '%s.py' % name), stat.S_IRWXU) 6445 logger.info('To use this module, you need to quit MG5aMC and run the executable bin/%s.py' % name) 6446 status=0 6447 6448 elif logger.level <= logging.INFO: 6449 devnull = open(os.devnull,'w') 6450 try: 6451 misc.call(['make', 'clean'], stdout=devnull, stderr=-2) 6452 except Exception: 6453 pass 6454 if name == 'pythia-pgs': 6455 #SLC6 needs to have this first (don't ask why) 6456 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6457 if name in ['golem95','QCDLoop']: 6458 status = misc.call(['make','install'], 6459 cwd = os.path.join(MG5DIR, name)) 6460 else: 6461 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name)) 6462 devnull.close() 6463 else: 6464 try: 6465 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6466 except Exception: 6467 pass 6468 if name == 'pythia-pgs': 6469 #SLC6 needs to have this first (don't ask why) 6470 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6471 if name in ['golem95','QCDLoop']: 6472 status = misc.compile(['install'], mode='', 6473 cwd = os.path.join(MG5DIR, name)) 6474 else: 6475 status = self.compile(make_flags, mode='', 6476 cwd = os.path.join(MG5DIR, name)) 6477 6478 if not status: 6479 logger.info('Installation succeeded') 6480 else: 6481 # For pythia-pgs check when removing the "-fno-second-underscore" flag 6482 if name == 'pythia-pgs': 6483 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio', 6484 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch'] 6485 for f in to_comment: 6486 f = pjoin(MG5DIR, name, *f.split('/')) 6487 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l) 6488 fsock = open(f,'w').write(text) 6489 try: 6490 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6491 except Exception: 6492 pass 6493 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name)) 6494 if not status: 6495 logger.info('Compilation succeeded') 6496 else: 6497 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.') 6498 6499 6500 # Special treatment for TD/Ghostscript program (require by MadAnalysis) 6501 if args[0] == 'MadAnalysis': 6502 try: 6503 os.system('rm -rf td') 6504 os.mkdir(pjoin(MG5DIR, 'td')) 6505 except Exception as error: 6506 print(error) 6507 pass 6508 6509 if sys.platform == "darwin": 6510 logger.info('Downloading TD for Mac') 6511 target = 'https://home.fnal.gov/~parke/TD/td_mac_intel64.tar.gz' 6512 misc.wget(target, 'td.tgz', cwd=pjoin(MG5DIR,'td')) 6513 misc.call(['tar', '-xzpvf', 'td.tgz'], 6514 cwd=pjoin(MG5DIR,'td')) 6515 files.mv(MG5DIR + '/td/td_intel_mac64',MG5DIR+'/td/td') 6516 else: 6517 if sys.maxsize > 2**32: 6518 logger.info('Downloading TD for Linux 64 bit') 6519 target = 'https://home.fnal.gov/~parke/TD/td_linux_64bit.tar.gz' 6520 #logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer. 6521 #In 99% of the case, this is perfectly fine. If you do not have plot, please follow 6522 #instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''') 6523 else: 6524 logger.info('Downloading TD for Linux 32 bit') 6525 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td' 6526 misc.wget(target, 'td', cwd=pjoin(MG5DIR,'td')) 6527 os.chmod(pjoin(MG5DIR,'td','td'), 0o775) 6528 self.options['td_path'] = pjoin(MG5DIR,'td') 6529 6530 if not misc.which('gs'): 6531 logger.warning('''gosthscript not install on your system. This is not required to run MA. 6532 but this prevent to create jpg files and therefore to have the plots in the html output.''') 6533 if sys.platform == "darwin": 6534 logger.warning('''You can download this program at the following link: 6535 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''') 6536 6537 if args[0] == 'Delphes2': 6538 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read() 6539 data = data.replace('data/', 'DELPHESDIR/data/') 6540 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w') 6541 out.write(data) 6542 if args[0] == 'Delphes3': 6543 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')): 6544 card_dir = pjoin(MG5DIR, 'Delphes','cards') 6545 else: 6546 card_dir = pjoin(MG5DIR, 'Delphes','examples') 6547 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6548 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat')) 6549 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6550 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat')) 6551 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'), 6552 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat')) 6553 6554 if not self.options['pythia-pgs_path'] and not self.options['pythia8_path']: 6555 logger.warning("We noticed that no parton-shower module are installed/linked. \n In order to use Delphes from MG5aMC please install/link pythia8.") 6556 6557 #reset the position of the executable 6558 options_name = {'Delphes': 'delphes_path', 6559 'Delphes2': 'delphes_path', 6560 'Delphes3': 'delphes_path', 6561 'ExRootAnalysis': 'exrootanalysis_path', 6562 'MadAnalysis': 'madanalysis_path', 6563 'SysCalc': 'syscalc_path', 6564 'pythia-pgs':'pythia-pgs_path', 6565 'Golem95': 'golem'} 6566 6567 if args[0] in options_name: 6568 opt = options_name[args[0]] 6569 if opt=='golem': 6570 self.options[opt] = pjoin(MG5DIR,name,'lib') 6571 self.exec_cmd('save options %s' % opt, printcmd=False) 6572 elif self.options[opt] != self.options_configuration[opt]: 6573 self.options[opt] = self.options_configuration[opt] 6574 self.exec_cmd('save options %s' % opt, printcmd=False)
6575 6576 6577
6578 - def install_update(self, args, wget):
6579 """ check if the current version of mg5 is up-to-date. 6580 and allow user to install the latest version of MG5 """ 6581 6582 def apply_patch(filetext): 6583 """function to apply the patch""" 6584 text = filetext.read() 6585 6586 pattern = re.compile(r'''=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6587 #=== renamed directory 'Template' => 'Template/LO' 6588 for orig, new in pattern.findall(text): 6589 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP')) 6590 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6591 for i, name in enumerate(full_path): 6592 path = os.path.sep.join(full_path[:i+1]) 6593 if path and not os.path.isdir(path): 6594 os.mkdir(path) 6595 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new)) 6596 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP')) 6597 # track rename since patch fail to apply those correctly. 6598 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6599 #=== renamed file 'Template/SubProcesses/addmothers.f' => 'madgraph/iolibs/template_files/addmothers.f' 6600 for orig, new in pattern.findall(text): 6601 print('move %s to %s' % (orig, new)) 6602 try: 6603 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6604 except IOError: 6605 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6606 for i, name in enumerate(full_path): 6607 path = os.path.sep.join(full_path[:i+1]) 6608 if path and not os.path.isdir(path): 6609 os.mkdir(path) 6610 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6611 # track remove/re-added file: 6612 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M) 6613 all_add = pattern.findall(text) 6614 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6615 #all_rm = pattern.findall(text) 6616 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S) 6617 print('this step can take a few minuts. please be patient') 6618 all_rm_add = pattern.findall(text) 6619 #=== added file 'tests/input_files/full_sm/interactions.dat' 6620 for new in all_add: 6621 if new in all_rm_add: 6622 continue 6623 if os.path.isfile(pjoin(MG5DIR, new)): 6624 os.remove(pjoin(MG5DIR, new)) 6625 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6626 #=== removed file 'tests/input_files/full_sm/interactions.dat' 6627 #for old in pattern.findall(text): 6628 # if not os.path.isfile(pjoin(MG5DIR, old)): 6629 # full_path = os.path.dirname(pjoin(MG5DIR, old)).split('/') 6630 # for i, _ in enumerate(full_path): 6631 # path = os.path.sep.join(full_path[:i+1]) 6632 # if path and not os.path.isdir(path): 6633 # os.mkdir(path) 6634 # subprocess.call(['touch', pjoin(MG5DIR, old)]) 6635 6636 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE, 6637 cwd=MG5DIR) 6638 p.communicate(text.encode()) 6639 6640 # check file which are not move 6641 #=== modified file 'Template/LO/Cards/run_card.dat' 6642 #--- old/Template/Cards/run_card.dat 2012-12-06 10:01:04 +0000 6643 #+++ new/Template/LO/Cards/run_card.dat 2013-12-09 02:35:59 +0000 6644 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6645 for match in pattern.findall(text): 6646 new = pjoin(MG5DIR, match[0]) 6647 old = pjoin(MG5DIR, match[1]) 6648 if new == old: 6649 continue 6650 elif os.path.exists(old): 6651 if not os.path.exists(os.path.dirname(new)): 6652 split = new.split('/') 6653 for i in range(1,len(split)): 6654 path = '/'.join(split[:i]) 6655 if not os.path.exists(path): 6656 print('mkdir', path) 6657 os.mkdir(path) 6658 files.cp(old,new) 6659 #=== renamed file 'Template/bin/internal/run_delphes' => 'Template/Common/bin/internal/run_delphes' 6660 #--- old/Template/bin/internal/run_delphes 2011-12-09 07:28:10 +0000 6661 #+++ new/Template/Common/bin/internal/run_delphes 2012-10-23 02:41:37 +0000 6662 #pattern=re.compile('''=== renamed file \'(?P<old>[^\']*)\' => \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P=old)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6663 #for match in pattern.findall(text): 6664 # old = pjoin(MG5DIR, match[0]) 6665 # new = pjoin(MG5DIR, match[1]) 6666 # if new == old: 6667 # continue 6668 # elif os.path.exists(old): 6669 # if not os.path.exists(os.path.dirname(new)): 6670 # split = new.split('/') 6671 # for i in range(1,len(split)): 6672 # path = '/'.join(split[:i]) 6673 # if not os.path.exists(path): 6674 # print 'mkdir', path 6675 # os.mkdir(path) 6676 # files.cp(old,new) 6677 6678 # check that all files in bin directory are executable 6679 for path in misc.glob('*', pjoin(MG5DIR, 'bin')): 6680 misc.call(['chmod', '+x', path]) 6681 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')): 6682 misc.call(['chmod', '+x', path]) 6683 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')): 6684 misc.call(['chmod', '+x', path]) 6685 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')): 6686 misc.call(['chmod', '+x', path]) 6687 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')): 6688 misc.call(['chmod', '+x', path]) 6689 6690 #add empty files/directory 6691 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M) 6692 for match in pattern.findall(text): 6693 if match[0] == 'file': 6694 new = os.path.dirname(pjoin(MG5DIR, match[1])) 6695 else: 6696 new = pjoin(MG5DIR, match[1]) 6697 if not os.path.exists(new): 6698 split = new.split('/') 6699 for i in range(1,len(split)+1): 6700 path = '/'.join(split[:i]) 6701 if path and not os.path.exists(path): 6702 print('mkdir', path) 6703 os.mkdir(path) 6704 if match[0] == 'file': 6705 print('touch ', pjoin(MG5DIR, match[1])) 6706 misc.call(['touch', pjoin(MG5DIR, match[1])]) 6707 # add new symlink 6708 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M) 6709 for new, old in pattern.findall(text): 6710 if not os.path.exists(pjoin(MG5DIR, new)): 6711 files.ln(pjoin(MG5DIR,old), os.path.dirname(pjoin(MG5DIR,new)), os.path.basename(new)) 6712 6713 # Re-compile CutTools and IREGI 6714 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')): 6715 misc.compile(arg=['-j1'],cwd=pjoin(MG5DIR,'vendor','CutTools'),nb_core=1) 6716 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')): 6717 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src')) 6718 6719 # check if it need to download binary: 6720 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M) 6721 if pattern.search(text): 6722 return True 6723 else: 6724 return False
6725 6726 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')] 6727 if mode: 6728 mode = mode[-1] 6729 else: 6730 mode = "userrequest" 6731 force = any([arg=='-f' for arg in args]) 6732 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')] 6733 if timeout: 6734 try: 6735 timeout = int(timeout[-1]) 6736 except ValueError: 6737 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1]) 6738 else: 6739 timeout = self.options['timeout'] 6740 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')] 6741 6742 if input_path: 6743 fsock = open(input_path[0]) 6744 need_binary = apply_patch(fsock) 6745 logger.info('manual patch apply. Please test your version.') 6746 if need_binary: 6747 logger.warning('Note that some files need to be loaded separately!') 6748 sys.exit(0) 6749 6750 options = ['y','n','on_exit'] 6751 if mode == 'mg5_start': 6752 timeout = 2 6753 default = 'n' 6754 update_delay = self.options['auto_update'] * 24 * 3600 6755 if update_delay == 0: 6756 return 6757 elif mode == 'mg5_end': 6758 timeout = 5 6759 default = 'n' 6760 update_delay = self.options['auto_update'] * 24 * 3600 6761 if update_delay == 0: 6762 return 6763 options.remove('on_exit') 6764 elif mode == "userrequest": 6765 default = 'y' 6766 update_delay = 0 6767 else: 6768 raise self.InvalidCmd('Unknown mode for command install update') 6769 6770 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')) or \ 6771 os.path.exists(os.path.join(MG5DIR,'.bzr')): 6772 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are: 6773 1) This version was loaded via bazaar (use bzr pull to update instead). 6774 2) This version is a beta release of MG5.""" 6775 if mode == 'userrequest': 6776 raise self.ConfigurationError(error_text) 6777 return 6778 6779 if not misc.which('patch'): 6780 error_text = """Not able to find program \'patch\'. Please reload a clean version 6781 or install that program and retry.""" 6782 if mode == 'userrequest': 6783 raise self.ConfigurationError(error_text) 6784 return 6785 6786 # read the data present in .autoupdate 6787 data = {} 6788 for line in open(os.path.join(MG5DIR,'input','.autoupdate')): 6789 if not line.strip(): 6790 continue 6791 sline = line.split() 6792 data[sline[0]] = int(sline[1]) 6793 6794 #check validity of the file 6795 if 'version_nb' not in data: 6796 if mode == 'userrequest': 6797 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)' 6798 raise self.ConfigurationError(error_text) 6799 return 6800 elif 'last_check' not in data: 6801 data['last_check'] = time.time() 6802 6803 #check if we need to update. 6804 if time.time() - data['last_check'] < update_delay: 6805 return 6806 6807 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout) 6808 class TimeOutError(Exception): pass 6809 6810 def handle_alarm(signum, frame): 6811 raise TimeOutError 6812 6813 signal.signal(signal.SIGALRM, handle_alarm) 6814 signal.alarm(timeout) 6815 to_update = 0 6816 try: 6817 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/mg5amc_build_nb') 6818 signal.alarm(0) 6819 web_version = int(filetext.read().strip()) 6820 except (TimeOutError, ValueError, IOError): 6821 signal.alarm(0) 6822 print('failed to connect server') 6823 if mode == 'mg5_end': 6824 # wait 24h before next check 6825 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6826 fsock.write("version_nb %s\n" % data['version_nb']) 6827 fsock.write("last_check %s\n" % \ 6828 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1)) 6829 fsock.close() 6830 return 6831 6832 if web_version == data['version_nb']: 6833 logger.info('No new version of MG5 available') 6834 # update .autoupdate to prevent a too close check 6835 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6836 fsock.write("version_nb %s\n" % data['version_nb']) 6837 fsock.write("last_check %s\n" % int(time.time())) 6838 fsock.close() 6839 return 6840 elif data['version_nb'] > web_version: 6841 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version)) 6842 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6843 fsock.write("version_nb %s\n" % data['version_nb']) 6844 fsock.write("last_check %s\n" % int(time.time())) 6845 fsock.close() 6846 return 6847 else: 6848 if not force: 6849 answer = self.ask('New Version of MG5 available! Do you want to update your current version?', 6850 default, options) 6851 else: 6852 answer = default 6853 6854 6855 if answer == 'y': 6856 logger.info('start updating code') 6857 fail = 0 6858 for i in range(data['version_nb'], web_version): 6859 try: 6860 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1)) 6861 except Exception: 6862 print('fail to load patch to build #%s' % (i+1)) 6863 fail = i 6864 break 6865 need_binary = apply_patch(filetext) 6866 if need_binary: 6867 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1) 6868 name = "extra_file%i" % (i+1) 6869 misc.wget(path, '%s.tgz' % name, cwd=MG5DIR) 6870 # Untar the file 6871 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6872 stdout=open(os.devnull, 'w')) 6873 6874 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6875 if not fail: 6876 fsock.write("version_nb %s\n" % web_version) 6877 else: 6878 fsock.write("version_nb %s\n" % fail) 6879 fsock.write("last_check %s\n" % int(time.time())) 6880 fsock.close() 6881 logger.info('Refreshing installation of MG5aMC_PY8_interface.') 6882 self.do_install('mg5amc_py8_interface',additional_options=['--force']) 6883 logger.info('Checking current version. (type ctrl-c to bypass the check)') 6884 subprocess.call([os.path.join('tests','test_manager.py')], 6885 cwd=MG5DIR) 6886 print('new version installed, please relaunch mg5') 6887 try: 6888 os.remove(pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6889 shutil.copy(pjoin(MG5DIR, 'Template','LO','Source','.make_opts'), 6890 pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6891 except: 6892 pass 6893 sys.exit(0) 6894 elif answer == 'n': 6895 # prevent for a future check 6896 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6897 fsock.write("version_nb %s\n" % data['version_nb']) 6898 fsock.write("last_check %s\n" % int(time.time())) 6899 fsock.close() 6900 logger.info('Update bypassed.') 6901 logger.info('The next check for a new version will be performed in %s days' \ 6902 % abs(self.options['auto_update'])) 6903 logger.info('In order to change this delay. Enter the command:') 6904 logger.info('set auto_update X') 6905 logger.info('Putting X to zero will prevent this check at anytime.') 6906 logger.info('You can upgrade your version at any time by typing:') 6907 logger.info('install update') 6908 else: #answer is on_exit 6909 #ensure that the test will be done on exit 6910 #Do not use the set command here!! 6911 self.options['auto_update'] = -1 * self.options['auto_update'] 6912 6913 6914
6915 - def set_configuration(self, config_path=None, final=True):
6916 """ assign all configuration variable from file 6917 ./input/mg5_configuration.txt. assign to default if not define """ 6918 6919 if not self.options: 6920 self.options = dict(self.options_configuration) 6921 self.options.update(self.options_madgraph) 6922 self.options.update(self.options_madevent) 6923 6924 if not config_path: 6925 if 'MADGRAPH_BASE' in os.environ: 6926 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 6927 self.set_configuration(config_path, final=False) 6928 if 'HOME' in os.environ: 6929 config_path = pjoin(os.environ['HOME'],'.mg5', 6930 'mg5_configuration.txt') 6931 if os.path.exists(config_path): 6932 self.set_configuration(config_path, final=False) 6933 config_path = os.path.relpath(pjoin(MG5DIR,'input', 6934 'mg5_configuration.txt')) 6935 return self.set_configuration(config_path, final) 6936 6937 if not os.path.exists(config_path): 6938 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path) 6939 config_file = open(config_path) 6940 6941 # read the file and extract information 6942 logger.info('load MG5 configuration from %s ' % config_file.name) 6943 for line in config_file: 6944 if '#' in line: 6945 line = line.split('#',1)[0] 6946 line = line.replace('\n','').replace('\r\n','') 6947 try: 6948 name, value = line.split('=') 6949 except ValueError: 6950 pass 6951 else: 6952 name = name.strip() 6953 value = value.strip() 6954 if name != 'mg5_path': 6955 self.options[name] = value 6956 if value.lower() == "none" or value=="": 6957 self.options[name] = None 6958 config_file.close() 6959 self.options['stdout_level'] = logging.getLogger('madgraph').level 6960 if not final: 6961 return self.options # the return is usefull for unittest 6962 6963 # Treat each expected input 6964 # 1: Pythia8_path and hewrig++ paths 6965 # try absolute and relative path 6966 for key in self.options: 6967 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path', 6968 'mg5amc_py8_interface_path','madanalysis5_path']: 6969 if self.options[key] in ['None', None]: 6970 self.options[key] = None 6971 continue 6972 path = self.options[key] 6973 #this is for pythia8 6974 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')): 6975 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')): 6976 self.options['pythia8_path'] = None 6977 else: 6978 continue 6979 #this is for mg5amc_py8_interface_path 6980 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')): 6981 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')): 6982 self.options['mg5amc_py8_interface_path'] = None 6983 else: 6984 continue 6985 #this is for madanalysis5 6986 if key == 'madanalysis5_path' and not os.path.isfile(pjoin(MG5DIR, path,'bin','ma5')): 6987 if not os.path.isfile(pjoin(path,'bin','ma5')): 6988 self.options['madanalysis5_path'] = None 6989 else: 6990 ma5path = pjoin(MG5DIR, path) if os.path.isfile(pjoin(MG5DIR, path)) else path 6991 message = misc.is_MA5_compatible_with_this_MG5(ma5path) 6992 if not message is None: 6993 self.options['madanalysis5_path'] = None 6994 logger.warning(message) 6995 continue 6996 6997 #this is for hw++ 6998 if key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 6999 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 7000 self.options['hwpp_path'] = None 7001 else: 7002 continue 7003 # this is for thepeg 7004 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 7005 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 7006 self.options['thepeg_path'] = None 7007 else: 7008 continue 7009 # this is for hepmc 7010 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 7011 if not os.path.isfile(pjoin(path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 7012 self.options['hepmc_path'] = None 7013 else: 7014 continue 7015 7016 elif key in ['golem','samurai']: 7017 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto': 7018 # try to find it automatically on the system 7019 program = misc.which_lib('lib%s.a'%key) 7020 if program != None: 7021 fpath, _ = os.path.split(program) 7022 logger.info('Using %s library in %s' % (key,fpath)) 7023 self.options[key]=fpath 7024 else: 7025 # Try to look for it locally 7026 local_install = { 'golem':'golem95', 7027 'samurai':'samurai'} 7028 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)): 7029 self.options[key]=pjoin(MG5DIR,local_install[key],'lib') 7030 else: 7031 self.options[key]=None 7032 # Make sure that samurai version is recent enough 7033 if key=='samurai' and \ 7034 isinstance(self.options[key],str) and \ 7035 self.options[key].lower() != 'auto': 7036 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')): 7037 try: 7038 version = open(pjoin(self.options[key],os.pardir, 7039 'VERSION'),'r').read() 7040 except IOError: 7041 version = None 7042 if version is None: 7043 self.options[key] = None 7044 logger.info('--------') 7045 logger.info( 7046 """The version of 'samurai' automatically detected seems too old to be compatible 7047 with MG5aMC and it will be turned off. Ask the authors for the latest version if 7048 you want to use samurai. 7049 If you want to enforce its use as-it-is, then specify directly its library folder 7050 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""") 7051 logger.info('--------') 7052 7053 elif key.endswith('path'): 7054 pass 7055 elif key in ['run_mode', 'auto_update']: 7056 self.options[key] = int(self.options[key]) 7057 elif key in ['cluster_type','automatic_html_opening']: 7058 pass 7059 elif key in ['notification_center']: 7060 if self.options[key] in ['False', 'True']: 7061 self.allow_notification_center = eval(self.options[key]) 7062 self.options[key] = self.allow_notification_center 7063 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']: 7064 # Default: try to set parameter 7065 try: 7066 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 7067 except MadGraph5Error as error: 7068 print(error) 7069 logger.warning("Option %s from config file not understood" \ 7070 % key) 7071 else: 7072 if key in self.options_madgraph: 7073 self.history.append('set %s %s' % (key, self.options[key])) 7074 7075 warnings = madevent_interface.MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options) 7076 if warnings: 7077 logger.warning(warnings) 7078 7079 # Configure the way to open a file: 7080 launch_ext.open_file.configure(self.options) 7081 return self.options
7082
7083 - def check_for_export_dir(self, filepath):
7084 """Check if the files is in a valid export directory and assign it to 7085 export path if if is""" 7086 7087 # keep previous if a previous one is defined 7088 if self._export_dir: 7089 return 7090 7091 if os.path.exists(pjoin(os.getcwd(), 'Cards')): 7092 self._export_dir = os.getcwd() 7093 return 7094 7095 path_split = filepath.split(os.path.sep) 7096 if len(path_split) > 2 and path_split[-2] == 'Cards': 7097 self._export_dir = os.path.sep.join(path_split[:-2]) 7098 return
7099
7100 - def do_launch(self, line):
7101 """Main commands: Ask for editing the parameter and then 7102 Execute the code (madevent/standalone/...) 7103 """ 7104 7105 #ensure that MG option are not modified by the launch routine 7106 current_options = dict([(name, self.options[name]) for name in self.options_madgraph]) 7107 start_cwd = os.getcwd() 7108 7109 args = self.split_arg(line) 7110 # check argument validity and normalise argument 7111 (options, args) = _launch_parser.parse_args(args) 7112 self.check_launch(args, options) 7113 options = options.__dict__ 7114 # args is now MODE PATH 7115 7116 if args[0].startswith('standalone'): 7117 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\ 7118 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\ 7119 os.getcwd(),args[1],'SubProcesses','check_poles.f')): 7120 ext_program = launch_ext.MadLoopLauncher(self, args[1], \ 7121 options=self.options, **options) 7122 else: 7123 ext_program = launch_ext.SALauncher(self, args[1], \ 7124 options=self.options, **options) 7125 elif args[0] == 'madevent': 7126 if options['interactive']: 7127 7128 if isinstance(self, cmd.CmdShell): 7129 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options) 7130 else: 7131 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options) 7132 ME.pass_in_web_mode() 7133 stop = self.define_child_cmd_interface(ME) 7134 return stop 7135 7136 #check if this is a cross-section 7137 if not self._generate_info: 7138 # This relaunch an old run -> need to check if this is a 7139 # cross-section or a width 7140 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read() 7141 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1] 7142 generate_info = generate_info.split('#')[0] 7143 else: 7144 generate_info = self._generate_info 7145 7146 if len(generate_info.split('>')[0].strip().split())>1: 7147 ext_program = launch_ext.MELauncher(args[1], self, 7148 shell = isinstance(self, cmd.CmdShell), 7149 options=self.options,**options) 7150 else: 7151 # This is a width computation 7152 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV', 7153 shell = isinstance(self, cmd.CmdShell), 7154 options=self.options,**options) 7155 7156 elif args[0] == 'pythia8': 7157 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options) 7158 7159 elif args[0] == 'aMC@NLO': 7160 if options['interactive']: 7161 if isinstance(self, cmd.CmdShell): 7162 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options) 7163 else: 7164 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options) 7165 ME.pass_in_web_mode() 7166 # transfer interactive configuration 7167 config_line = [l for l in self.history if l.strip().startswith('set')] 7168 for line in config_line: 7169 ME.exec_cmd(line) 7170 stop = self.define_child_cmd_interface(ME) 7171 return stop 7172 ext_program = launch_ext.aMCatNLOLauncher( args[1], self, 7173 shell = isinstance(self, cmd.CmdShell), 7174 **options) 7175 elif args[0] == 'madweight': 7176 import madgraph.interface.madweight_interface as madweight_interface 7177 if options['interactive']: 7178 if isinstance(self, cmd.CmdShell): 7179 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options) 7180 else: 7181 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options) 7182 # transfer interactive configuration 7183 config_line = [l for l in self.history if l.strip().startswith('set')] 7184 for line in config_line: 7185 MW.exec_cmd(line) 7186 stop = self.define_child_cmd_interface(MW) 7187 return stop 7188 ext_program = launch_ext.MWLauncher( self, args[1], 7189 shell = isinstance(self, cmd.CmdShell), 7190 options=self.options,**options) 7191 else: 7192 os.chdir(start_cwd) #ensure to go to the initial path 7193 raise self.InvalidCmd('%s cannot be run from MG5 interface' % args[0]) 7194 7195 7196 ext_program.run() 7197 os.chdir(start_cwd) #ensure to go to the initial path 7198 # ensure that MG options are not changed! 7199 for key, value in current_options.items(): 7200 self.options[key] = value
7201
7202 - def do_load(self, line):
7203 """Not in help: Load information from file""" 7204 7205 args = self.split_arg(line) 7206 # check argument validity 7207 self.check_load(args) 7208 7209 cpu_time1 = time.time() 7210 if args[0] == 'model': 7211 self._curr_model = save_load_object.load_from_file(args[1]) 7212 if self._curr_model.get('parameters'): 7213 # This is a UFO model 7214 self._model_v4_path = None 7215 else: 7216 # This is a v4 model 7217 self._model_v4_path = import_v4.find_model_path(\ 7218 self._curr_model.get('name').replace("_v4", ""), 7219 self._mgme_dir) 7220 7221 # Do post-processing of model 7222 self.process_model() 7223 7224 #save_model.save_model(args[1], self._curr_model) 7225 if isinstance(self._curr_model, base_objects.Model): 7226 cpu_time2 = time.time() 7227 logger.info("Loaded model from file in %0.3f s" % \ 7228 (cpu_time2 - cpu_time1)) 7229 else: 7230 raise self.RWError('Could not load model from file %s' \ 7231 % args[1]) 7232 elif args[0] == 'processes': 7233 amps,proc_defs = save_load_object.load_from_file(args[1]) 7234 if isinstance(amps, diagram_generation.AmplitudeList): 7235 cpu_time2 = time.time() 7236 logger.info("Loaded processes from file in %0.3f s" % \ 7237 (cpu_time2 - cpu_time1)) 7238 if amps: 7239 model = amps[0].get('process').get('model') 7240 if not model.get('parameters'): 7241 # This is a v4 model. Look for path. 7242 self._model_v4_path = import_v4.find_model_path(\ 7243 model.get('name').replace("_v4", ""), 7244 self._mgme_dir) 7245 else: 7246 self._model_v4_path = None 7247 # If not exceptions from previous steps, set 7248 # _curr_amps and _curr_model 7249 self._curr_amps = amps 7250 self._curr_model = model 7251 self._curr_proc_defs = proc_defs 7252 logger.info("Model set from process.") 7253 # Do post-processing of model 7254 self.process_model() 7255 self._done_export = None 7256 else: 7257 raise self.RWError('Could not load processes from file %s' % args[1])
7258 7259
7260 - def do_customize_model(self, line):
7261 """create a restriction card in a interactive way""" 7262 7263 args = self.split_arg(line) 7264 self.check_customize_model(args) 7265 7266 model_path = self._curr_model.get('modelpath') 7267 if not os.path.exists(pjoin(model_path,'build_restrict.py')): 7268 raise self.InvalidCmd('''Model not compatible with this option.''') 7269 7270 # (re)import the full model (get rid of the default restriction) 7271 self._curr_model = import_ufo.import_model(model_path, restrict=False) 7272 7273 #1) create the full param_card 7274 out_path = StringIO.StringIO() 7275 param_writer.ParamCardWriter(self._curr_model, out_path) 7276 # and load it to a python object 7277 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 7278 7279 7280 all_categories = self.ask('','0',[], ask_class=AskforCustomize) 7281 put_to_one = [] 7282 ## Make a Temaplate for the restriction card. (card with no restrict) 7283 for block in param_card: 7284 value_dict = {} 7285 for param in param_card[block]: 7286 value = param.value 7287 if value == 0: 7288 param.value = 0.000001e-99 7289 elif value == 1: 7290 if block != 'qnumbers': 7291 put_to_one.append((block,param.lhacode)) 7292 param.value = random.random() 7293 elif abs(value) in value_dict: 7294 param.value += value_dict[abs(value)] * 1e-4 * param.value 7295 value_dict[abs(value)] += 1 7296 else: 7297 value_dict[abs(value)] = 1 7298 7299 for category in all_categories: 7300 for options in category: 7301 if not options.status: 7302 continue 7303 param = param_card[options.lhablock].get(options.lhaid) 7304 param.value = options.value 7305 7306 logger.info('Loading the resulting model') 7307 # Applying the restriction 7308 self._curr_model = import_ufo.RestrictModel(self._curr_model) 7309 model_name = self._curr_model.get('name') 7310 if model_name == 'mssm': 7311 keep_external=True 7312 else: 7313 keep_external=False 7314 self._curr_model.restrict_model(param_card,keep_external=keep_external) 7315 7316 if args: 7317 name = args[0].split('=',1)[1] 7318 path = pjoin(model_path,'restrict_%s.dat' % name) 7319 logger.info('Save restriction file as %s' % path) 7320 param_card.write(path) 7321 self._curr_model['name'] += '-%s' % name 7322 7323 # if some need to put on one 7324 if put_to_one: 7325 out_path = StringIO.StringIO() 7326 param_writer.ParamCardWriter(self._curr_model, out_path) 7327 # and load it to a python object 7328 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 7329 7330 for (block, lhacode) in put_to_one: 7331 try: 7332 param_card[block].get(lhacode).value = 1 7333 except: 7334 pass # was removed of the model! 7335 self._curr_model.set_parameters_and_couplings(param_card) 7336 7337 if args: 7338 name = args[0].split('=',1)[1] 7339 path = pjoin(model_path,'paramcard_%s.dat' % name) 7340 logger.info('Save default card file as %s' % path) 7341 param_card.write(path)
7342
7343 - def do_save(self, line, check=True, to_keep={}, log=True):
7344 """Not in help: Save information to file""" 7345 7346 7347 args = self.split_arg(line) 7348 # Check argument validity 7349 if check: 7350 self.check_save(args) 7351 7352 if args[0] == 'model': 7353 if self._curr_model: 7354 #save_model.save_model(args[1], self._curr_model) 7355 if save_load_object.save_to_file(args[1], self._curr_model): 7356 logger.info('Saved model to file %s' % args[1]) 7357 else: 7358 raise self.InvalidCmd('No model to save!') 7359 elif args[0] == 'processes': 7360 if self._curr_amps: 7361 if save_load_object.save_to_file(args[1], (self._curr_amps,self._curr_proc_defs) ): 7362 logger.info('Saved processes to file %s' % args[1]) 7363 else: 7364 raise self.InvalidCmd('No processes to save!') 7365 7366 elif args[0] == 'options': 7367 partial_save = False 7368 to_define = {} 7369 7370 if any(not arg.startswith('--') and arg in self.options 7371 for arg in args): 7372 # store in file only those ones 7373 partial_save = True 7374 all_arg = [arg for arg in args[1:] if not arg.startswith('--') and 7375 arg in self.options] 7376 for key in all_arg: 7377 to_define[key] = self.options[key] 7378 else: 7379 # First look at options which should be put in MG5DIR/input 7380 for key, default in self.options_configuration.items(): 7381 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None: 7382 to_define[key] = self.options[key] 7383 7384 if not '--auto' in args: 7385 for key, default in self.options_madevent.items(): 7386 if self.options_madevent[key] != self.options[key] != None: 7387 if '_path' in key and os.path.basename(self.options[key]) == 'None': 7388 continue 7389 to_define[key] = self.options[key] 7390 elif key == 'cluster_queue' and self.options[key] is None: 7391 to_define[key] = self.options[key] 7392 7393 if '--all' in args: 7394 for key, default in self.options_madgraph.items(): 7395 if self.options_madgraph[key] != self.options[key] != None and \ 7396 key != 'stdout_level': 7397 to_define[key] = self.options[key] 7398 elif not '--auto' in args: 7399 for key, default in self.options_madgraph.items(): 7400 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level': 7401 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 7402 % (key,self.options_madgraph[key]) ) 7403 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 7404 7405 if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options: 7406 filepath = args[1] 7407 else: 7408 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 7409 7410 basedir = MG5DIR 7411 if partial_save: 7412 basefile = filepath 7413 else: 7414 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt') 7415 7416 7417 7418 if to_keep: 7419 to_define = to_keep 7420 self.write_configuration(filepath, basefile, basedir, to_define)
7421 7422 # Set an option
7423 - def do_set(self, line, log=True, model_reload=True):
7424 """Set an option, which will be default for coming generations/outputs. 7425 """ 7426 7427 # Be careful: 7428 # This command is associated to a post_cmd: post_set. 7429 args = self.split_arg(line) 7430 7431 # Check the validity of the arguments 7432 self.check_set(args) 7433 7434 if args[0] == 'ignore_six_quark_processes': 7435 if args[1].lower() == 'false': 7436 self.options[args[0]] = False 7437 return 7438 self.options[args[0]] = list(set([abs(p) for p in \ 7439 self._multiparticles[args[1]]\ 7440 if self._curr_model.get_particle(p).\ 7441 is_fermion() and \ 7442 self._curr_model.get_particle(abs(p)).\ 7443 get('color') == 3])) 7444 if log: 7445 logger.info('Ignore processes with >= 6 quarks (%s)' % \ 7446 ",".join([\ 7447 self._curr_model.get_particle(q).get('name') \ 7448 for q in self.options[args[0]]])) 7449 7450 elif args[0] == 'group_subprocesses': 7451 if args[1].lower() not in ['auto', 'nlo']: 7452 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, name="group_subprocesses") 7453 else: 7454 if args[1].lower() == 'nlo': 7455 self.options[args[0]] = "NLO" 7456 else: 7457 self.options[args[0]] = "Auto" 7458 if log: 7459 logger.info('Set group_subprocesses to %s' % \ 7460 str(self.options[args[0]])) 7461 logger.info('Note that you need to regenerate all processes') 7462 self._curr_amps = diagram_generation.AmplitudeList() 7463 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7464 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7465 7466 elif args[0] == "stdout_level": 7467 if args[1].isdigit(): 7468 level = int(args[1]) 7469 else: 7470 level = eval('logging.' + args[1]) 7471 logging.root.setLevel(level) 7472 logging.getLogger('madgraph').setLevel(level) 7473 logging.getLogger('madevent').setLevel(level) 7474 self.options[args[0]] = level 7475 if log: 7476 logger.info('set output information to level: %s' % level) 7477 elif args[0].lower() == "ewscheme": 7478 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." %\ 7479 (self._curr_model.get('name'), args[1])) 7480 logger.info("Importing a model will restore the default scheme") 7481 self._curr_model.change_electroweak_mode(args[1]) 7482 elif args[0] == "complex_mass_scheme": 7483 old = self.options[args[0]] 7484 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, "complex_mass_scheme") 7485 aloha.complex_mass = self.options[args[0]] 7486 aloha_lib.KERNEL.clean() 7487 if self.options[args[0]]: 7488 if old: 7489 if log: 7490 logger.info('Complex mass already activated.') 7491 return 7492 if log: 7493 logger.info('Activate complex mass scheme.') 7494 else: 7495 if not old: 7496 if log: 7497 logger.info('Complex mass already desactivated.') 7498 return 7499 if log: 7500 logger.info('Desactivate complex mass scheme.') 7501 if not self._curr_model: 7502 return 7503 self.exec_cmd('import model %s' % self._curr_model.get('name')) 7504 7505 elif args[0] == "gauge": 7506 # Treat the case where they are no model loaded 7507 if not self._curr_model: 7508 if args[1] == 'unitary': 7509 aloha.unitary_gauge = True 7510 elif args[1] == 'axial': 7511 aloha.unitary_gauge = 2 7512 else: 7513 aloha.unitary_gauge = False 7514 aloha_lib.KERNEL.clean() 7515 self.options[args[0]] = args[1] 7516 if log: logger.info('Passing to gauge %s.' % args[1]) 7517 return 7518 7519 # They are a valid model 7520 able_to_mod = True 7521 if args[1] == 'unitary': 7522 if 0 in self._curr_model.get('gauge'): 7523 aloha.unitary_gauge = True 7524 else: 7525 able_to_mod = False 7526 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \ 7527 % self._curr_model.get('name')) 7528 elif args[1] == 'axial': 7529 if 0 in self._curr_model.get('gauge'): 7530 aloha.unitary_gauge = 2 7531 else: 7532 able_to_mod = False 7533 if log: logger.warning('Note that parton-shower gauge is not allowed for your current model %s' \ 7534 % self._curr_model.get('name')) 7535 else: 7536 if 1 in self._curr_model.get('gauge'): 7537 aloha.unitary_gauge = False 7538 else: 7539 able_to_mod = False 7540 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \ 7541 % self._curr_model.get('name')) 7542 7543 if self.options['gauge'] == args[1]: 7544 return 7545 7546 7547 self.options[args[0]] = args[1] 7548 7549 if able_to_mod and log and args[0] == 'gauge' and \ 7550 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \ 7551 isinstance(self._curr_model,loop_base_objects.LoopModel) and \ 7552 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 7553 logger.warning('You will only be able to do tree level'+\ 7554 ' and QCD corrections in the unitary gauge.') 7555 7556 7557 7558 #re-init all variable 7559 model_name = self._curr_model.get('modelpath+restriction') 7560 self._curr_model = None 7561 self._curr_amps = diagram_generation.AmplitudeList() 7562 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7563 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7564 self._curr_helas_model = None 7565 self._curr_exporter = None 7566 self._done_export = False 7567 import_ufo._import_once = [] 7568 logger.info('Passing to gauge %s.' % args[1]) 7569 7570 if able_to_mod: 7571 # We don't want to go through the MasterCommand again 7572 # because it messes with the interface switching when 7573 # importing a loop model from MG5 7574 if 'modelname' in self.history.get('full_model_line'): 7575 opts = '--modelname' 7576 else: 7577 opts='' 7578 MadGraphCmd.do_import(self,'model %s %s' % (model_name, opts), force=True) 7579 elif log: 7580 logger.info('Note that you have to reload the model') 7581 7582 elif args[0] == 'fortran_compiler': 7583 if args[1] != 'None': 7584 if log: 7585 logger.info('set fortran compiler to %s' % args[1]) 7586 self.options['fortran_compiler'] = args[1] 7587 else: 7588 self.options['fortran_compiler'] = None 7589 elif args[0] == 'default_unset_couplings': 7590 self.options['default_unset_couplings'] = banner_module.ConfigFile.format_variable(args[1], int, name="default_unset_couplings") 7591 elif args[0].startswith('f2py_compiler'): 7592 to_do = True 7593 if args[0].endswith('_py2') and six.PY3: 7594 to_do = False 7595 elif args[0].endswith('_py3') and six.PY2: 7596 to_do = False 7597 if to_do: 7598 if args[1] != 'None': 7599 if log: 7600 logger.info('set f2py compiler to %s' % args[1]) 7601 7602 self.options['f2py_compiler'] = args[1] 7603 else: 7604 self.options['f2py_compiler'] = None 7605 7606 elif args[0] == 'loop_optimized_output': 7607 7608 if log: 7609 logger.info('set loop optimized output to %s' % args[1]) 7610 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7611 self.options[args[0]] = args[1] 7612 if not self.options['loop_optimized_output'] and \ 7613 self.options['loop_color_flows']: 7614 logger.warning("Turning off option 'loop_color_flows'"+\ 7615 " since it is not available for non-optimized loop output.") 7616 self.do_set('loop_color_flows False',log=False) 7617 elif args[0] == 'loop_color_flows': 7618 if log: 7619 logger.info('set loop color flows to %s' % args[1]) 7620 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7621 self.options[args[0]] = args[1] 7622 if self.options['loop_color_flows'] and \ 7623 not self.options['loop_optimized_output']: 7624 logger.warning("Turning on option 'loop_optimized'"+\ 7625 " needed for loop color flow computation.") 7626 self.do_set('loop_optimized_output True',False) 7627 7628 elif args[0] == 'fastjet': 7629 try: 7630 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE, 7631 stderr=subprocess.PIPE) 7632 output, error = p.communicate() 7633 output = output.decode() 7634 res = 0 7635 except Exception: 7636 res = 1 7637 7638 if res != 0 or error: 7639 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \ 7640 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \ 7641 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' + 7642 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n') 7643 self.options[args[0]] = None 7644 if self.history and 'fastjet' in self.history[-1]: 7645 self.history.pop() 7646 elif int(output.split('.')[0]) < 3: 7647 logger.warning('%s is not ' % args[1] + \ 7648 'v3 or greater. Please install FastJet v3+.') 7649 self.options[args[0]] = None 7650 self.history.pop() 7651 else: #everything is fine 7652 logger.info('set fastjet to %s' % args[1]) 7653 self.options[args[0]] = args[1] 7654 7655 elif args[0] in ['golem','samurai','ninja','collier'] and \ 7656 not (args[0] in ['ninja','collier'] and args[1]=='./HEPTools/lib'): 7657 if args[1] in ['None',"''",'""']: 7658 self.options[args[0]] = None 7659 else: 7660 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0])) 7661 if program!=None: 7662 res = 0 7663 logger.info('set %s to %s' % (args[0],args[1])) 7664 self.options[args[0]] = args[1] 7665 else: 7666 res = 1 7667 7668 if res != 0 : 7669 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \ 7670 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \ 7671 'You will NOT be able to run %s otherwise.\n'%args[0]) 7672 7673 elif args[0].startswith('lhapdf'): 7674 to_do = True 7675 if args[0].endswith('_py2') and six.PY3: 7676 to_do = False 7677 elif args[0].endswith('_py3') and six.PY2: 7678 to_do = False 7679 if to_do: 7680 try: 7681 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE, 7682 stderr=subprocess.PIPE) 7683 logger.info('set lhapdf to %s' % args[1]) 7684 self.options['lhapdf'] = args[1] 7685 self.options[args[0]] = args[1] 7686 except Exception: 7687 res = 1 7688 if res != 0: 7689 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \ 7690 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \ 7691 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \ 7692 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \ 7693 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n') 7694 7695 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry', 'max_t_for_channel', 7696 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']: 7697 self.options[args[0]] = int(args[1]) 7698 7699 elif args[0] in ['cluster_local_path']: 7700 self.options[args[0]] = args[1].strip() 7701 7702 elif args[0] == 'cluster_status_update': 7703 if '(' in args[1]: 7704 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 7705 data = data.replace('(','').replace(')','').replace(',',' ').split() 7706 first, second = data[:2] 7707 else: 7708 first, second = args[1:3] 7709 7710 self.options[args[0]] = (int(first), int(second)) 7711 7712 elif args[0] == 'madanalysis5_path': 7713 ma5path = pjoin(MG5DIR, args[1]) if os.path.isfile(pjoin(MG5DIR, args[1])) else args[1] 7714 message = misc.is_MA5_compatible_with_this_MG5(ma5path) 7715 if message is None: 7716 self.options['madanalysis5_path'] = args[1] 7717 else: 7718 logger.warning(message) 7719 7720 elif args[0] == 'OLP': 7721 if six.PY3 and self.options['low_mem_multicore_nlo_generation']: 7722 raise self.InvalidCmd('Not possible to set OLP with both \"low_mem_multicore_nlo_generation\" and python3') 7723 # Reset the amplitudes, MatrixElements and exporter as they might 7724 # depend on this option 7725 self._curr_amps = diagram_generation.AmplitudeList() 7726 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7727 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7728 self._curr_exporter = None 7729 self.options[args[0]] = args[1] 7730 7731 elif args[0] =='output_dependencies': 7732 self.options[args[0]] = args[1] 7733 elif args[0] =='notification_center': 7734 if args[1] in ['None','True','False']: 7735 self.options[args[0]] = eval(args[1]) 7736 self.allow_notification_center = self.options[args[0]] 7737 else: 7738 raise self.InvalidCmd('expected bool for notification_center') 7739 # True/False formatting 7740 elif args[0] in ['crash_on_error']: 7741 try: 7742 tmp = banner_module.ConfigFile.format_variable(args[1], bool, 'crash_on_error') 7743 except Exception: 7744 if args[1].lower() in ['never']: 7745 tmp = args[1].lower() 7746 else: 7747 raise 7748 self.options[args[0]] = tmp 7749 elif args[0] in ['zerowidth_tchannel']: 7750 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, args[0]) 7751 elif args[0] in ['cluster_queue']: 7752 self.options[args[0]] = args[1].strip() 7753 elif args[0] in ['low_mem_multicore_nlo_generation']: 7754 if six.PY3 and self.options['OLP'] != 'MadLoop': 7755 raise self.InvalidCmd('Not possible to set \"low_mem_multicore_nlo_generation\" for an OLP different of MadLoop when running python3') 7756 else: 7757 self.options[args[0]] = args[1] 7758 elif args[0] in self.options: 7759 if args[1] in ['None','True','False']: 7760 self.options[args[0]] = eval(args[1]) 7761 else: 7762 self.options[args[0]] = args[1]
7763
7764 - def post_set(self, stop, line):
7765 """Check if we need to save this in the option file""" 7766 7767 args = self.split_arg(line) 7768 # Check the validity of the arguments 7769 try: 7770 self.check_set(args, log=False) 7771 except Exception: 7772 return stop 7773 7774 if args[0] in self.options_configuration and '--no_save' not in args: 7775 self.exec_cmd('save options %s' % args[0] , log=False) 7776 elif args[0] in self.options_madevent: 7777 if not '--no_save' in line: 7778 logger.info('This option will be the default in any output that you are going to create in this session.') 7779 logger.info('In order to keep this changes permanent please run \'save options\'') 7780 else: 7781 #MadGraph5_aMC@NLO configuration 7782 if not self.history or self.history[-1].split() != line.split(): 7783 self.history.append('set %s' % line) 7784 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set']) 7785 return stop
7786
7787 - def do_open(self, line):
7788 """Open a text file/ eps file / html file""" 7789 7790 args = self.split_arg(line) 7791 # Check Argument validity and modify argument to be the real path 7792 self.check_open(args) 7793 file_path = args[0] 7794 7795 launch_ext.open_file(file_path)
7796
7797 - def do_output(self, line):
7798 """Main commands: Initialize a new Template or reinitialize one""" 7799 7800 args = self.split_arg(line) 7801 # Check Argument validity 7802 self.check_output(args) 7803 7804 noclean = '-noclean' in args 7805 force = '-f' in args 7806 nojpeg = '-nojpeg' in args 7807 if '--noeps=True' in args: 7808 nojpeg = True 7809 flaglist = [] 7810 7811 if '--postpone_model' in args: 7812 flaglist.append('store_model') 7813 7814 line_options = dict(arg[2:].split('=') for arg in args if arg.startswith('--') and '=' in arg) 7815 main_file_name = "" 7816 try: 7817 main_file_name = args[args.index('-name') + 1] 7818 except Exception: 7819 pass 7820 7821 7822 ################ 7823 # ALOHA OUTPUT # 7824 ################ 7825 if self._export_format == 'aloha': 7826 # catch format 7827 format = [d[9:] for d in args if d.startswith('--format=')] 7828 if not format: 7829 format = 'Fortran' 7830 else: 7831 format = format[-1] 7832 # catch output dir 7833 output = [d for d in args if d.startswith('--output=')] 7834 if not output: 7835 output = import_ufo.find_ufo_path(self._curr_model['name']) 7836 output = pjoin(output, format) 7837 if not os.path.isdir(output): 7838 os.mkdir(output) 7839 else: 7840 output = output[-1] 7841 if not os.path.isdir(output): 7842 raise self.InvalidCmd('%s is not a valid directory' % output) 7843 logger.info('creating routines in directory %s ' % output) 7844 # build the calling list for aloha 7845 names = [d for d in args if not d.startswith('-')] 7846 wanted_lorentz = aloha_fct.guess_routine_from_name(names) 7847 # Create and write ALOHA Routine 7848 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name')) 7849 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz')) 7850 if wanted_lorentz: 7851 aloha_model.compute_subset(wanted_lorentz) 7852 else: 7853 aloha_model.compute_all(save=False) 7854 aloha_model.write(output, format) 7855 return 7856 7857 ################# 7858 ## Other Output # 7859 ################# 7860 # Configuration of what to do: 7861 # check: check status of the directory 7862 # exporter: which exporter to use (v4/cpp/...) 7863 # output: [Template/dir/None] copy the Template, just create dir or do nothing 7864 config = {} 7865 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7866 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'} 7867 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7868 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7869 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7870 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7871 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'} 7872 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'} 7873 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} 7874 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'} 7875 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7876 7877 if self._export_format == 'plugin': 7878 options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output} 7879 else: 7880 options = config[self._export_format] 7881 7882 # check 7883 if os.path.realpath(self._export_dir) == os.getcwd(): 7884 if len(args) == 0: 7885 i=0 7886 while 1: 7887 if os.path.exists('Pythia8_proc_%i' %i): 7888 i+=1 7889 else: 7890 break 7891 os.mkdir('Pythia8_proc_%i' %i) 7892 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i) 7893 logger.info('Create output in %s' % self._export_dir) 7894 elif not args[0] in ['.', '-f']: 7895 raise self.InvalidCmd('Wrong path directory to create in local directory use \'.\'') 7896 elif not noclean and os.path.isdir(self._export_dir) and options['check']: 7897 if not force: 7898 # Don't ask if user already specified force or noclean 7899 logger.info('INFO: directory %s already exists.' % self._export_dir) 7900 logger.info('If you continue this directory will be deleted and replaced.') 7901 answer = self.ask('Do you want to continue?', 'y', ['y','n']) 7902 else: 7903 answer = 'y' 7904 if answer != 'y': 7905 raise self.InvalidCmd('Stopped by user request') 7906 else: 7907 shutil.rmtree(self._export_dir) 7908 7909 # Choose here whether to group subprocesses or not, if the option was 7910 # set to 'Auto' and propagate this choice down the line: 7911 if self.options['group_subprocesses'] in [True, False]: 7912 group_processes = self.options['group_subprocesses'] 7913 elif self.options['group_subprocesses'] == 'Auto': 7914 # By default we set it to True 7915 group_processes = True 7916 # But we turn if off for decay processes which 7917 # have been defined with multiparticle labels, because then 7918 # branching ratios necessitates to keep subprocesses independent. 7919 # That applies only if there is more than one subprocess of course. 7920 if self._curr_amps[0].get_ninitial() == 1 and \ 7921 len(self._curr_amps)>1: 7922 7923 processes = [amp.get('process') for amp in self._curr_amps if 'process' in list(amp.keys())] 7924 if len(set(proc.get('id') for proc in processes))!=len(processes): 7925 # Special warning for loop-induced 7926 if any(proc['perturbation_couplings'] != [] for proc in 7927 processes) and self._export_format == 'madevent': 7928 logger.warning(""" 7929 || The loop-induced decay process you have specified contains several 7930 || subprocesses and, in order to be able to compute individual branching ratios, 7931 || MG5_aMC will *not* group them. Integration channels will also be considered 7932 || for each diagrams and as a result integration will be inefficient. 7933 || It is therefore recommended to perform this simulation by setting the MG5_aMC 7934 || option 'group_subprocesses' to 'True' (before the output of the process). 7935 || Notice that when doing so, processes for which one still wishes to compute 7936 || branching ratios independently can be specified using the syntax: 7937 || -> add process <proc_def> 7938 """) 7939 group_processes = False 7940 7941 #Exporter + Template 7942 if options['exporter'] == 'v4': 7943 self._curr_exporter = export_v4.ExportV4Factory(self, noclean, 7944 group_subprocesses=group_processes, 7945 cmd_options=line_options) 7946 elif options['exporter'] == 'cpp': 7947 self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes, 7948 cmd_options=line_options) 7949 7950 self._curr_exporter.pass_information_from_cmd(self) 7951 7952 if options['output'] == 'Template': 7953 self._curr_exporter.copy_template(self._curr_model) 7954 elif options['output'] == 'dir' and not os.path.isdir(self._export_dir): 7955 os.makedirs(self._export_dir) 7956 7957 # Reset _done_export, since we have new directory 7958 self._done_export = False 7959 7960 if self._export_format == "madevent": 7961 # for MadEvent with MadLoop decide if we keep the box as channel of 7962 #integration or not. Forbid them for matching and for h+j 7963 if self.options['max_npoint_for_channel']: 7964 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel'] 7965 else: 7966 base_objects.Vertex.max_n_loop_for_multichanneling = 3 7967 base_objects.Vertex.max_tpropa = self.options['max_t_for_channel'] 7968 7969 # Perform export and finalize right away 7970 self.export(nojpeg, main_file_name, group_processes, args) 7971 7972 # Automatically run finalize 7973 self.finalize(nojpeg, flaglist=flaglist) 7974 7975 # Remember that we have done export 7976 self._done_export = (self._export_dir, self._export_format) 7977 7978 # Reset _export_dir, so we don't overwrite by mistake later 7979 self._export_dir = None
7980 7981 # Export a matrix element
7982 - def export(self, nojpeg = False, main_file_name = "", group_processes=True, 7983 args=[]):
7984 """Export a generated amplitude to file.""" 7985 7986 7987 # Define the helas call writer 7988 if self._curr_exporter.exporter == 'cpp': 7989 self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model) 7990 elif self._model_v4_path: 7991 assert self._curr_exporter.exporter == 'v4' 7992 self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model) 7993 else: 7994 assert self._curr_exporter.exporter == 'v4' 7995 options = {'zerowidth_tchannel': True} 7996 if self._curr_amps and self._curr_amps[0].get_ninitial() == 1: 7997 options['zerowidth_tchannel'] = False 7998 7999 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 8000 8001 version = [arg[10:] for arg in args if arg.startswith('--version=')] 8002 if version: 8003 version = version[-1] 8004 else: 8005 version = '8.2' 8006 8007 def generate_matrix_elements(self, group_processes=True): 8008 """Helper function to generate the matrix elements before 8009 exporting. Uses the main function argument 'group_processes' to decide 8010 whether to use group_subprocess or not. (it has been set in do_output to 8011 the appropriate value if the MG5 option 'group_subprocesses' was set 8012 to 'Auto'.""" 8013 8014 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']: 8015 to_distinguish = [] 8016 for part in self._curr_model.get('particles'): 8017 if part.get('name') in args and part.get('antiname') in args and\ 8018 part.get('name') != part.get('antiname'): 8019 to_distinguish.append(abs(part.get('pdg_code'))) 8020 # Sort amplitudes according to number of diagrams, 8021 # to get most efficient multichannel output 8022 self._curr_amps.sort(key=lambda x: x.get_number_of_diagrams(),reverse=True) 8023 8024 cpu_time1 = time.time() 8025 ndiags = 0 8026 if not self._curr_matrix_elements.get_matrix_elements(): 8027 if group_processes: 8028 cpu_time1 = time.time() 8029 dc_amps = diagram_generation.DecayChainAmplitudeList(\ 8030 [amp for amp in self._curr_amps if isinstance(amp, \ 8031 diagram_generation.DecayChainAmplitude)]) 8032 non_dc_amps = diagram_generation.AmplitudeList(\ 8033 [amp for amp in self._curr_amps if not \ 8034 isinstance(amp, \ 8035 diagram_generation.DecayChainAmplitude)]) 8036 subproc_groups = group_subprocs.SubProcessGroupList() 8037 matrix_elements_opts = {'optimized_output': 8038 self.options['loop_optimized_output']} 8039 8040 grouping_criteria = self._curr_exporter.grouped_mode 8041 if non_dc_amps: 8042 subproc_groups.extend(\ 8043 group_subprocs.SubProcessGroup.group_amplitudes(\ 8044 non_dc_amps,grouping_criteria, 8045 matrix_elements_opts=matrix_elements_opts)) 8046 8047 if dc_amps: 8048 dc_subproc_group = \ 8049 group_subprocs.DecayChainSubProcessGroup.\ 8050 group_amplitudes(dc_amps, grouping_criteria, 8051 matrix_elements_opts=matrix_elements_opts) 8052 subproc_groups.extend(dc_subproc_group.\ 8053 generate_helas_decay_chain_subproc_groups()) 8054 8055 ndiags = sum([len(m.get('diagrams')) for m in \ 8056 subproc_groups.get_matrix_elements()]) 8057 self._curr_matrix_elements = subproc_groups 8058 # assign a unique id number to all groups 8059 uid = 0 8060 for group in subproc_groups: 8061 uid += 1 # update the identification number 8062 for me in group.get('matrix_elements'): 8063 me.get('processes')[0].set('uid', uid) 8064 else: # Not grouped subprocesses 8065 mode = {} 8066 if self._export_format in [ 'standalone_msP' , 8067 'standalone_msF', 'standalone_rw']: 8068 mode['mode'] = 'MadSpin' 8069 # The conditional statement tests whether we are dealing 8070 # with a loop induced process. 8071 if isinstance(self._curr_amps[0], 8072 loop_diagram_generation.LoopAmplitude): 8073 mode['optimized_output']=self.options['loop_optimized_output'] 8074 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess 8075 compute_loop_nc = True 8076 else: 8077 HelasMultiProcessClass = helas_objects.HelasMultiProcess 8078 compute_loop_nc = False 8079 8080 self._curr_matrix_elements = HelasMultiProcessClass( 8081 self._curr_amps, compute_loop_nc=compute_loop_nc, 8082 matrix_element_opts=mode) 8083 8084 ndiags = sum([len(me.get('diagrams')) for \ 8085 me in self._curr_matrix_elements.\ 8086 get_matrix_elements()]) 8087 # assign a unique id number to all process 8088 uid = 0 8089 for me in self._curr_matrix_elements.get_matrix_elements()[:]: 8090 uid += 1 # update the identification number 8091 me.get('processes')[0].set('uid', uid) 8092 8093 cpu_time2 = time.time() 8094 8095 8096 return ndiags, cpu_time2 - cpu_time1
8097 8098 # Start of the actual routine 8099 8100 ndiags, cpu_time = generate_matrix_elements(self,group_processes) 8101 8102 calls = 0 8103 8104 path = self._export_dir 8105 8106 cpu_time1 = time.time() 8107 8108 # First treat madevent and pythia8 exports, where we need to 8109 # distinguish between grouped and ungrouped subprocesses 8110 8111 # MadEvent 8112 if self._export_format == 'madevent': 8113 calls += self._curr_exporter.export_processes(self._curr_matrix_elements, 8114 self._curr_helas_model) 8115 8116 #try: 8117 # cmd.Cmd.onecmd(self, 'history .') 8118 #except Exception: 8119 # misc.sprint('command history fails.', 10) 8120 # pass 8121 8122 # Pythia 8 8123 elif self._export_format == 'pythia8': 8124 # Output the process files 8125 process_names = [] 8126 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList): 8127 for (group_number, me_group) in enumerate(self._curr_matrix_elements): 8128 exporter = self._curr_exporter.generate_process_directory(\ 8129 me_group.get('matrix_elements'), self._curr_helas_model, 8130 process_string = me_group.get('name'), 8131 process_number = group_number+1, 8132 version = version) 8133 process_names.append(exporter.process_name) 8134 else: 8135 exporter = self._curr_exporter.generate_process_directory(\ 8136 self._curr_matrix_elements, self._curr_helas_model, 8137 process_string = self._generate_info, version = version) 8138 process_names.append(exporter.process_file_name) 8139 8140 # Output the model parameter and ALOHA files 8141 model_name, model_path = exporter.convert_model_to_pythia8(\ 8142 self._curr_model, self._export_dir) 8143 8144 # Generate the main program file 8145 filename, make_filename = \ 8146 self._curr_exporter.generate_example_file_pythia8(path, 8147 model_path, 8148 process_names, 8149 exporter, 8150 main_file_name) 8151 8152 8153 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8154 # Just the matrix.f files 8155 if self._export_format == 'matrix': 8156 for me in matrix_elements: 8157 filename = pjoin(path, 'matrix_' + \ 8158 me.get('processes')[0].shell_string() + ".f") 8159 if os.path.isfile(filename): 8160 logger.warning("Overwriting existing file %s" % filename) 8161 else: 8162 logger.info("Creating new file %s" % filename) 8163 calls = calls + self._curr_exporter.write_matrix_element_v4(\ 8164 writers.FortranWriter(filename),\ 8165 me, self._curr_helas_model) 8166 elif self._export_format in ['madevent', 'pythia8']: 8167 pass 8168 # grouping mode 8169 elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\ 8170 self._curr_exporter.grouped_mode: 8171 modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements) 8172 if modify: 8173 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8174 8175 for me_number, me in enumerate(self._curr_matrix_elements): 8176 calls = calls + \ 8177 self._curr_exporter.generate_subprocess_directory(\ 8178 me, self._curr_helas_model, me_number) 8179 8180 # ungroup mode 8181 else: 8182 for nb,me in enumerate(matrix_elements[:]): 8183 new_calls = self._curr_exporter.generate_subprocess_directory(\ 8184 me, self._curr_helas_model, nb) 8185 if isinstance(new_calls, int): 8186 if new_calls ==0: 8187 matrix_elements.remove(me) 8188 else: 8189 calls = calls + new_calls 8190 8191 if self._generate_info and hasattr(self._curr_exporter, 'write_procdef_mg5'): 8192 # Write the procdef_mg5.dat file with process info 8193 card_path = pjoin(self._export_dir ,'SubProcesses', \ 8194 'procdef_mg5.dat') 8195 self._curr_exporter.write_procdef_mg5(card_path, 8196 self._curr_model['name'], 8197 self._generate_info) 8198 8199 8200 cpu_time2 = time.time() - cpu_time1 8201 8202 logger.info(("Generated helas calls for %d subprocesses " + \ 8203 "(%d diagrams) in %0.3f s") % \ 8204 (len(matrix_elements), 8205 ndiags, cpu_time)) 8206 8207 if calls: 8208 if "cpu_time2" in locals(): 8209 logger.info("Wrote files for %d helas calls in %0.3f s" % \ 8210 (calls, cpu_time2)) 8211 else: 8212 logger.info("Wrote files for %d helas calls" % \ 8213 (calls)) 8214 8215 if self._export_format == 'pythia8': 8216 logger.info("- All necessary files for Pythia 8 generated.") 8217 logger.info("- Run \"launch\" and select %s.cc," % filename) 8218 logger.info(" or go to %s/examples and run" % path) 8219 logger.info(" make -f %s" % make_filename) 8220 logger.info(" (with process_name replaced by process name).") 8221 logger.info(" You can then run ./%s to produce events for the process" % \ 8222 filename) 8223 8224 # Replace the amplitudes with the actual amplitudes from the 8225 # matrix elements, which allows proper diagram drawing also of 8226 # decay chain processes 8227 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8228 self._curr_amps = diagram_generation.AmplitudeList(\ 8229 [me.get('base_amplitude') for me in \ 8230 matrix_elements]) 8231
8232 - def finalize(self, nojpeg, online = False, flaglist=[]):
8233 """Make the html output, write proc_card_mg5.dat and create 8234 madevent.tar.gz for a MadEvent directory""" 8235 8236 compiler_dict = {'fortran': self.options['fortran_compiler'], 8237 'cpp': self.options['cpp_compiler'], 8238 'f2py': self.options['f2py_compiler']} 8239 8240 # Handling of the model. 8241 if self._model_v4_path: 8242 logger.info('Copy %s model files to directory %s' % \ 8243 (os.path.basename(self._model_v4_path), self._export_dir)) 8244 self._curr_exporter.export_model_files(self._model_v4_path) 8245 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS')) 8246 else: 8247 # wanted_lorentz are the lorentz structures which are 8248 # actually used in the wavefunctions and amplitudes in 8249 # these processes 8250 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 8251 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 8252 # For a unique output of multiple type of exporter need to store this 8253 # information. 8254 if hasattr(self, 'previous_lorentz'): 8255 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz)) 8256 wanted_couplings = list(set(self.previous_couplings + wanted_couplings)) 8257 del self.previous_lorentz 8258 del self.previous_couplings 8259 if 'store_model' in flaglist: 8260 self.previous_lorentz = wanted_lorentz 8261 self.previous_couplings = wanted_couplings 8262 else: 8263 self._curr_exporter.convert_model(self._curr_model, 8264 wanted_lorentz, 8265 wanted_couplings) 8266 8267 # move the old options to the flaglist system. 8268 if nojpeg: 8269 flaglist.append('nojpeg') 8270 if online: 8271 flaglist.append('online') 8272 8273 8274 8275 if self._export_format in ['NLO']: 8276 ## write fj_lhapdf_opts file 8277 # Create configuration file [path to executable] for amcatnlo 8278 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt') 8279 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path', 8280 'hepmc_path'] 8281 to_keep = {} 8282 for opt in opts_to_keep: 8283 if self.options[opt]: 8284 to_keep[opt] = self.options[opt] 8285 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \ 8286 to_keep = to_keep) 8287 8288 elif self._export_format in ['madevent', 'madweight']: 8289 # Create configuration file [path to executable] for madevent 8290 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt') 8291 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, 8292 to_keep={'mg5_path':MG5DIR}) 8293 8294 # Dedicated finalize function. 8295 self._curr_exporter.finalize(self._curr_matrix_elements, 8296 self.history, 8297 self.options, 8298 flaglist) 8299 8300 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']: 8301 logger.info('Output to directory ' + self._export_dir + ' done.') 8302 8303 if self._export_format in ['madevent', 'NLO']: 8304 logger.info('Type \"launch\" to generate events from this process, or see') 8305 logger.info(self._export_dir + '/README') 8306 logger.info('Run \"open index.html\" to see more information about this process.')
8307
8308 - def do_help(self, line):
8309 """ propose some usefull possible action """ 8310 8311 super(MadGraphCmd,self).do_help(line) 8312 8313 if line: 8314 return 8315 8316 if len(self.history) == 0: 8317 last_action_2 = 'mg5_start' 8318 last_action = 'mg5_start' 8319 else: 8320 args = self.history[-1].split() 8321 last_action = args[0] 8322 if len(args)>1: 8323 last_action_2 = '%s %s' % (last_action, args[1]) 8324 else: 8325 last_action_2 = 'none'
8326 8327 8328 8329 # Calculate decay width
8330 - def do_compute_widths(self, line, model=None, do2body=True, decaymodel=None):
8331 """Documented commands:Generate amplitudes for decay width calculation, with fixed 8332 number of final particles (called level) 8333 syntax; compute_widths particle [other particles] [--options=] 8334 8335 - particle/other particles can also be multiparticle name (can also be 8336 pid of the particle) 8337 8338 --body_decay=X [default=4.0025] allow to choose the precision. 8339 if X is an integer: compute all X body decay 8340 if X is a float <1: compute up to the time that total error < X 8341 if X is a float >1: stops at the first condition. 8342 8343 --path=X. Use a given file for the param_card. (default UFO built-in) 8344 8345 special argument: 8346 - skip_2body: allow to not consider those decay (use FR) 8347 - model: use the model pass in argument. 8348 8349 """ 8350 8351 8352 8353 self.change_principal_cmd('MadGraph') 8354 if '--nlo' not in line: 8355 warning_text = """Please note that the automatic computation of the width is 8356 only valid in narrow-width approximation and at tree-level.""" 8357 logger.warning(warning_text) 8358 8359 if not model: 8360 modelname = self._curr_model.get('modelpath+restriction') 8361 with misc.MuteLogger(['madgraph'], ['INFO']): 8362 model = import_ufo.import_model(modelname, decay=True) 8363 self._curr_model = model 8364 8365 if not isinstance(model, model_reader.ModelReader): 8366 model = model_reader.ModelReader(model) 8367 8368 if '--nlo' in line: 8369 # call SMWidth to calculate NLO Width 8370 self.compute_widths_SMWidth(line, model=model) 8371 return 8372 8373 # check the argument and return those in a dictionary format 8374 particles, opts = self.check_compute_widths(self.split_arg(line)) 8375 8376 if opts['path']: 8377 correct = True 8378 param_card = check_param_card.ParamCard(opts['path']) 8379 for param in param_card['decay']: 8380 if param.value == "auto": 8381 param.value = 1 8382 param.format = 'float' 8383 correct = False 8384 if not correct: 8385 if opts['output']: 8386 param_card.write(opts['output']) 8387 opts['path'] = opts['output'] 8388 else: 8389 param_card.write(opts['path']) 8390 8391 data = model.set_parameters_and_couplings(opts['path']) 8392 8393 8394 # find UFO particles linked to the require names. 8395 if do2body: 8396 skip_2body = True 8397 decay_info = {} 8398 for pid in particles: 8399 particle = model.get_particle(pid) 8400 if not hasattr(particle, 'partial_widths'): 8401 skip_2body = False 8402 break 8403 elif not decay_info: 8404 logger_mg.info('Get two body decay from FeynRules formula') 8405 decay_info[pid] = [] 8406 mass = abs(eval(str(particle.get('mass')), data).real) 8407 data = model.set_parameters_and_couplings(opts['path'], scale= mass) 8408 total = 0 8409 8410 # check if the value of alphas is set to zero and raise warning if appropriate 8411 if 'aS' in data and data['aS'] == 0 and particle.get('color') != 1: 8412 logger.warning("aS set to zero for this particle since the running is not defined for such low mass.") 8413 8414 for mode, expr in particle.partial_widths.items(): 8415 tmp_mass = mass 8416 for p in mode: 8417 try: 8418 value_mass = eval(str(p.mass), data) 8419 except Exception: 8420 # the p object can still be UFO reference. since the 8421 # mass name might hve change load back the MG5 one. 8422 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data) 8423 tmp_mass -= abs(value_mass) 8424 if tmp_mass <=0: 8425 continue 8426 8427 decay_to = [p.get('pdg_code') for p in mode] 8428 value = eval(expr,{'cmath':cmath},data).real 8429 if -1e-10 < value < 0: 8430 value = 0 8431 if -1e-5 < value < 0: 8432 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' % 8433 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 8434 value = 0 8435 elif value < 0: 8436 raise Exception('Partial width for %s > %s negative: %s' % \ 8437 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 8438 elif 0 < value < 0.1 and particle['color'] !=1: 8439 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 8440 % (particle.get('name'), value, decay_to)) 8441 value = 0 8442 8443 decay_info[particle.get('pdg_code')].append([decay_to, value]) 8444 total += value 8445 else: 8446 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 8447 opts['path'], opts['output']) 8448 if float(opts['body_decay']) == 2: 8449 return decay_info 8450 else: 8451 skip_2body = True 8452 8453 # 8454 # add info from decay module 8455 # 8456 8457 self.do_decay_diagram('%s %s' % (' '.join([repr(id) for id in particles]), 8458 ' '.join('--%s=%s' % (key,value) 8459 for key,value in opts.items() 8460 if key not in ['precision_channel']) 8461 ), skip_2body=skip_2body, model=decaymodel) 8462 8463 if self._curr_amps: 8464 logger.info('Pass to numerical integration for computing the widths:') 8465 else: 8466 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output']) 8467 8468 8469 8470 return decay_info 8471 8472 # Do the MadEvent integration!! 8473 with misc.TMP_directory(dir=os.getcwd()) as path: 8474 decay_dir = pjoin(path,'temp_decay') 8475 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir)) 8476 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]): 8477 self.exec_cmd('output madevent %s -f' % decay_dir,child=False) 8478 8479 #modify some parameter of the default run_card 8480 run_card = banner_module.RunCard(pjoin(decay_dir,'Cards','run_card.dat')) 8481 if run_card['ickkw']: 8482 run_card['ickkw'] = 0 8483 run_card['xqcut'] = 0 8484 run_card.remove_all_cut() 8485 run_card.write(pjoin(decay_dir,'Cards','run_card.dat')) 8486 8487 # Need to write the correct param_card in the correct place !!! 8488 if os.path.exists(opts['output']): 8489 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 8490 else: 8491 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 8492 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 8493 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat')) 8494 # call a ME interface and define as it as child for correct error handling 8495 me_cmd = madevent_interface.MadEventCmd(decay_dir) 8496 for name, val in self.options.items(): 8497 if name in me_cmd.options and me_cmd.options[name] != val: 8498 self.exec_cmd('set %s %s --no_save' % (name, val)) 8499 #me_cmd.options.update(self.options) 8500 #me_cmd.configure_run_mode(self.options['run_mode']) 8501 #self.define_child_cmd_interface(me_cmd, interface=False) 8502 me_cmd.model_name = self._curr_model['name'] #needed for mssm 8503 me_cmd.options['automatic_html_opening'] = False 8504 8505 me_opts=[('accuracy', opts['precision_channel']), # default 0.01 8506 ('points', 1000), 8507 ('iterations',9)] 8508 me_cmd.exec_cmd('survey decay -f %s' % ( 8509 " ".join(['--%s=%s' % val for val in me_opts])), 8510 postcmd=False) 8511 me_cmd.exec_cmd('combine_events', postcmd=False) 8512 #me_cmd.exec_cmd('store_events', postcmd=False) 8513 me_cmd.collect_decay_widths() 8514 me_cmd.do_quit('') 8515 # cleaning 8516 del me_cmd 8517 8518 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat')) 8519 8520 for pid in particles: 8521 width = param['decay'].get((pid,)).value 8522 particle = self._curr_model.get_particle(pid) 8523 #if particle['color'] !=1 and 0 < width.real < 0.1: 8524 # logger.warning("width of colored particle \"%s(%s)\" lower than QCD scale: %s. Set width to zero " 8525 # % (particle.get('name'), pid, width.real)) 8526 # width = 0 8527 8528 8529 if not pid in param['decay'].decay_table: 8530 continue 8531 if pid not in decay_info: 8532 decay_info[pid] = [] 8533 for BR in param['decay'].decay_table[pid]: 8534 if len(BR.lhacode) == 3 and skip_2body: 8535 continue 8536 if 0 < BR.value * width <0.1 and particle['color'] !=1: 8537 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 8538 % (particle.get('name'), BR.value * width, BR.lhacode[1:])) 8539 8540 continue 8541 8542 decay_info[pid].append([BR.lhacode[1:], BR.value * width]) 8543 8544 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 8545 opts['path'], opts['output']) 8546 8547 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 8548 check_param_card.convert_to_slha1(opts['output']) 8549 return decay_info
8550 8551 8552 8553 # Calculate decay width with SMWidth
8554 - def compute_widths_SMWidth(self, line, model=None):
8555 """Compute widths with SMWidth. 8556 """ 8557 8558 # check the argument and return those in a dictionary format 8559 particles, opts = self.check_compute_widths(self.split_arg(line)) 8560 8561 if opts['path']: 8562 correct = True 8563 param_card = check_param_card.ParamCard(opts['path']) 8564 for param in param_card['decay']: 8565 if param.value == "auto": 8566 param.value = 1 8567 param.format = 'float' 8568 correct = False 8569 if not correct: 8570 if opts['output']: 8571 param_card.write(opts['output']) 8572 opts['path'] = opts['output'] 8573 else: 8574 param_card.write(opts['path']) 8575 8576 if not model: 8577 model_path = self._curr_model.get('modelpath') 8578 model_name = self._curr_model.get('name') 8579 currmodel = self._curr_model 8580 else: 8581 model_path = model.get('modelpath') 8582 model_name = model.get('name') 8583 currmodel = model 8584 8585 if not os.path.exists(pjoin(model_path, 'SMWidth')): 8586 raise self.InvalidCmd("Model %s is not valid for computing NLO width with SMWidth"%model_name) 8587 8588 # determine the EW scheme 8589 externparam = [(param.lhablock.lower(),param.name.lower()) for param \ 8590 in currmodel.get('parameters')[('external',)]] 8591 8592 if ('sminputs','aewm1') in externparam: 8593 # alpha(MZ) scheme 8594 arg2 = "1" 8595 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam: 8596 # Gmu scheme 8597 arg2 = "2" 8598 else: 8599 raise Exception("Do not know the EW scheme in the model %s"%model_name) 8600 8601 #compile the code 8602 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')): 8603 logger.info('Compiling SMWidth. This has to be done only once and'+\ 8604 ' can take a couple of minutes.','$MG:BOLD') 8605 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth', 8606 'makefile_MW5')) 8607 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \ 8608 self.options_configuration['fortran_compiler'] 8609 if current != new: 8610 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current) 8611 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current) 8612 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current) 8613 misc.compile(cwd=pjoin(model_path, 'SMWidth')) 8614 8615 # look for the ident_card.dat 8616 identpath=" " 8617 carddir=os.path.dirname(opts['path']) 8618 if 'ident_card.dat' in os.listdir(carddir): 8619 identpath=pjoin(carddir,'ident_card.dat') 8620 #run the code 8621 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2], 8622 stdout=subprocess.PIPE, 8623 stdin=subprocess.PIPE, 8624 cwd=pjoin(model_path, 'SMWidth')).communicate() 8625 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I) 8626 width_list = pattern.findall(output.decode()) 8627 width_dict = {} 8628 for pid,width in width_list: 8629 width_dict[int(pid)] = float(width) 8630 8631 for pid in particles: 8632 if not pid in width_dict: 8633 width = 0 8634 else: 8635 width = width_dict[pid] 8636 param = param_card['decay'].get((pid,)) 8637 param.value = width 8638 param.format = 'float' 8639 if pid not in param_card['decay'].decay_table: 8640 continue 8641 del param_card['decay'].decay_table[pid] # reset the BR 8642 # write the output file. (the new param_card) 8643 if opts['output']: 8644 param_card.write(opts['output']) 8645 logger.info('Results are written in %s' % opts['output']) 8646 else: 8647 param_card.write(opts['path']) 8648 logger.info('Results are written in %s' % opts['path']) 8649 return
8650 8651 # Calculate decay width
8652 - def do_decay_diagram(self, line, skip_2body=False, model=None):
8653 """Not in help: Generate amplitudes for decay width calculation, with fixed 8654 number of final particles (called level) 8655 syntax; decay_diagram part_name level param_path 8656 args; part_name level param_path 8657 part_name = name of the particle you want to calculate width 8658 level = a.) when level is int, 8659 it means the max number of decay products 8660 b.) when level is float, 8661 it means the required precision for width. 8662 param_path = path for param_card 8663 (this is necessary to determine whether a channel is onshell or not) 8664 e.g. calculate width for higgs up to 2-body decays. 8665 calculate_width h 2 [path] 8666 N.B. param_card must be given so that the program knows which channel 8667 is on shell and which is not. 8668 8669 special argument: 8670 - skip_2body: allow to not consider those decay (use FR) 8671 - model: use the model pass in argument. 8672 """ 8673 8674 if model: 8675 self._curr_decaymodel = model 8676 8677 8678 args = self.split_arg(line) 8679 #check the validity of the arguments 8680 particles, args = self.check_decay_diagram(args) 8681 #print args 8682 pids = particles 8683 level = float(args['body_decay']) 8684 param_card_path = args['path'] 8685 min_br = float(args['min_br']) 8686 8687 # Reset amplitudes 8688 self._curr_amps = diagram_generation.AmplitudeList() 8689 self._curr_proc_defs = base_objects.ProcessDefinitionList() 8690 # Reset Helas matrix elements 8691 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 8692 # Reset _done_export, since we have new process 8693 self._done_export = False 8694 # Also reset _export_format and _export_dir 8695 self._export_format = None 8696 8697 8698 # Setup before find_channels 8699 if not model: 8700 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model, 8701 True) 8702 self._curr_decaymodel.read_param_card(param_card_path) 8703 else: 8704 self._curr_decaymodel = model 8705 model = self._curr_decaymodel 8706 8707 if isinstance(pids, int): 8708 pids = [pids] 8709 8710 first =True 8711 for part_nb,pid in enumerate(pids): 8712 part = self._curr_decaymodel.get_particle(pid) 8713 if part.get('width').lower() == 'zero': 8714 continue 8715 logger_mg.info('get decay diagram for %s' % part['name']) 8716 # Find channels as requested 8717 if level // 1 == level and level >1: 8718 level = int(level) 8719 self._curr_decaymodel.find_channels(part, level, min_br) 8720 if not skip_2body: 8721 amp = part.get_amplitudes(2) 8722 if amp: 8723 self._curr_amps.extend(amp) 8724 8725 for l in range(3, level+1): 8726 amp = part.get_amplitudes(l) 8727 if amp: 8728 self._curr_amps.extend(amp) 8729 else: 8730 max_level = level // 1 8731 if max_level < 2: 8732 max_level = 999 8733 precision = level % 1 8734 if first: 8735 model.find_all_channels(2,generate_abstract=False) 8736 first = False 8737 if not skip_2body: 8738 amp = part.get_amplitudes(2) 8739 if amp: 8740 self._curr_amps.extend(amp) 8741 clevel = 2 8742 while part.get('apx_decaywidth_err').real > precision: 8743 clevel += 1 8744 if clevel > max_level: 8745 logger_mg.info(' stop to %s body-decay. approximate error: %s' % 8746 (max_level, part.get('apx_decaywidth_err')) ) 8747 break 8748 if clevel > 3: 8749 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\ 8750 (part.get('apx_decaywidth_err'), clevel)) 8751 part.find_channels_nextlevel(model, min_br) 8752 #part.group_channels_2_amplitudes(clevel, model, min_br) 8753 amp = part.get_amplitudes(clevel) 8754 if amp: 8755 self._curr_amps.extend(amp) 8756 part.update_decay_attributes(False, True, True, model) 8757 8758 8759 # Set _generate_info 8760 if len(self._curr_amps) > 0: 8761 process = self._curr_amps[0]['process'].nice_string() 8762 #print process 8763 self._generate_info = process[9:] 8764 #print self._generate_info 8765 else: 8766 logger.info("No decay is found")
8767
8768 -class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd):
8769 """Temporary parser"""
8770 8771 #=============================================================================== 8772 # Command Parser 8773 #=============================================================================== 8774 # DRAW 8775 _draw_usage = "draw FILEPATH [options]\n" + \ 8776 "-- draw the diagrams in eps format\n" + \ 8777 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \ 8778 " Example: draw plot_dir . \n" 8779 _draw_parser = misc.OptionParser(usage=_draw_usage) 8780 _draw_parser.add_option("", "--horizontal", default=False, 8781 action='store_true', help="force S-channel to be horizontal") 8782 _draw_parser.add_option("", "--external", default=0, type='float', 8783 help="authorizes external particles to end at top or " + \ 8784 "bottom of diagram. If bigger than zero this tune the " + \ 8785 "length of those line.") 8786 _draw_parser.add_option("", "--max_size", default=1.5, type='float', 8787 help="this forbids external line bigger than max_size") 8788 _draw_parser.add_option("", "--non_propagating", default=True, \ 8789 dest="contract_non_propagating", action='store_false', 8790 help="avoid contractions of non propagating lines") 8791 _draw_parser.add_option("", "--add_gap", default=0, type='float', \ 8792 help="set the x-distance between external particles") 8793 8794 # LAUNCH PROGRAM 8795 _launch_usage = "launch [DIRPATH] [options]\n" + \ 8796 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \ 8797 " By default DIRPATH is the latest created directory \n" + \ 8798 " (for pythia8, it should be the Pythia 8 main directory) \n" + \ 8799 " Example: launch PROC_sm_1 --name=run2 \n" + \ 8800 " Example: launch ../pythia8 \n" 8801 _launch_parser = misc.OptionParser(usage=_launch_usage) 8802 _launch_parser.add_option("-f", "--force", default=False, action='store_true', 8803 help="Use the card present in the directory in order to launch the different program") 8804 _launch_parser.add_option("-n", "--name", default='', type='str', 8805 help="Provide a name to the run (for madevent run)") 8806 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true', 8807 help="submit the job on the cluster") 8808 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true', 8809 help="submit the job on multicore core") 8810 8811 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true', 8812 help="Use Interactive Console [if available]") 8813 _launch_parser.add_option("-s", "--laststep", default='', 8814 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]") 8815 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true', 8816 help="Run the reweight module (reweighting by different model parameter") 8817 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', 8818 help="Run the madspin package")
8819 8820 #=============================================================================== 8821 # Interface for customize question. 8822 #=============================================================================== 8823 -class AskforCustomize(cmd.SmartQuestion):
8824 """A class for asking a question where in addition you can have the 8825 set command define and modifying the param_card/run_card correctly""" 8826
8827 - def __init__(self, question, allow_arg=[], default=None, 8828 mother_interface=None, *arg, **opt):
8829 8830 model_path = mother_interface._curr_model.get('modelpath') 8831 #2) Import the option available in the model 8832 ufo_model = ufomodels.load_model(model_path) 8833 self.all_categories = ufo_model.build_restrict.all_categories 8834 8835 question = self.get_question() 8836 # determine the possible value and how they are linked to the restriction 8837 #options. 8838 allow_arg = ['0'] 8839 self.name2options = {} 8840 for category in self.all_categories: 8841 for options in category: 8842 if not options.first: 8843 continue 8844 self.name2options[str(len(allow_arg))] = options 8845 self.name2options[options.name.replace(' ','')] = options 8846 allow_arg.append(len(allow_arg)) 8847 allow_arg.append('done') 8848 8849 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8850 8851 8852
8853 - def default(self, line):
8854 """Default action if line is not recognized""" 8855 8856 line = line.strip() 8857 args = line.split() 8858 if line == '' and self.default_value is not None: 8859 self.value = self.default_value 8860 # check if input is a file 8861 elif hasattr(self, 'do_%s' % args[0]): 8862 self.do_set(' '.join(args[1:])) 8863 elif line.strip() != '0' and line.strip() != 'done' and \ 8864 str(line) != 'EOF' and line.strip() in self.allow_arg: 8865 option = self.name2options[line.strip()] 8866 option.status = not option.status 8867 self.value = 'repeat' 8868 else: 8869 self.value = line 8870 8871 return self.all_categories
8872
8873 - def reask(self, reprint_opt=True):
8874 """ """ 8875 reprint_opt = True 8876 self.question = self.get_question() 8877 cmd.SmartQuestion.reask(self, reprint_opt)
8878
8879 - def do_set(self, line):
8880 """ """ 8881 self.value = 'repeat' 8882 8883 args = line.split() 8884 if args[0] not in self.name2options: 8885 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' % 8886 (args[0], ', '.join(list(self.name2options.keys())) )) 8887 return 8888 elif len(args) != 2: 8889 logger.warning('Invalid set command. Not correct number of argument') 8890 return 8891 8892 8893 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']: 8894 self.name2options[args[0]].status = True 8895 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']: 8896 self.name2options[args[0]].status = False 8897 else: 8898 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8899 8900 8901
8902 - def get_question(self):
8903 """define the current question.""" 8904 question = '' 8905 i=0 8906 for category in self.all_categories: 8907 question += category.name + ':\n' 8908 for options in category: 8909 if not options.first: 8910 continue 8911 i+=1 8912 question += ' %s: %s [%s]\n' % (i, options.name, 8913 options.display(options.status)) 8914 question += 'Enter a number to change it\'s status or press enter to validate.\n' 8915 question += 'For scripting this function, please type: \'help\'' 8916 return question
8917 8918
8919 - def complete_set(self, text, line, begidx, endidx):
8920 """ Complete the set command""" 8921 signal.alarm(0) # avoid timer if any 8922 args = self.split_arg(line[0:begidx]) 8923 8924 if len(args) == 1: 8925 possibilities = [x for x in self.name2options if not x.isdigit()] 8926 return self.list_completion(text, possibilities, line) 8927 else: 8928 return self.list_completion(text,['True', 'False'], line)
8929 8930
8931 - def do_help(self, line):
8932 '''help message''' 8933 8934 print('This allows you to optimize your model to your needs.') 8935 print('Enter the number associate to the possible restriction/add-on') 8936 print(' to change the status of this restriction/add-on.') 8937 print('') 8938 print('In order to allow scripting of this function you can use the ') 8939 print('function \'set\'. This function takes two argument:') 8940 print('set NAME VALUE') 8941 print(' NAME is the description of the option where you remove all spaces') 8942 print(' VALUE is either True or False') 8943 print(' Example: For the question') 8944 print(''' sm customization: 8945 1: diagonal ckm [True] 8946 2: c mass = 0 [True] 8947 3: b mass = 0 [False] 8948 4: tau mass = 0 [False] 8949 5: muon mass = 0 [True] 8950 6: electron mass = 0 [True] 8951 Enter a number to change it's status or press enter to validate.''') 8952 print(''' you can answer by''') 8953 print(' set diagonalckm False') 8954 print(' set taumass=0 True')
8955
8956 - def cmdloop(self, intro=None):
8957 cmd.SmartQuestion.cmdloop(self, intro) 8958 return self.all_categories
8959 8960 8961 8962 #=============================================================================== 8963 # __main__ 8964 #=============================================================================== 8965 8966 if __name__ == '__main__': 8967 8968 run_option = sys.argv 8969 if len(run_option) > 1: 8970 # The first argument of sys.argv is the name of the program 8971 input_file = open(run_option[1], 'rU') 8972 cmd_line = MadGraphCmd(stdin=input_file) 8973 cmd_line.use_rawinput = False #put it in non interactive mode 8974 cmd_line.cmdloop() 8975 else: 8976 # Interactive mode 8977 MadGraphCmd().cmdloop() 8978