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==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 try: 3188 # Negative coupling order contraints can be given on at most one 3189 # coupling order (and either in squared orders or orders, not both) 3190 if len([1 for val in list(myprocdef.get('orders').values())+\ 3191 list(myprocdef.get('squared_orders').values()) if val<0])>1: 3192 raise MadGraph5Error("Negative coupling order constraints"+\ 3193 " can only be given on one type of coupling and either on"+\ 3194 " squared orders or amplitude orders, not both.") 3195 3196 if myprocdef.get_ninitial() ==1 and myprocdef.get('squared_orders'): 3197 logger.warning('''Computation of interference term with decay is not 100% validated. 3198 Please check carefully your result. 3199 One suggestion is also to compare the generation of your process with and without 3200 set group_subprocesses True 3201 (to write Before the generate command) 3202 ''') 3203 3204 cpu_time1 = time.time() 3205 3206 # Generate processes 3207 if self.options['group_subprocesses'] == 'Auto': 3208 collect_mirror_procs = True 3209 else: 3210 collect_mirror_procs = self.options['group_subprocesses'] 3211 ignore_six_quark_processes = \ 3212 self.options['ignore_six_quark_processes'] if \ 3213 "ignore_six_quark_processes" in self.options \ 3214 else [] 3215 3216 myproc = diagram_generation.MultiProcess(myprocdef, 3217 collect_mirror_procs = collect_mirror_procs, 3218 ignore_six_quark_processes = ignore_six_quark_processes, 3219 optimize=optimize, diagram_filter=diagram_filter) 3220 3221 3222 for amp in myproc.get('amplitudes'): 3223 if amp not in self._curr_amps: 3224 self._curr_amps.append(amp) 3225 elif warning_duplicate: 3226 raise self.InvalidCmd( "Duplicate process %s found. Please check your processes." % \ 3227 amp.nice_string_processes()) 3228 except Exception: 3229 self._curr_proc_defs.pop(-1) 3230 raise 3231 3232 # Reset _done_export, since we have new process 3233 self._done_export = False 3234 3235 cpu_time2 = time.time() 3236 3237 nprocs = len(myproc.get('amplitudes')) 3238 ndiags = sum([amp.get_number_of_diagrams() for \ 3239 amp in myproc.get('amplitudes')]) 3240 3241 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 3242 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 3243 ndiags = sum([amp.get_number_of_diagrams() for \ 3244 amp in self._curr_amps]) 3245 logger.info("Total: %i processes with %i diagrams" % \ 3246 (len(self._curr_amps), ndiags))
3247
3248 - def add_model(self, args):
3249 """merge two model""" 3250 3251 model_path = args[0] 3252 recreate = ('--recreate' in args) 3253 if recreate: 3254 args.remove('--recreate') 3255 keep_decay = ('--keep_decay' in args) 3256 if keep_decay: 3257 args.remove('--keep_decay') 3258 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')] 3259 if output_dir: 3260 output_dir = output_dir[0] 3261 recreate = True 3262 restrict_name = '' 3263 args.remove('--output=%s' % output_dir) 3264 else: 3265 name = os.path.basename(self._curr_model.get('modelpath')) 3266 restrict_name = self._curr_model.get('restrict_name') 3267 output_dir = pjoin(MG5DIR, 'models', '%s__%s' % (name, 3268 os.path.basename(model_path))) 3269 3270 if os.path.exists(output_dir): 3271 if recreate: 3272 shutil.rmtree(output_dir) 3273 else: 3274 logger.info('Model already created! Loading it from %s' % output_dir) 3275 oldmodel = self._curr_model.get('modelpath') 3276 new_model_name = output_dir 3277 if restrict_name: 3278 new_model_name = '%s-%s' % (output_dir, restrict_name) 3279 try: 3280 self.exec_cmd('import model %s' % new_model_name, errorhandling=False, 3281 printcmd=False, precmd=True, postcmd=True) 3282 except Exception as error: 3283 logger.debug('fail to load model %s with error:\n %s' % (output_dir, error)) 3284 logger.warning('Fail to load the model. Restore previous model') 3285 self.exec_cmd('import model %s' % oldmodel, errorhandling=False, 3286 printcmd=False, precmd=True, postcmd=True) 3287 raise Exception('Invalid Model! Please retry with the option \'--recreate\'.') 3288 else: 3289 return 3290 3291 #Need to do the work!!! 3292 import models.usermod as usermod 3293 base_model = copy.deepcopy(usermod.UFOModel(self._curr_model.get('modelpath'))) 3294 3295 identify = dict(tuple(a.split('=')) for a in args if '=' in a) 3296 base_model.add_model(path=model_path, identify_particles=identify) 3297 base_model.write(output_dir) 3298 3299 if keep_decay and os.path.exists(pjoin(self._curr_model.get('modelpath'), 'decays.py')): 3300 base_model.mod_file(pjoin(pjoin(self._curr_model.get('modelpath'), 'decays.py')), 3301 pjoin(pjoin(output_dir, 'decays.py'))) 3302 3303 new_model_name = output_dir 3304 if restrict_name: 3305 new_model_name = '%s-%s' % (output_dir, restrict_name) 3306 3307 if 'modelname' in self.history.get('full_model_line'): 3308 opts = '--modelname' 3309 else: 3310 opts='' 3311 self.exec_cmd('import model %s %s' % (new_model_name, opts), errorhandling=False, 3312 printcmd=False, precmd=True, postcmd=True)
3313 3314
3315 - def do_convert(self, line):
3316 """convert model FULLPATH 3317 modify (in place) the UFO model to make it compatible with both python2 and python3 3318 """ 3319 3320 args = self.split_arg(line) 3321 if hasattr(self, 'do_convert_%s' % args[0]): 3322 getattr(self, 'do_convert_%s' % args[0])(args[1:])
3323
3324 - def do_convert_model(self, args):
3325 "Not in help: shortcut for convert model" 3326 3327 if not os.path.isdir(args[0]): 3328 raise Exception( 'model to convert need to provide a full path') 3329 model_dir = args[0] 3330 3331 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?', 3332 'y', ['y','n']) 3333 if answer != 'y': 3334 return 3335 3336 #Object_library 3337 text = open(pjoin(model_dir, 'object_library.py')).read() 3338 #(.iteritems() -> .items()) 3339 text = text.replace('.iteritems()', '.items()') 3340 # raise UFOError, "" -> raise UFOError() 3341 text = re.sub('raise (\w+)\s*,\s*["\']([^"]+)["\']', 3342 'raise \g<1>("\g<2>")', text) 3343 text = open(pjoin(model_dir, 'object_library.py'),'w').write(text) 3344 3345 # write_param_card.dat -> copy the one of the sm model 3346 files.cp(pjoin(MG5DIR, 'models','sm','write_param_card.py'), 3347 pjoin(model_dir, 'write_param_card.py')) 3348 3349 # __init__.py check that function_library and object_library are imported 3350 text = open(pjoin(model_dir, '__init__.py')).read() 3351 mod = False 3352 to_check = ['object_library', 'function_library'] 3353 for lib in to_check: 3354 if 'import %s' % lib in text: 3355 continue 3356 mod = True 3357 text = "import %s \n" % lib + text 3358 if mod: 3359 open(pjoin(model_dir, '__init__.py'),'w').write(text)
3360 3361 3362 3363 3364 3365 # Define a multiparticle label
3366 - def do_define(self, line, log=True):
3367 """Define a multiparticle""" 3368 3369 self.avoid_history_duplicate('define %s' % line, ['define']) 3370 if not self._curr_model: 3371 self.do_import('model sm') 3372 self.history.append('define %s' % line) 3373 if not self._curr_model['case_sensitive']: 3374 # Particle names lowercase 3375 line = line.lower() 3376 # Make sure there are spaces around =, | and / 3377 line = line.replace("=", " = ") 3378 line = line.replace("|", " | ") 3379 line = line.replace("/", " / ") 3380 args = self.split_arg(line) 3381 # check the validity of the arguments 3382 self.check_define(args) 3383 3384 label = args[0] 3385 remove_ids = [] 3386 try: 3387 remove_index = args.index("/") 3388 except ValueError: 3389 pass 3390 else: 3391 remove_ids = args[remove_index + 1:] 3392 args = args[:remove_index] 3393 3394 pdg_list = self.extract_particle_ids(args[1:]) 3395 remove_list = self.extract_particle_ids(remove_ids) 3396 pdg_list = [p for p in pdg_list if p not in remove_list] 3397 3398 self.optimize_order(pdg_list) 3399 self._multiparticles[label] = pdg_list 3400 if log: 3401 logger.info("Defined multiparticle %s" % \ 3402 self.multiparticle_string(label))
3403 3404 # Display
3405 - def do_display(self, line, output=sys.stdout):
3406 """Display current internal status""" 3407 3408 args = self.split_arg(line) 3409 #check the validity of the arguments 3410 self.check_display(args) 3411 3412 if args[0] == 'diagrams': 3413 self.draw(' '.join(args[1:])) 3414 3415 if args[0] == 'particles' and len(args) == 1: 3416 propagating_particle = [] 3417 nb_unpropagating = 0 3418 for particle in self._curr_model['particles']: 3419 if particle.get('propagating'): 3420 propagating_particle.append(particle) 3421 else: 3422 nb_unpropagating += 1 3423 3424 print("Current model contains %i particles:" % \ 3425 len(propagating_particle)) 3426 part_antipart = [part for part in propagating_particle \ 3427 if not part['self_antipart']] 3428 part_self = [part for part in propagating_particle \ 3429 if part['self_antipart']] 3430 for part in part_antipart: 3431 print(part['name'] + '/' + part['antiname'], end=' ') 3432 print('') 3433 for part in part_self: 3434 print(part['name'], end=' ') 3435 print('') 3436 if nb_unpropagating: 3437 print('In addition of %s un-physical particle mediating new interactions.' \ 3438 % nb_unpropagating) 3439 3440 elif args[0] == 'particles': 3441 for arg in args[1:]: 3442 if arg.isdigit() or (arg[0] == '-' and arg[1:].isdigit()): 3443 particle = self._curr_model.get_particle(abs(int(arg))) 3444 else: 3445 particle = self._curr_model['particles'].find_name(arg) 3446 if not particle: 3447 raise self.InvalidCmd('no particle %s in current model' % arg) 3448 3449 print("Particle %s has the following properties:" % particle.get_name()) 3450 print(str(particle)) 3451 3452 elif args[0] == 'interactions' and len(args) == 1: 3453 text = "Current model contains %i interactions\n" % \ 3454 len(self._curr_model['interactions']) 3455 for i, inter in enumerate(self._curr_model['interactions']): 3456 text += str(i+1) + ':' 3457 for part in inter['particles']: 3458 if part['is_part']: 3459 text += part['name'] 3460 else: 3461 text += part['antiname'] 3462 text += " " 3463 text += " ".join(order + '=' + str(inter['orders'][order]) \ 3464 for order in inter['orders']) 3465 text += '\n' 3466 pydoc.pager(text) 3467 3468 elif args[0] == 'interactions' and len(args)==2 and args[1].isdigit(): 3469 for arg in args[1:]: 3470 if int(arg) > len(self._curr_model['interactions']): 3471 raise self.InvalidCmd('no interaction %s in current model' % arg) 3472 if int(arg) == 0: 3473 print('Special interactions which identify two particles') 3474 else: 3475 print("Interactions %s has the following property:" % arg) 3476 print(self._curr_model['interactions'][int(arg)-1]) 3477 3478 elif args[0] == 'interactions': 3479 request_part = args[1:] 3480 text = '' 3481 for i, inter in enumerate(self._curr_model['interactions']): 3482 present_part = [part['is_part'] and part['name'] or part['antiname'] 3483 for part in inter['particles'] 3484 if (part['is_part'] and part['name'] in request_part) or 3485 (not part['is_part'] and part['antiname'] in request_part)] 3486 if len(present_part) < len(request_part): 3487 continue 3488 # check that all particles are selected at least once 3489 if set(present_part) != set(request_part): 3490 continue 3491 # check if a particle is asked more than once 3492 if len(request_part) > len(set(request_part)): 3493 for p in request_part: 3494 if request_part.count(p) > present_part.count(p): 3495 continue 3496 3497 name = str(i+1) + ' : ' 3498 for part in inter['particles']: 3499 if part['is_part']: 3500 name += part['name'] 3501 else: 3502 name += part['antiname'] 3503 name += " " 3504 text += "\nInteractions %s has the following property:\n" % name 3505 text += str(self._curr_model['interactions'][i]) 3506 3507 text += '\n' 3508 print(name) 3509 if text =='': 3510 text += 'No matching for any interactions' 3511 pydoc.pager(text) 3512 3513 3514 elif args[0] == 'parameters' and len(args) == 1: 3515 text = "Current model contains %i parameters\n" % \ 3516 sum([len(part) for part in 3517 self._curr_model['parameters'].values()]) 3518 keys = list(self._curr_model['parameters'].keys()) 3519 def key_sort(x, y): 3520 if ('external',) == x: 3521 return -1 3522 elif ('external',) == y: 3523 return +1 3524 elif len(x) < len(y): 3525 return -1 3526 else: 3527 return 1
3528 keys.sort(key_sort) 3529 for key in keys: 3530 item = self._curr_model['parameters'][key] 3531 text += '\nparameter type: %s\n' % str(key) 3532 for value in item: 3533 if hasattr(value, 'expr'): 3534 if value.value is not None: 3535 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3536 else: 3537 text+= ' %s = %s\n' % (value.name, value.expr) 3538 else: 3539 if value.value is not None: 3540 text+= ' %s = %s\n' % (value.name, value.value) 3541 else: 3542 text+= ' %s \n' % (value.name) 3543 pydoc.pager(text) 3544 3545 elif args[0] == 'processes': 3546 for amp in self._curr_amps: 3547 print(amp.nice_string_processes()) 3548 3549 elif args[0] == 'diagrams_text': 3550 text = "\n".join([amp.nice_string() for amp in self._curr_amps]) 3551 pydoc.pager(text) 3552 3553 elif args[0] == 'multiparticles': 3554 print('Multiparticle labels:') 3555 for key in self._multiparticles: 3556 print(self.multiparticle_string(key)) 3557 3558 elif args[0] == 'coupling_order': 3559 hierarchy = list(self._curr_model['order_hierarchy'].items()) 3560 #self._curr_model.get_order_hierarchy().items() 3561 def order(first, second): 3562 if first[1] < second[1]: 3563 return -1 3564 else: 3565 return 1
3566 hierarchy.sort(order) 3567 for order in hierarchy: 3568 print(' %s : weight = %s' % order) 3569 3570 elif args[0] == 'couplings' and len(args) == 1: 3571 if self._model_v4_path: 3572 print('No couplings information available in V4 model') 3573 return 3574 text = '' 3575 text = "Current model contains %i couplings\n" % \ 3576 sum([len(part) for part in 3577 self._curr_model['couplings'].values()]) 3578 keys = list(self._curr_model['couplings'].keys()) 3579 def key_sort(x, y): 3580 if ('external',) == x: 3581 return -1 3582 elif ('external',) == y: 3583 return +1 3584 elif len(x) < len(y): 3585 return -1 3586 else: 3587 return 1 3588 keys.sort(key_sort) 3589 for key in keys: 3590 item = self._curr_model['couplings'][key] 3591 text += '\ncouplings type: %s\n' % str(key) 3592 for value in item: 3593 if value.value is not None: 3594 text+= ' %s = %s = %s\n' % (value.name, value.expr ,value.value) 3595 else: 3596 text+= ' %s = %s\n' % (value.name, value.expr) 3597 3598 pydoc.pager(text) 3599 3600 elif args[0] == 'couplings': 3601 if self._model_v4_path: 3602 print('No couplings information available in V4 model') 3603 return 3604 3605 try: 3606 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3607 print('Note that this is the UFO informations.') 3608 print(' "display couplings" present the actual definition') 3609 print('prints the current states of mode') 3610 print(eval('ufomodel.couplings.%s.nice_string()'%args[1])) 3611 except Exception: 3612 raise self.InvalidCmd('no couplings %s in current model' % args[1]) 3613 3614 elif args[0] == 'lorentz': 3615 print('in lorentz') 3616 if self._model_v4_path: 3617 print('No lorentz information available in V4 model') 3618 return 3619 elif len(args) == 1: 3620 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3621 print(dir(ufomodel.lorentz)) 3622 return 3623 try: 3624 ufomodel = ufomodels.load_model(self._curr_model.get('name')) 3625 print(getattr(ufomodel.lorentz, args[1]).nice_string()) 3626 except Exception as error: 3627 raise 3628 logger.info(str(error)) 3629 raise self.InvalidCmd('no lorentz %s in current model' % args[1]) 3630 3631 elif args[0] == 'checks': 3632 outstr = '' 3633 if self._comparisons: 3634 comparisons = self._comparisons[0] 3635 if len(args) > 1 and args[1] == 'failed': 3636 comparisons = [c for c in comparisons if not c['passed']] 3637 outstr += "Process check results:" 3638 for comp in comparisons: 3639 outstr += "\n%s:" % comp['process'].nice_string() 3640 outstr += "\n Phase space point: (px py pz E)" 3641 for i, p in enumerate(comp['momenta']): 3642 outstr += "\n%2s %+.9e %+.9e %+.9e %+.9e" % tuple([i] + p) 3643 outstr += "\n Permutation values:" 3644 outstr += "\n " + str(comp['values']) 3645 if comp['passed']: 3646 outstr += "\n Process passed (rel. difference %.9e)" % \ 3647 comp['difference'] 3648 else: 3649 outstr += "\n Process failed (rel. difference %.9e)" % \ 3650 comp['difference'] 3651 3652 used_aloha = sorted(self._comparisons[1]) 3653 if used_aloha: 3654 outstr += "\nChecked ALOHA routines:" 3655 for aloha in used_aloha: 3656 aloha_str = aloha[0] 3657 if aloha[1]: 3658 aloha_str += 'C' + 'C'.join([str(ia) for ia in aloha[1]]) 3659 aloha_str += "_%d" % aloha[2] 3660 outstr += "\n" + aloha_str 3661 3662 outstr += '\n' 3663 for cms_check in self._cms_checks: 3664 outstr += '*'*102+'\n' 3665 outstr += 'Complex Mass Scheme check:\n' 3666 outstr += ' -> check %s\n'%cms_check['line'] 3667 outstr += '*'*102+'\n' 3668 tmp_options = copy.copy(cms_check['options']) 3669 tmp_options['show_plot']=False 3670 outstr += process_checks.output_complex_mass_scheme( 3671 cms_check['cms_result'], cms_check['output_path'], 3672 tmp_options, self._curr_model) + '\n' 3673 outstr += '*'*102+'\n\n' 3674 pydoc.pager(outstr) 3675 3676 elif args[0] == 'options': 3677 if len(args) == 1: 3678 to_print = lambda name: True 3679 else: 3680 to_print = lambda name: any(poss in name for poss in args[1:]) 3681 3682 outstr = " MadGraph5_aMC@NLO Options \n" 3683 outstr += " ---------------- \n" 3684 keys = list(self.options_madgraph.keys()) 3685 keys.sort() 3686 for key in keys: 3687 if not to_print(key): 3688 continue 3689 default = self.options_madgraph[key] 3690 value = self.options[key] 3691 if value == default: 3692 outstr += " %25s \t:\t%s\n" % (key,value) 3693 else: 3694 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3695 outstr += "\n" 3696 outstr += " MadEvent Options \n" 3697 outstr += " ---------------- \n" 3698 keys = list(self.options_madevent.keys()) 3699 keys.sort() 3700 for key in keys: 3701 if not to_print(key): 3702 continue 3703 default = self.options_madevent[key] 3704 value = self.options[key] 3705 if value == default: 3706 outstr += " %25s \t:\t%s\n" % (key,value) 3707 else: 3708 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3709 outstr += "\n" 3710 outstr += " Configuration Options \n" 3711 outstr += " --------------------- \n" 3712 keys = list(self.options_configuration.keys()) 3713 keys.sort() 3714 for key in keys: 3715 if not to_print(key): 3716 continue 3717 default = self.options_configuration[key] 3718 value = self.options[key] 3719 if value == default: 3720 outstr += " %25s \t:\t%s\n" % (key,value) 3721 else: 3722 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 3723 3724 output.write(outstr) 3725 elif args[0] in ["variable"]: 3726 super(MadGraphCmd, self).do_display(line, output) 3727 3728 elif args[0] in ["modellist", "model_list"]: 3729 outstr = [] 3730 template = """%-30s | %-60s | %-25s """ 3731 outstr.append(template % ('name', 'restriction', 'comment')) 3732 outstr.append('*'*150) 3733 already_done = [] 3734 #local model #use 3735 3736 if 'PYTHONPATH' in os.environ: 3737 pythonpath = os.environ['PYTHONPATH'].split(':') 3738 else: 3739 pythonpath = [] 3740 3741 for base in [pjoin(MG5DIR,'models')] + pythonpath: 3742 if not os.path.exists(base): 3743 continue 3744 file_cond = lambda p : os.path.exists(pjoin(base,p,'particles.py')) 3745 mod_name = lambda name: name 3746 3747 model_list = [mod_name(name) for name in \ 3748 self.path_completion('', 3749 base, 3750 only_dirs = True) \ 3751 if file_cond(name)] 3752 3753 for model_name in model_list: 3754 if model_name in already_done: 3755 continue 3756 all_name = self.find_restrict_card(model_name, 3757 base_dir=base, 3758 online=False) 3759 already_done.append(model_name) 3760 restrict = [name[len(model_name):] for name in all_name 3761 if len(name)>len(model_name)] 3762 3763 comment = 'from models directory' 3764 if base != pjoin(MG5DIR,'models'): 3765 comment = 'from PYTHONPATH: %s' % base 3766 lrestrict = ', '.join(restrict) 3767 if len(lrestrict) > 50: 3768 for i in range(-1,-len(restrict), -1): 3769 lrestrict = ', '.join(restrict[:i]) 3770 if len(lrestrict)<50: 3771 break 3772 outstr.append(template % (model_name, lrestrict, comment)) 3773 outstr.append(template % ('', ', '.join(restrict[i:]), '')) 3774 else: 3775 outstr.append(template % (model_name, ', '.join(restrict), comment)) 3776 outstr.append('*'*150) 3777 3778 # Still have to add the one with internal information 3779 for model_name in self._online_model: 3780 if model_name in already_done: 3781 continue 3782 restrict = [tag for tag in self._online_model[model_name]] 3783 comment = 'automatic download from MG5aMC server' 3784 outstr.append(template % (model_name, ','.join(restrict), comment)) 3785 already_done.append(model_name) 3786 3787 outstr.append('*'*150) 3788 # other downloadable model 3789 data = import_ufo.get_model_db() 3790 self._online_model2 = [] 3791 for line in data: 3792 model_name, path = line.decode().split() 3793 if model_name in already_done: 3794 continue 3795 if model_name.endswith('_v4'): 3796 continue 3797 3798 if 'feynrules' in path: 3799 comment = 'automatic download from FeynRules website' 3800 elif 'madgraph.phys' in path: 3801 comment = 'automatic download from MG5aMC server' 3802 else: 3803 comment = 'automatic download.' 3804 restrict = 'unknown' 3805 outstr.append(template % (model_name, restrict, comment)) 3806 self._online_model2.append(model_name) 3807 pydoc.pager('\n'.join(outstr)) 3808 3809
3810 - def multiparticle_string(self, key):
3811 """Returns a nicely formatted string for the multiparticle""" 3812 3813 if self._multiparticles[key] and \ 3814 isinstance(self._multiparticles[key][0], list): 3815 return "%s = %s" % (key, "|".join([" ".join([self._curr_model.\ 3816 get('particle_dict')[part_id].get_name() \ 3817 for part_id in id_list]) \ 3818 for id_list in self._multiparticles[key]])) 3819 else: 3820 return "%s = %s" % (key, " ".join([self._curr_model.\ 3821 get('particle_dict')[part_id].get_name() \ 3822 for part_id in self._multiparticles[key]]))
3823
3824 - def do_tutorial(self, line):
3825 """Activate/deactivate the tutorial mode.""" 3826 3827 args = self.split_arg(line) 3828 self.check_tutorial(args) 3829 tutorials = {'MadGraph5': logger_tuto, 3830 'aMCatNLO': logger_tuto_nlo, 3831 'MadLoop': logger_tuto_madloop} 3832 try: 3833 tutorials[args[0]].setLevel(logging.INFO) 3834 for mode in [m for m in tutorials.keys() if m != args[0]]: 3835 tutorials[mode].setLevel(logging.ERROR) 3836 except KeyError: 3837 logger_tuto.info("\n\tThanks for using the tutorial!") 3838 logger_tuto.setLevel(logging.ERROR) 3839 logger_tuto_nlo.info("\n\tThanks for using the aMC@NLO tutorial!") 3840 logger_tuto_nlo.setLevel(logging.ERROR) 3841 logger_tuto_madloop.info("\n\tThanks for using MadLoop tutorial!") 3842 logger_tuto_madloop.setLevel(logging.ERROR) 3843 3844 if not self._mgme_dir: 3845 logger_tuto.info(\ 3846 "\n\tWarning: To use all features in this tutorial, " + \ 3847 "please run from a" + \ 3848 "\n\t valid MG_ME directory.")
3849 3850 3851
3852 - def draw(self, line,selection='all',Dtype=''):
3853 """ draw the Feynman diagram for the given process. 3854 Dtype refers to born, real or loop""" 3855 3856 args = self.split_arg(line) 3857 # Check the validity of the arguments 3858 self.check_draw(args) 3859 3860 # Check if we plot a decay chain 3861 if any([isinstance(a, diagram_generation.DecayChainAmplitude) for \ 3862 a in self._curr_amps]) and not self._done_export: 3863 warn = 'WARNING: You try to draw decay chain diagrams without first running output.\n' 3864 warn += '\t The decay processes will be drawn separately' 3865 logger.warning(warn) 3866 3867 (options, args) = _draw_parser.parse_args(args) 3868 if madgraph.iolibs.drawing_eps.EpsDiagramDrawer.april_fool: 3869 options.horizontal = True 3870 options.external = True 3871 options.max_size = 0.3 3872 options.add_gap = 0.5 3873 options = draw_lib.DrawOption(options) 3874 start = time.time() 3875 3876 3877 3878 3879 # Collect amplitudes 3880 amplitudes = diagram_generation.AmplitudeList() 3881 3882 for amp in self._curr_amps: 3883 amplitudes.extend(amp.get_amplitudes()) 3884 3885 for amp in amplitudes: 3886 filename = pjoin(args[0], 'diagrams_' + \ 3887 amp.get('process').shell_string() + ".eps") 3888 3889 if selection=='all' and Dtype != 'loop': 3890 diags=amp.get('diagrams') 3891 elif selection=='born': 3892 diags=amp.get('born_diagrams') 3893 elif selection=='loop' or Dtype == 'loop': 3894 diags=base_objects.DiagramList([d for d in 3895 amp.get('loop_diagrams') if d.get('type')>0]) 3896 if len(diags) > 5000: 3897 logger.warning('Displaying only the first 5000 diagrams') 3898 diags = base_objects.DiagramList(diags[:5000]) 3899 3900 plot = draw.MultiEpsDiagramDrawer(diags, 3901 filename, 3902 model=self._curr_model, 3903 amplitude=amp, 3904 legend=amp.get('process').input_string(), 3905 diagram_type=Dtype) 3906 3907 3908 logger.info("Drawing " + \ 3909 amp.get('process').nice_string()) 3910 plot.draw(opt=options) 3911 logger.info("Wrote file " + filename) 3912 self.exec_cmd('open %s' % filename) 3913 3914 stop = time.time() 3915 logger.info('time to draw %s' % (stop - start))
3916 3917 # Perform checks
3918 - def do_check(self, line):
3919 """Check a given process or set of processes""" 3920 3921 def create_lambda_values_list(lower_bound, N): 3922 """ Returns a list of values spanning the range [1.0, lower_bound] with 3923 lower_bound < 1.0 and with each interval [1e-i, 1e-(i+1)] covered 3924 by N values uniformly distributed. For example, lower_bound=1e-2 3925 and N=5 returns: 3926 [1, 0.8, 0.6, 0.4, 0.2, 0.1, 0.08, 0.06, 0.04, 0.02, 0.01]""" 3927 3928 lCMS_values = [1] 3929 exp = 0 3930 n = 0 3931 while lCMS_values[-1]>=lower_bound: 3932 n = (n+1) 3933 lCMS_values.append(float('1.0e-%d'%exp)*((N-n%N)/float(N))) 3934 if lCMS_values[-1]==lCMS_values[-2]: 3935 lCMS_values.pop() 3936 exp = (n+1)//N 3937 3938 lCMS_values = lCMS_values[:-1] 3939 if lCMS_values[-1]!=lower_bound: 3940 lCMS_values.append(lower_bound) 3941 3942 return lCMS_values
3943 3944 ###### BEGIN do_check 3945 3946 args = self.split_arg(line) 3947 # Check args validity 3948 param_card = self.check_check(args) 3949 3950 options= {'events':None} # If the momentum needs to be picked from a event file 3951 if param_card and 'banner' == madevent_interface.MadEventCmd.detect_card_type(param_card): 3952 logger_check.info("Will use the param_card contained in the banner and the events associated") 3953 import madgraph.various.banner as banner 3954 options['events'] = param_card 3955 mybanner = banner.Banner(param_card) 3956 param_card = mybanner.charge_card('param_card') 3957 3958 aloha_lib.KERNEL.clean() 3959 # Back up the gauge for later 3960 gauge = str(self.options['gauge']) 3961 options['reuse'] = args[1]=="-reuse" 3962 args = args[:1]+args[2:] 3963 # For the stability check the user can specify the statistics (i.e 3964 # number of trial PS points) as a second argument 3965 if args[0] in ['stability', 'profile']: 3966 options['npoints'] = int(args[1]) 3967 args = args[:1]+args[2:] 3968 MLoptions={} 3969 i=-1 3970 CMS_options = {} 3971 while args[i].startswith('--'): 3972 option = args[i].split('=') 3973 if option[0] =='--energy': 3974 options['energy']=float(option[1]) 3975 elif option[0] == '--events' and option[1]: 3976 if option[1] == 'None': 3977 options['events'] = None 3978 elif not os.path.exists(option[1]): 3979 raise Exception('path %s does not exists' % option[1]) 3980 else: 3981 options['events'] = option[1] 3982 elif option[0] == '--skip_evt': 3983 options['skip_evt']=int(option[1]) 3984 elif option[0]=='--split_orders': 3985 options['split_orders']=int(option[1]) 3986 elif option[0]=='--helicity': 3987 try: 3988 options['helicity']=int(option[1]) 3989 except ValueError: 3990 raise self.InvalidCmd("The value of the 'helicity' option"+\ 3991 " must be an integer, not %s."%option[1]) 3992 elif option[0]=='--reduction': 3993 MLoptions['MLReductionLib']=[int(ir) for ir in option[1].split('|')] 3994 elif option[0]=='--collier_mode': 3995 MLoptions['COLLIERMode']=int(option[1]) 3996 elif option[0]=='--collier_cache': 3997 MLoptions['COLLIERGlobalCache']=int(option[1]) 3998 elif option[0]=='--collier_req_acc': 3999 if option[1]!='auto': 4000 MLoptions['COLLIERRequiredAccuracy']=float(option[1]) 4001 elif option[0]=='--collier_internal_stability_test': 4002 MLoptions['COLLIERUseInternalStabilityTest']=eval(option[1]) 4003 elif option[0]=='--CTModeRun': 4004 try: 4005 MLoptions['CTModeRun']=int(option[1]) 4006 except ValueError: 4007 raise self.InvalidCmd("The value of the 'CTModeRun' option"+\ 4008 " must be an integer, not %s."%option[1]) 4009 elif option[0]=='--offshellness': 4010 CMS_options['offshellness'] = float(option[1]) 4011 if CMS_options['offshellness']<=-1.0: 4012 raise self.InvalidCmd('Offshellness must be number larger or'+ 4013 ' equal to -1.0, not %f'%CMS_options['offshellness']) 4014 elif option[0]=='--analyze': 4015 options['analyze'] = option[1] 4016 elif option[0]=='--show_plot': 4017 options['show_plot'] = 'true' in option[1].lower() 4018 elif option[0]=='--report': 4019 options['report'] = option[1].lower() 4020 elif option[0]=='--seed': 4021 options['seed'] = int(option[1]) 4022 elif option[0]=='--name': 4023 if '.' in option[1]: 4024 raise self.InvalidCmd("Do not specify the extension in the"+ 4025 " name of the run") 4026 CMS_options['name'] = option[1] 4027 elif option[0]=='--resonances': 4028 if option[1]=='all': 4029 CMS_options['resonances'] = 'all' 4030 else: 4031 try: 4032 resonances=eval(option[1]) 4033 except: 4034 raise self.InvalidCmd("Could not evaluate 'resonances'"+ 4035 " option '%s'"%option[1]) 4036 if isinstance(resonances,int) and resonances>0: 4037 CMS_options['resonances'] = resonances 4038 elif isinstance(resonances,list) and all(len(res)==2 and 4039 isinstance(res[0],int) and all(isinstance(i, int) for i in 4040 res[1]) for res in resonances): 4041 CMS_options['resonances'] = resonances 4042 else: 4043 raise self.InvalidCmd("The option 'resonances' can only be 'all'"+ 4044 " or and integer or a list of tuples of the form "+ 4045 "(resPDG,(res_mothers_ID)). You gave '%s'"%option[1]) 4046 elif option[0]=='--tweak': 4047 # Lists the sets of custom and widths modifications to apply 4048 value = option[1] 4049 # Set a shortcuts for applying all relevant tweaks 4050 if value=='alltweaks': 4051 value=str(['default','seed667(seed667)','seed668(seed668)', 4052 'allwidths->0.9*allwidths(widths_x_0.9)', 4053 'allwidths->0.99*allwidths(widths_x_0.99)', 4054 'allwidths->1.01*allwidths(widths_x_1.01)', 4055 'allwidths->1.1*allwidths(widths_x_1.1)', 4056 'logp->logm(logp2logm)','logm->logp(logm2logp)']) 4057 try: 4058 tweaks = eval(value) 4059 if isinstance(tweaks, str): 4060 tweaks = [value] 4061 elif not isinstance(tweaks,list): 4062 tweaks = [value] 4063 except: 4064 tweaks = [value] 4065 if not all(isinstance(t,str) for t in tweaks): 4066 raise self.InvalidCmd("Invalid specificaiton of tweaks: %s"%value) 4067 CMS_options['tweak'] = [] 4068 for tweakID, tweakset in enumerate(tweaks): 4069 specs =re.match(r'^(?P<tweakset>.*)\((?P<name>.*)\)$', tweakset) 4070 if specs: 4071 tweakset = specs.group('tweakset') 4072 name = specs.group('name') 4073 else: 4074 if tweakset!='default': 4075 name = 'tweak_%d'%(tweakID+1) 4076 else: 4077 name = '' 4078 new_tweak_set = {'custom':[],'params':{},'name':name} 4079 for tweak in tweakset.split('&'): 4080 if tweak=='default': 4081 continue 4082 if tweak.startswith('seed'): 4083 new_tweak_set['custom'].append(tweak) 4084 continue 4085 try: 4086 param, replacement = tweak.split('->') 4087 except ValueError: 4088 raise self.InvalidCmd("Tweak specification '%s'"%\ 4089 tweak+" is incorrect. It should be of"+\ 4090 " the form a->_any_function_of_(a,lambdaCMS).") 4091 if param in ['logp','logm','log'] and \ 4092 replacement in ['logp','logm','log']: 4093 new_tweak_set['custom'].append(tweak) 4094 continue 4095 try: 4096 # for safety prefix parameters, because 'as' for alphas 4097 # is a python reserved name for example 4098 orig_param, orig_replacement = param, replacement 4099 replacement = replacement.replace(param, 4100 '__tmpprefix__%s'%param) 4101 param = '__tmpprefix__%s'%param 4102 res = float(eval(replacement.lower(), 4103 {'lambdacms':1.0,param.lower():98.85})) 4104 except: 4105 raise self.InvalidCmd("The substitution expression "+ 4106 "'%s' for the tweaked parameter"%orig_replacement+ 4107 " '%s' could not be evaluated. It must be an "%orig_param+ 4108 "expression of the parameter and 'lambdaCMS'.") 4109 new_tweak_set['params'][param.lower()] = replacement.lower() 4110 CMS_options['tweak'].append(new_tweak_set) 4111 4112 elif option[0]=='--recompute_width': 4113 if option[1].lower() not in ['never','always','first_time','auto']: 4114 raise self.InvalidCmd("The option 'recompute_width' can "+\ 4115 "only be 'never','always', 'first_time' or 'auto' (default).") 4116 CMS_options['recompute_width'] = option[1] 4117 elif option[0]=='--loop_filter': 4118 # Specify a loop, filter. See functions get_loop_filter and 4119 # user_filter in loop_diagram_generation.LoopAmplitude for 4120 # information on usage. 4121 CMS_options['loop_filter'] = '='.join(option[1:]) 4122 elif option[0]=='--diff_lambda_power': 4123 #'secret' option to chose by which lambda power one should divide 4124 # the nwa-cms difference. Useful to set to 2 when doing the Born check 4125 # to see whether the NLO check will have sensitivity to the CMS 4126 # implementation 4127 try: 4128 CMS_options['diff_lambda_power']=float(option[1]) 4129 except ValueError: 4130 raise self.InvalidCmd("the '--diff_lambda_power' option"+\ 4131 " must be an integer or float, not '%s'."%option[1]) 4132 elif option[0]=='--lambda_plot_range': 4133 try: 4134 plot_range=eval(option[1]) 4135 except Exception as e: 4136 raise self.InvalidCmd("The plot range specified %s"%option[1]+\ 4137 " is not a valid syntax. Error:\n%s"%str(e)) 4138 if not isinstance(plot_range,(list,tuple)) or \ 4139 len(plot_range)!=2 or any(not isinstance(p,(float,int)) 4140 for p in plot_range): 4141 raise self.InvalidCmd("The plot range specified %s"\ 4142 %option[1]+" is invalid") 4143 CMS_options['lambda_plot_range']=list([float(p) for p in plot_range]) 4144 elif option[0]=='--lambdaCMS': 4145 try: 4146 lambda_values = eval(option[1]) 4147 except SyntaxError: 4148 raise self.InvalidCmd("'%s' is not a correct"%option[1]+ 4149 " python expression for lambdaCMS values.") 4150 if isinstance(lambda_values,list): 4151 if lambda_values[0]!=1.0: 4152 raise self.InvalidCmd("The first value of the lambdaCMS values"+ 4153 " specified must be 1.0, not %s"%str(lambda_values)) 4154 for l in lambda_values: 4155 if not isinstance(l,float): 4156 raise self.InvalidCmd("All lambda CMS values must be"+ 4157 " float, not '%s'"%str(l)) 4158 elif isinstance(lambda_values,(tuple,float)): 4159 # Format here is then (lower_bound, N) were lower_bound is 4160 # the minimum lambdaCMS value that must be probed and the 4161 # integer N is the number of such values that must be 4162 # uniformly distributed in each intervale [1.0e-i,1.0e-(i+1)] 4163 if isinstance(lambda_values, float): 4164 # Use default of 10 for the number of lambda values 4165 lower_bound = lambda_values 4166 N = 10 4167 else: 4168 if isinstance(lambda_values[0],float) and \ 4169 isinstance(lambda_values[1],int): 4170 lower_bound = lambda_values[0] 4171 N = lambda_values[1] 4172 else: 4173 raise self.InvalidCmd("'%s' must be a "%option[1]+ 4174 "tuple with types (float, int).") 4175 lambda_values = create_lambda_values_list(lower_bound,N) 4176 else: 4177 raise self.InvalidCmd("'%s' must be an expression"%option[1]+ 4178 " for either a float, tuple or list.") 4179 lower_bound = lambda_values[-1] 4180 # and finally add 5 points for stability test on the last values 4181 # Depending on how the stab test will behave at NLO, we can 4182 # consider automatically adding the values below 4183 # for stab in range(1,6): 4184 # lambda_values.append((1.0+(stab/100.0))*lower_bound) 4185 4186 CMS_options['lambdaCMS'] = lambda_values 4187 elif option[0]=='--cms': 4188 try: 4189 CMS_expansion_orders, CMS_expansion_parameters = \ 4190 option[1].split(',') 4191 except ValueError: 4192 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 4193 args[i]+" is incorrect.") 4194 CMS_options['expansion_orders'] = [expansion_order for 4195 expansion_order in CMS_expansion_orders.split('&')] 4196 CMS_options['expansion_parameters'] = {} 4197 for expansion_parameter in CMS_expansion_parameters.split('&'): 4198 try: 4199 param, replacement = expansion_parameter.split('->') 4200 except ValueError: 4201 raise self.InvalidCmd("CMS expansion specification '%s'"%\ 4202 expansion_parameter+" is incorrect. It should be of"+\ 4203 " the form a->_any_function_of_(a,lambdaCMS).") 4204 try: 4205 # for safety prefix parameters, because 'as' for alphas 4206 # is a python reserved name for example 4207 orig_param, orig_replacement = param, replacement 4208 replacement = replacement.replace(param, 4209 '__tmpprefix__%s'%param) 4210 param = '__tmpprefix__%s'%param 4211 res = float(eval(replacement.lower(), 4212 {'lambdacms':1.0,param.lower():98.85})) 4213 except: 4214 raise self.InvalidCmd("The substitution expression "+ 4215 "'%s' for CMS expansion parameter"%orig_replacement+ 4216 " '%s' could not be evaluated. It must be an "%orig_param+ 4217 "expression of the parameter and 'lambdaCMS'.") 4218 # Put everything lower case as it will be done when 4219 # accessing model variables 4220 CMS_options['expansion_parameters'][param.lower()]=\ 4221 replacement.lower() 4222 else: 4223 raise self.InvalidCmd("The option '%s' is not reckognized."%option[0]) 4224 4225 i=i-1 4226 args = args[:i+1] 4227 4228 if args[0]=='options': 4229 # Simple printout of the check command options 4230 logger_check.info("Options for the command 'check' are:") 4231 logger_check.info("{:<20} {}".format(' name','default value')) 4232 logger_check.info("-"*40) 4233 for key, value in options.items(): 4234 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 4235 return 4236 4237 if args[0].lower()=='cmsoptions': 4238 # Simple printout of the special check cms options 4239 logger_check.info("Special options for the command 'check cms' are:") 4240 logger_check.info("{:<20} {}".format(' name','default value')) 4241 logger_check.info("-"*40) 4242 for key, value in CMS_options.items(): 4243 logger_check.info("{:<20} = {}".format('--%s'%key,str(value))) 4244 return 4245 4246 # Set the seed here if not in cms check and if specified 4247 if args[0]!='cms' and options['seed']!=-1: 4248 # Not necessarily optimal as there could be additional call to 4249 # random() as the code develops, but at least it will encompass 4250 # everything in this way. 4251 logger_check.info('Setting random seed to %d.'%options['seed']) 4252 random.seed(options['seed']) 4253 4254 proc_line = " ".join(args[1:]) 4255 # Don't try to extract the process if just re-analyzing a saved run 4256 if not (args[0]=='cms' and options['analyze']!='None'): 4257 myprocdef = self.extract_process(proc_line) 4258 4259 # Check that we have something 4260 if not myprocdef: 4261 raise self.InvalidCmd("Empty or wrong format process, please try again.") 4262 # For the check command, only the mode 'virt' make sense. 4263 if myprocdef.get('NLO_mode')=='all': 4264 myprocdef.set('NLO_mode','virt') 4265 else: 4266 myprocdef = None 4267 4268 # If the test has to write out on disk, it should do so at the location 4269 # specified below where the user must be sure to have writing access. 4270 output_path = os.getcwd() 4271 4272 if args[0] in ['timing','stability', 'profile'] and not \ 4273 myprocdef.get('perturbation_couplings'): 4274 raise self.InvalidCmd("Only loop processes can have their "+ 4275 " timings or stability checked.") 4276 4277 if args[0]=='gauge' and \ 4278 not myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4279 raise self.InvalidCmd( 4280 """Feynman vs unitary gauge comparisons can only be done if there are no loop 4281 propagators affected by this gauge. Typically, either processes at tree level 4282 or including only QCD perturbations can be considered here.""") 4283 4284 if args[0]=='gauge' and len(self._curr_model.get('gauge')) < 2: 4285 raise self.InvalidCmd("The current model does not allow for both "+\ 4286 "Feynman and unitary gauge.") 4287 4288 # Disable some loggers 4289 loggers = [logging.getLogger('madgraph.diagram_generation'), 4290 logging.getLogger('madgraph.loop_diagram_generation'), 4291 logging.getLogger('ALOHA'), 4292 logging.getLogger('madgraph.helas_objects'), 4293 logging.getLogger('madgraph.loop_exporter'), 4294 logging.getLogger('madgraph.export_v4'), 4295 logging.getLogger('cmdprint'), 4296 logging.getLogger('madgraph.model'), 4297 logging.getLogger('madgraph.base_objects')] 4298 old_levels = [log.level for log in loggers] 4299 for log in loggers: 4300 log.setLevel(logging.WARNING) 4301 4302 # run the check 4303 cpu_time1 = time.time() 4304 # Run matrix element generation check on processes 4305 4306 # The aloha python output has trouble when doing (tree level of course) 4307 # python output and that loop_mode is True at the beginning. 4308 # So as a temporary fix for the problem that after doing a check at NLO 4309 # then a check at LO will fail, I make sure I set it to False if the 4310 # process is a tree-level one 4311 if myprocdef: 4312 if myprocdef.get('perturbation_couplings')==[]: 4313 aloha.loop_mode = False 4314 4315 comparisons = [] 4316 gauge_result = [] 4317 gauge_result_no_brs = [] 4318 lorentz_result =[] 4319 nb_processes = 0 4320 timings = [] 4321 stability = [] 4322 profile_time = [] 4323 profile_stab = [] 4324 cms_results = [] 4325 4326 if "_cuttools_dir" in dir(self): 4327 CT_dir = self._cuttools_dir 4328 else: 4329 CT_dir ="" 4330 if "MLReductionLib" in MLoptions: 4331 if 1 in MLoptions["MLReductionLib"]: 4332 MLoptions["MLReductionLib"].remove(1) 4333 # directories for TIR 4334 TIR_dir={} 4335 if "_iregi_dir" in dir(self): 4336 TIR_dir['iregi_dir']=self._iregi_dir 4337 else: 4338 if "MLReductionLib" in MLoptions: 4339 if 3 in MLoptions["MLReductionLib"]: 4340 logger_check.warning('IREGI not available on your system; it will be skipped.') 4341 MLoptions["MLReductionLib"].remove(3) 4342 4343 4344 if "MLReductionLib" in MLoptions: 4345 if 2 in MLoptions["MLReductionLib"]: 4346 logger_check.warning('PJFRY not supported anymore; it will be skipped.') 4347 MLoptions["MLReductionLib"].remove(2) 4348 4349 if 'golem' in self.options and isinstance(self.options['golem'],str): 4350 TIR_dir['golem_dir']=self.options['golem'] 4351 else: 4352 if "MLReductionLib" in MLoptions: 4353 if 4 in MLoptions["MLReductionLib"]: 4354 logger_check.warning('GOLEM not available on your system; it will be skipped.') 4355 MLoptions["MLReductionLib"].remove(4) 4356 4357 if 'samurai' in self.options and isinstance(self.options['samurai'],str): 4358 TIR_dir['samurai_dir']=self.options['samurai'] 4359 else: 4360 if "MLReductionLib" in MLoptions: 4361 if 5 in MLoptions["MLReductionLib"]: 4362 logger_check.warning('Samurai not available on your system; it will be skipped.') 4363 MLoptions["MLReductionLib"].remove(5) 4364 4365 if 'collier' in self.options and isinstance(self.options['collier'],str): 4366 TIR_dir['collier_dir']=self.options['collier'] 4367 else: 4368 if "MLReductionLib" in MLoptions: 4369 if 7 in MLoptions["MLReductionLib"]: 4370 logger_check.warning('Collier not available on your system; it will be skipped.') 4371 MLoptions["MLReductionLib"].remove(7) 4372 4373 if 'ninja' in self.options and isinstance(self.options['ninja'],str): 4374 TIR_dir['ninja_dir']=self.options['ninja'] 4375 else: 4376 if "MLReductionLib" in MLoptions: 4377 if 6 in MLoptions["MLReductionLib"]: 4378 logger_check.warning('Ninja not available on your system; it will be skipped.') 4379 MLoptions["MLReductionLib"].remove(6) 4380 4381 if args[0] in ['timing']: 4382 timings = process_checks.check_timing(myprocdef, 4383 param_card = param_card, 4384 cuttools=CT_dir, 4385 tir=TIR_dir, 4386 options = options, 4387 cmd = self, 4388 output_path = output_path, 4389 MLOptions = MLoptions 4390 ) 4391 4392 if args[0] in ['stability']: 4393 stability=process_checks.check_stability(myprocdef, 4394 param_card = param_card, 4395 cuttools=CT_dir, 4396 tir=TIR_dir, 4397 options = options, 4398 output_path = output_path, 4399 cmd = self, 4400 MLOptions = MLoptions) 4401 4402 if args[0] in ['profile']: 4403 # In this case timing and stability will be checked one after the 4404 # other without re-generating the process. 4405 profile_time, profile_stab = process_checks.check_profile(myprocdef, 4406 param_card = param_card, 4407 cuttools=CT_dir, 4408 tir=TIR_dir, 4409 options = options, 4410 MLOptions = MLoptions, 4411 output_path = output_path, 4412 cmd = self) 4413 4414 if args[0] in ['gauge', 'full'] and \ 4415 len(self._curr_model.get('gauge')) == 2 and\ 4416 myprocdef.get('perturbation_couplings') in [[],['QCD']]: 4417 4418 line = " ".join(args[1:]) 4419 myprocdef = self.extract_process(line) 4420 if gauge == 'unitary': 4421 myprocdef_unit = myprocdef 4422 self.do_set('gauge Feynman', log=False) 4423 myprocdef_feyn = self.extract_process(line) 4424 else: 4425 myprocdef_feyn = myprocdef 4426 self.do_set('gauge unitary', log=False) 4427 myprocdef_unit = self.extract_process(line) 4428 4429 nb_part_unit = len(myprocdef_unit.get('model').get('particles')) 4430 nb_part_feyn = len(myprocdef_feyn.get('model').get('particles')) 4431 if nb_part_feyn == nb_part_unit: 4432 logger_check.error('No Goldstone present for this check!!') 4433 gauge_result_no_brs = process_checks.check_unitary_feynman( 4434 myprocdef_unit, myprocdef_feyn, 4435 param_card = param_card, 4436 options=options, 4437 cuttools=CT_dir, 4438 tir=TIR_dir, 4439 reuse = options['reuse'], 4440 output_path = output_path, 4441 cmd = self) 4442 4443 # restore previous settings 4444 self.do_set('gauge %s' % gauge, log=False) 4445 nb_processes += len(gauge_result_no_brs) 4446 4447 if args[0] in ['permutation', 'full']: 4448 comparisons = process_checks.check_processes(myprocdef, 4449 param_card = param_card, 4450 quick = True, 4451 cuttools=CT_dir, 4452 tir=TIR_dir, 4453 reuse = options['reuse'], 4454 cmd = self, 4455 output_path = output_path, 4456 options=options) 4457 nb_processes += len(comparisons[0]) 4458 4459 if args[0] in ['lorentz', 'full']: 4460 myprocdeff = copy.copy(myprocdef) 4461 lorentz_result = process_checks.check_lorentz(myprocdeff, 4462 param_card = param_card, 4463 cuttools=CT_dir, 4464 tir=TIR_dir, 4465 reuse = options['reuse'], 4466 cmd = self, 4467 output_path = output_path, 4468 options=options) 4469 nb_processes += len(lorentz_result) 4470 4471 if args[0] in ['brs', 'full']: 4472 gauge_result = process_checks.check_gauge(myprocdef, 4473 param_card = param_card, 4474 cuttools=CT_dir, 4475 tir=TIR_dir, 4476 reuse = options['reuse'], 4477 cmd = self, 4478 output_path = output_path, 4479 options=options) 4480 nb_processes += len(gauge_result) 4481 4482 # The CMS check is typically more complicated and slower than others 4483 # so we don't run it automatically with 'full'. 4484 if args[0] in ['cms']: 4485 4486 cms_original_setup = self.options['complex_mass_scheme'] 4487 process_line = " ".join(args[1:]) 4488 # Merge in the CMS_options to the options 4489 for key, value in CMS_options.items(): 4490 if key=='tweak': 4491 continue 4492 if key not in options: 4493 options[key] = value 4494 else: 4495 raise MadGraph5Error("Option '%s' is both in the option"%key+\ 4496 " and CMS_option dictionary.") 4497 4498 if options['analyze']=='None': 4499 cms_results = [] 4500 for tweak in CMS_options['tweak']: 4501 options['tweak']=tweak 4502 # Try to guess the save path and try to load it before running 4503 guessed_proc = myprocdef.get_process( 4504 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4505 if not leg.get('state')], 4506 [leg.get('ids')[0] for leg in myprocdef.get('legs') 4507 if leg.get('state')]) 4508 save_path = process_checks.CMS_save_path('pkl', 4509 {'ordered_processes':[guessed_proc.base_string()], 4510 'perturbation_orders':guessed_proc.get('perturbation_couplings')}, 4511 self._curr_model, options, output_path=output_path) 4512 if os.path.isfile(save_path) and options['reuse']: 4513 cms_result = save_load_object.load_from_file(save_path) 4514 logger_check.info("The cms check for tweak %s is recycled from file:\n %s"% 4515 (tweak['name'],save_path)) 4516 if cms_result is None: 4517 raise self.InvalidCmd('The complex mass scheme check result'+ 4518 " file below could not be read.\n %s"%save_path) 4519 else: 4520 cms_result = process_checks.check_complex_mass_scheme( 4521 process_line, 4522 param_card = param_card, 4523 cuttools=CT_dir, 4524 tir=TIR_dir, 4525 cmd = self, 4526 output_path = output_path, 4527 MLOptions = MLoptions, 4528 options=options) 4529 # Now set the correct save path 4530 save_path = process_checks.CMS_save_path('pkl', cms_result, 4531 self._curr_model, options, output_path=output_path) 4532 cms_results.append((cms_result,save_path,tweak['name'])) 4533 else: 4534 cms_result = save_load_object.load_from_file( 4535 options['analyze'].split(',')[0]) 4536 cms_results.append((cms_result,options['analyze'].split(',')[0], 4537 CMS_options['tweak'][0]['name'])) 4538 if cms_result is None: 4539 raise self.InvalidCmd('The complex mass scheme check result'+ 4540 " file below could not be read.\n %s" 4541 %options['analyze'].split(',')[0]) 4542 4543 # restore previous settings 4544 self.do_set('complex_mass_scheme %s'%str(cms_original_setup), 4545 log=False) 4546 # Use here additional key 'ordered_processes' 4547 nb_processes += len(cms_result['ordered_processes']) 4548 4549 cpu_time2 = time.time() 4550 logger_check.info("%i check performed in %s"% (nb_processes, 4551 misc.format_time(int(cpu_time2 - cpu_time1)))) 4552 4553 if args[0] in ['cms']: 4554 text = "Note that the complex mass scheme test in principle only\n" 4555 text+= "works for stable particles in final states.\n\ns" 4556 if args[0] not in ['timing','stability', 'profile', 'cms']: 4557 if self.options['complex_mass_scheme']: 4558 text = "Note that Complex mass scheme gives gauge/lorentz invariant\n" 4559 text+= "results only for stable particles in final states.\n\ns" 4560 elif not myprocdef.get('perturbation_couplings'): 4561 text = "Note That all width have been set to zero for those checks\n\n" 4562 else: 4563 text = "\n" 4564 else: 4565 text ="\n" 4566 4567 if timings: 4568 text += 'Timing result for the '+('optimized' if \ 4569 self.options['loop_optimized_output'] else 'default')+' output:\n' 4570 4571 text += process_checks.output_timings(myprocdef, timings) 4572 if stability: 4573 text += 'Stability result for the '+('optimized' if \ 4574 self.options['loop_optimized_output'] else 'default')+' output:\n' 4575 text += process_checks.output_stability(stability,output_path) 4576 4577 if profile_time and profile_stab: 4578 text += 'Timing result '+('optimized' if \ 4579 self.options['loop_optimized_output'] else 'default')+':\n' 4580 text += process_checks.output_profile(myprocdef, profile_stab, 4581 profile_time, output_path, options['reuse']) + '\n' 4582 if lorentz_result: 4583 text += 'Lorentz invariance results:\n' 4584 text += process_checks.output_lorentz_inv(lorentz_result) + '\n' 4585 if gauge_result: 4586 text += 'Gauge results:\n' 4587 text += process_checks.output_gauge(gauge_result) + '\n' 4588 if gauge_result_no_brs: 4589 text += 'Gauge results (switching between Unitary/Feynman/axial gauge):\n' 4590 text += process_checks.output_unitary_feynman(gauge_result_no_brs) + '\n' 4591 if cms_results: 4592 text += 'Complex mass scheme results (varying width in the off-shell regions):\n' 4593 cms_result = cms_results[0][0] 4594 if len(cms_results)>1: 4595 analyze = [] 4596 for i, (cms_res, save_path, tweakname) in enumerate(cms_results): 4597 save_load_object.save_to_file(save_path, cms_res) 4598 logger_check.info("Pickle file for tweak '%s' saved to disk at:\n ->%s"% 4599 (tweakname,save_path)) 4600 if i==0: 4601 analyze.append(save_path) 4602 else: 4603 analyze.append('%s(%s)'%(save_path,tweakname)) 4604 options['analyze']=','.join(analyze) 4605 options['tweak'] = CMS_options['tweak'][0] 4606 4607 self._cms_checks.append({'line':line, 'cms_result':cms_result, 4608 'options':options, 'output_path':output_path}) 4609 text += process_checks.output_complex_mass_scheme(cms_result, 4610 output_path, options, self._curr_model, 4611 output='concise_text' if options['report']=='concise' else 'text')+'\n' 4612 4613 if comparisons and len(comparisons[0])>0: 4614 text += 'Process permutation results:\n' 4615 text += process_checks.output_comparisons(comparisons[0]) + '\n' 4616 self._comparisons = comparisons 4617 4618 # We use the reuse tag for an alternative way of skipping the pager. 4619 if len(text.split('\n'))>20 and not '-reuse' in line and text!='': 4620 if 'test_manager' not in sys.argv[0]: 4621 pydoc.pager(text) 4622 4623 # Restore diagram logger 4624 for i, log in enumerate(loggers): 4625 log.setLevel(old_levels[i]) 4626 4627 # Output the result to the interface directly if short enough or if it 4628 # was anyway not output to the pager 4629 if len(text.split('\n'))<=20 or options['reuse']: 4630 # Useful to really specify what logger is used for ML acceptance tests 4631 logging.getLogger('madgraph.check_cmd').info(text) 4632 else: 4633 logging.getLogger('madgraph.check_cmd').debug(text) 4634 4635 # clean the globals created. 4636 process_checks.clean_added_globals(process_checks.ADDED_GLOBAL) 4637 if not options['reuse']: 4638 process_checks.clean_up(self._mgme_dir) 4639 4640
4641 - def clean_process(self):
4642 """ensure that all processes are cleaned from memory. 4643 typically called from import model and generate XXX command 4644 """ 4645 4646 aloha_lib.KERNEL.clean() 4647 # Reset amplitudes 4648 self._curr_amps = diagram_generation.AmplitudeList() 4649 # Reset Process definition 4650 self._curr_proc_defs = base_objects.ProcessDefinitionList() 4651 # Reset Helas matrix elements 4652 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 4653 self._generate_info = "" 4654 # Reset _done_export, since we have new process 4655 self._done_export = False 4656 # Also reset _export_format and _export_dir 4657 self._export_format = None
4658 4659 4660 # Generate a new amplitude
4661 - def do_generate(self, line):
4662 """Main commands: Generate an amplitude for a given process""" 4663 4664 self.clean_process() 4665 self._generate_info = line 4666 4667 # Call add process 4668 args = self.split_arg(line) 4669 args.insert(0, 'process') 4670 self.do_add(" ".join(args))
4671
4672 - def extract_process(self, line, proc_number = 0, overall_orders = {}):
4673 """Extract a process definition from a string. Returns 4674 a ProcessDefinition.""" 4675 4676 orig_line = line 4677 # Check basic validity of the line 4678 if not len(re.findall('>\D', line)) in [1,2]: 4679 self.do_help('generate') 4680 raise self.InvalidCmd('Wrong use of \">\" special character.') 4681 4682 4683 # Perform sanity modifications on the lines: 4684 # Add a space before and after any > , $ / | [ ] 4685 space_before = re.compile(r"(?P<carac>\S)(?P<tag>[\\[\\]/\,\\$\\>|])(?P<carac2>\S)") 4686 line = space_before.sub(r'\g<carac> \g<tag> \g<carac2>', line) 4687 4688 # Use regular expressions to extract s-channel propagators, 4689 # forbidden s-channel propagators/particles, coupling orders 4690 # and process number, starting from the back 4691 4692 # Start with process number (identified by "@") 4693 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 4694 proc_number_re = proc_number_pattern.match(line) 4695 if proc_number_re: 4696 proc_number = int(proc_number_re.group(2)) 4697 line = proc_number_re.group(1)+ proc_number_re.group(3) 4698 #overall_order are already handle but it is better to pass the info to each group 4699 4700 # Now check for perturbation orders, specified in between squared brackets 4701 perturbation_couplings_pattern = \ 4702 re.compile("^(?P<proc>.+>.+)\s*\[\s*((?P<option>\w+)\s*\=)?\s*"+\ 4703 "(?P<pertOrders>(\w+\s*)*)\s*\]\s*(?P<rest>.*)$") 4704 perturbation_couplings_re = perturbation_couplings_pattern.match(line) 4705 perturbation_couplings = "" 4706 LoopOption= 'tree' 4707 HasBorn= True 4708 if perturbation_couplings_re: 4709 perturbation_couplings = perturbation_couplings_re.group("pertOrders") 4710 option=perturbation_couplings_re.group("option") 4711 if option: 4712 if option in self._valid_nlo_modes: 4713 LoopOption=option 4714 if option=='sqrvirt': 4715 LoopOption='virt' 4716 HasBorn=False 4717 elif option=='noborn': 4718 HasBorn=False 4719 else: 4720 raise self.InvalidCmd("NLO mode %s is not valid. "%option+\ 4721 "Valid modes are %s. "%str(self._valid_nlo_modes)) 4722 else: 4723 LoopOption='all' 4724 4725 line = perturbation_couplings_re.group("proc")+\ 4726 perturbation_couplings_re.group("rest") 4727 4728 ## Now check for orders/squared orders/constrained orders 4729 order_pattern = re.compile(\ 4730 "^(?P<before>.+>.+)\s+(?P<name>(\w|(\^2))+)\s*(?P<type>"+\ 4731 "(=|(<=)|(==)|(===)|(!=)|(>=)|<|>))\s*(?P<value>-?\d+)\s*?(?P<after>.*)") 4732 order_re = order_pattern.match(line) 4733 squared_orders = {} 4734 orders = {} 4735 constrained_orders = {} 4736 ## The 'split_orders' (i.e. those for which individual matrix element 4737 ## evalutations must be provided for each corresponding order value) are 4738 ## defined from the orders specified in between [] and any order for 4739 ## which there are squared order constraints. 4740 split_orders = [] 4741 while order_re: 4742 type = order_re.group('type') 4743 if order_re.group('name').endswith('^2'): 4744 if type not in self._valid_sqso_types: 4745 raise self.InvalidCmd("Type of squared order "+\ 4746 "constraint '%s'"% type+" is not supported.") 4747 if type == '=': 4748 name = order_re.group('name') 4749 value = order_re.group('value') 4750 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4751 {'n':name, 'v': value}) 4752 type = "<=" 4753 squared_orders[order_re.group('name')[:-2]] = \ 4754 (int(order_re.group('value')),type) 4755 else: 4756 if type not in self._valid_amp_so_types: 4757 raise self.InvalidCmd("Amplitude order constraints can only be of type %s"%\ 4758 (', '.join(self._valid_amp_so_types))+", not '%s'."%type) 4759 name = order_re.group('name') 4760 value = int(order_re.group('value')) 4761 if type in ['=', '<=']: 4762 if type == '=' and value != 0: 4763 logger.warning("Interpreting '%(n)s=%(v)s' as '%(n)s<=%(v)s'" %\ 4764 {'n':name, 'v': value}) 4765 orders[name] = value 4766 elif type == "==": 4767 constrained_orders[name] = (value, type) 4768 if name not in squared_orders: 4769 squared_orders[name] = (2 * value,'==') 4770 if True:#name not in orders: 4771 orders[name] = value 4772 4773 elif type == ">": 4774 constrained_orders[name] = (value, type) 4775 if name not in squared_orders: 4776 squared_orders[name] = (2 * value,'>') 4777 4778 line = '%s %s' % (order_re.group('before'),order_re.group('after')) 4779 order_re = order_pattern.match(line) 4780 4781 # handle the case where default is not 99 and some coupling defined 4782 if self.options['default_unset_couplings'] != 99 and \ 4783 (orders or squared_orders): 4784 4785 to_set = [name for name in self._curr_model.get('coupling_orders') 4786 if name not in orders and name not in squared_orders] 4787 if to_set: 4788 logger.info('the following coupling will be allowed up to the maximal value of %s: %s' % 4789 (self.options['default_unset_couplings'], ', '.join(to_set)), '$MG:BOLD') 4790 for name in to_set: 4791 orders[name] = int(self.options['default_unset_couplings']) 4792 4793 #only allow amplitue restrctions >/ == for LO/tree level 4794 if constrained_orders and LoopOption != 'tree': 4795 raise self.InvalidCmd("Amplitude order constraints (for not LO processes) can only be of type %s"%\ 4796 (', '.join(['<=']))+", not '%s'."%type) 4797 4798 # If the squared orders are defined but not the orders, assume 4799 # orders=sq_orders. In case the squared order has a negative value or is 4800 # defined with the '>' operato, then this order correspondingly set to 4801 # be maximal (99) since there is no way to know, during generation, if 4802 # the amplitude being contstructed will be leading or not. 4803 if orders=={} and squared_orders!={}: 4804 for order in squared_orders.keys(): 4805 if squared_orders[order][0]>=0 and squared_orders[order][1]!='>': 4806 orders[order]=squared_orders[order][0] 4807 else: 4808 orders[order]=99 4809 4810 4811 if not self._curr_model['case_sensitive']: 4812 # Particle names lowercase 4813 line = line.lower() 4814 4815 # Now check for forbidden particles, specified using "/" 4816 slash = line.find("/") 4817 dollar = line.find("$") 4818 forbidden_particles = "" 4819 if slash > 0: 4820 if dollar > slash: 4821 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)(\$.*)$", line) 4822 else: 4823 forbidden_particles_re = re.match("^(.+)\s*/\s*(.+\s*)$", line) 4824 if forbidden_particles_re: 4825 forbidden_particles = forbidden_particles_re.group(2) 4826 line = forbidden_particles_re.group(1) 4827 if len(forbidden_particles_re.groups()) > 2: 4828 line = line + forbidden_particles_re.group(3) 4829 4830 # Now check for forbidden schannels, specified using "$$" 4831 forbidden_schannels_re = re.match("^(.+)\s*\$\s*\$\s*(.+)\s*$", line) 4832 forbidden_schannels = "" 4833 if forbidden_schannels_re: 4834 forbidden_schannels = forbidden_schannels_re.group(2) 4835 line = forbidden_schannels_re.group(1) 4836 4837 # Now check for forbidden onshell schannels, specified using "$" 4838 forbidden_onsh_schannels_re = re.match("^(.+)\s*\$\s*(.+)\s*$", line) 4839 forbidden_onsh_schannels = "" 4840 if forbidden_onsh_schannels_re: 4841 forbidden_onsh_schannels = forbidden_onsh_schannels_re.group(2) 4842 line = forbidden_onsh_schannels_re.group(1) 4843 4844 # Now check for required schannels, specified using "> >" 4845 required_schannels_re = re.match("^(.+?)>(.+?)>(.+)$", line) 4846 required_schannels = "" 4847 if required_schannels_re: 4848 required_schannels = required_schannels_re.group(2) 4849 line = required_schannels_re.group(1) + ">" + \ 4850 required_schannels_re.group(3) 4851 4852 args = self.split_arg(line) 4853 4854 myleglist = base_objects.MultiLegList() 4855 state = False 4856 4857 # Extract process 4858 for part_name in args: 4859 if part_name == '>': 4860 if not myleglist: 4861 raise self.InvalidCmd("No final state particles") 4862 state = True 4863 continue 4864 4865 mylegids = [] 4866 polarization = [] 4867 if '{' in part_name: 4868 part_name, pol = part_name.split('{',1) 4869 pol, rest = pol.split('}',1) 4870 4871 no_dup_name = part_name 4872 while True: 4873 try: 4874 spin = self._curr_model.get_particle(no_dup_name).get('spin') 4875 break 4876 except AttributeError: 4877 if no_dup_name in self._multiparticles: 4878 spins = set([self._curr_model.get_particle(p).get('spin') for p in self._multiparticles[no_dup_name]]) 4879 if len(spins) > 1: 4880 raise self.InvalidCmd('Can not use polarised on multi-particles for multi-particles with various spin') 4881 else: 4882 spin = spins.pop() 4883 break 4884 elif no_dup_name[0].isdigit(): 4885 no_dup_name = no_dup_name[1:] 4886 else: 4887 raise 4888 if rest: 4889 raise self.InvalidCmd('A space is required after the "}" symbol to separate particles') 4890 ignore =False 4891 for i,p in enumerate(pol): 4892 if ignore or p==',': 4893 ignore= False 4894 continue 4895 if p in ['t','T']: 4896 if spin == 3: 4897 polarization += [1,-1] 4898 else: 4899 raise self.InvalidCmd('"T" (transverse) polarization are only supported for spin one particle.') 4900 elif p in ['l', 'L']: 4901 if spin == 3: 4902 logger.warning('"L" polarization is interpreted as Left for Longitudinal please use "0".') 4903 polarization += [-1] 4904 elif p in ['R','r']: 4905 polarization += [1] 4906 elif p in ["A",'a']: 4907 if spin == 3: 4908 polarization += [99] 4909 else: 4910 raise self.InvalidCmd('"A" (auxiliary) polarization are only supported for spin one particle.') 4911 elif p in ['+']: 4912 if i +1 < len(pol) and pol[i+1].isdigit(): 4913 p = int(pol[i+1]) 4914 if abs(p) > 3: 4915 raise self.InvalidCmd("polarization are between -3 and 3") 4916 polarization.append(p) 4917 ignore = True 4918 else: 4919 polarization += [1] 4920 elif p in ['-']: 4921 if i+1 < len(pol) and pol[i+1].isdigit(): 4922 p = int(pol[i+1]) 4923 if abs(p) > 3: 4924 raise self.InvalidCmd("polarization are between -3 and 3") 4925 polarization.append(-p) 4926 ignore = True 4927 else: 4928 polarization += [-1] 4929 elif p in [0,'0']: 4930 if spin in [1,2]: 4931 raise self.InvalidCmd('"0" (longitudinal) polarization are not supported for scalar/fermion.') 4932 else: 4933 polarization += [0] 4934 elif p.isdigit(): 4935 p = int(p) 4936 if abs(p) > 3: 4937 raise self.InvalidCmd("polarization are between -3 and 3") 4938 polarization.append(p) 4939 else: 4940 raise self.InvalidCmd('Invalid Polarization') 4941 4942 duplicate =1 4943 if part_name in self._multiparticles: 4944 if isinstance(self._multiparticles[part_name][0], list): 4945 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 4946 " which can be used only for required s-channels") 4947 mylegids.extend(self._multiparticles[part_name]) 4948 elif part_name.isdigit() or part_name.startswith('-') and part_name[1:].isdigit(): 4949 if int(part_name) in self._curr_model.get('particle_dict'): 4950 mylegids.append(int(part_name)) 4951 else: 4952 raise self.InvalidCmd("No pdg_code %s in model" % part_name) 4953 else: 4954 mypart = self._curr_model['particles'].get_copy(part_name) 4955 4956 if mypart: 4957 mylegids.append(mypart.get_pdg_code()) 4958 else: 4959 # check for duplication flag! 4960 if part_name[0].isdigit(): 4961 duplicate, part_name = int(part_name[0]), part_name[1:] 4962 if part_name in self._multiparticles: 4963 if isinstance(self._multiparticles[part_name][0], list): 4964 raise self.InvalidCmd(\ 4965 "Multiparticle %s is or-multiparticle" % part_name + \ 4966 " which can be used only for required s-channels") 4967 mylegids.extend(self._multiparticles[part_name]) 4968 else: 4969 mypart = self._curr_model['particles'].get_copy(part_name) 4970 mylegids.append(mypart.get_pdg_code()) 4971 4972 if mylegids: 4973 for _ in range(duplicate): 4974 myleglist.append(base_objects.MultiLeg({'ids':mylegids, 4975 'state':state, 4976 'polarization': polarization})) 4977 else: 4978 raise self.InvalidCmd("No particle %s in model" % part_name) 4979 4980 # Apply the keyword 'all' for perturbed coupling orders. 4981 if perturbation_couplings.lower() in ['all', 'loonly']: 4982 if perturbation_couplings.lower() in ['loonly']: 4983 LoopOption = 'LOonly' 4984 perturbation_couplings=' '.join(self._curr_model['perturbation_couplings']) 4985 4986 4987 if [leg for leg in myleglist if leg.get('state') == True]: 4988 # We have a valid process 4989 # Extract perturbation orders 4990 perturbation_couplings_list = perturbation_couplings.split() 4991 if perturbation_couplings_list==['']: 4992 perturbation_couplings_list=[] 4993 # Correspondingly set 'split_order' from the squared orders and the 4994 # perturbation couplings list 4995 split_orders=list(set(perturbation_couplings_list+list(squared_orders.keys()))) 4996 try: 4997 split_orders.sort(key=lambda elem: 0 if elem=='WEIGHTED' else 4998 self._curr_model.get('order_hierarchy') 4999 [elem if not elem.endswith('.sqrt') else elem[:-5]]) 5000 except KeyError: 5001 raise self.InvalidCmd("The loaded model does not defined a "+\ 5002 " coupling order hierarchy for these couplings: %s"%\ 5003 str([so for so in split_orders if so!='WEIGHTED' and so not 5004 in list(self._curr_model['order_hierarchy'].keys())])) 5005 5006 # If the loopOption is 'tree' then the user used the syntax 5007 # [tree= Orders] for the sole purpose of setting split_orders. We 5008 # then empty the perturbation_couplings_list at this stage. 5009 if LoopOption=='tree': 5010 perturbation_couplings_list = [] 5011 if perturbation_couplings_list and LoopOption not in ['real', 'LOonly']: 5012 if not isinstance(self._curr_model,loop_base_objects.LoopModel): 5013 raise self.InvalidCmd(\ 5014 "The current model does not allow for loop computations.") 5015 else: 5016 for pert_order in perturbation_couplings_list: 5017 if pert_order not in self._curr_model['perturbation_couplings']: 5018 raise self.InvalidCmd(\ 5019 "Perturbation order %s is not among" % pert_order + \ 5020 " the perturbation orders allowed for by the loop model.") 5021 if not self.options['loop_optimized_output'] and \ 5022 LoopOption not in ['tree','real'] and split_orders!=[]: 5023 logger.warning('The default output mode (loop_optimized_output'+\ 5024 ' = False) does not support evaluations for given powers of'+\ 5025 ' coupling orders. MadLoop output will therefore not be'+\ 5026 ' able to provide such quantities.') 5027 split_orders = [] 5028 5029 # Now extract restrictions 5030 forbidden_particle_ids = \ 5031 self.extract_particle_ids(forbidden_particles) 5032 if forbidden_particle_ids and \ 5033 isinstance(forbidden_particle_ids[0], list): 5034 raise self.InvalidCmd(\ 5035 "Multiparticle %s is or-multiparticle" % part_name + \ 5036 " which can be used only for required s-channels") 5037 forbidden_onsh_schannel_ids = \ 5038 self.extract_particle_ids(forbidden_onsh_schannels) 5039 forbidden_schannel_ids = \ 5040 self.extract_particle_ids(forbidden_schannels) 5041 if forbidden_onsh_schannel_ids and \ 5042 isinstance(forbidden_onsh_schannel_ids[0], list): 5043 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 5044 " which can be used only for required s-channels") 5045 if forbidden_schannel_ids and \ 5046 isinstance(forbidden_schannel_ids[0], list): 5047 raise self.InvalidCmd("Multiparticle %s is or-multiparticle" % part_name + \ 5048 " which can be used only for required s-channels") 5049 required_schannel_ids = \ 5050 self.extract_particle_ids(required_schannels) 5051 if required_schannel_ids and not \ 5052 isinstance(required_schannel_ids[0], list): 5053 required_schannel_ids = [required_schannel_ids] 5054 5055 sqorders_values = dict([(k,v[0]) for k, v in squared_orders.items()]) 5056 if len([1 for sqo_v in sqorders_values.values() if sqo_v<0])>1: 5057 raise self.InvalidCmd( 5058 "At most one negative squared order constraint can be specified.") 5059 5060 sqorders_types = dict([(k,v[1]) for k, v in squared_orders.items()]) 5061 5062 out = base_objects.ProcessDefinition({'legs': myleglist, 5063 'model': self._curr_model, 5064 'id': proc_number, 5065 'orders': orders, 5066 'squared_orders':sqorders_values, 5067 'sqorders_types':sqorders_types, 5068 'constrained_orders': constrained_orders, 5069 'forbidden_particles': forbidden_particle_ids, 5070 'forbidden_onsh_s_channels': forbidden_onsh_schannel_ids, 5071 'forbidden_s_channels': forbidden_schannel_ids, 5072 'required_s_channels': required_schannel_ids, 5073 'overall_orders': overall_orders, 5074 'perturbation_couplings': perturbation_couplings_list, 5075 'has_born':HasBorn, 5076 'NLO_mode':LoopOption, 5077 'split_orders':split_orders 5078 }) 5079 return out
5080 # 'is_decay_chain': decay_process\ 5081 5082
5083 - def create_loop_induced(self, line, myprocdef=None):
5084 """ Routine to create the MultiProcess for the loop-induced case""" 5085 5086 args = self.split_arg(line) 5087 5088 warning_duplicate = True 5089 if '--no_warning=duplicate' in args: 5090 warning_duplicate = False 5091 args.remove('--no_warning=duplicate') 5092 5093 # Check the validity of the arguments 5094 self.check_add(args) 5095 if args[0] == 'process': 5096 args = args[1:] 5097 5098 # special option for 1->N to avoid generation of kinematically forbidden 5099 #decay. 5100 if args[-1].startswith('--optimize'): 5101 optimize = True 5102 args.pop() 5103 else: 5104 optimize = False 5105 5106 # Extract potential loop_filter 5107 loop_filter=None 5108 for arg in args: 5109 if arg.startswith('--loop_filter='): 5110 loop_filter = arg[14:] 5111 #if not isinstance(self, extended_cmd.CmdShell): 5112 # raise self.InvalidCmd, "loop_filter is not allowed in web mode" 5113 args = [a for a in args if not a.startswith('--loop_filter=')] 5114 5115 if not myprocdef: 5116 myprocdef = self.extract_process(' '.join(args)) 5117 5118 myprocdef.set('NLO_mode', 'noborn') 5119 5120 # store the first process (for the perl script) 5121 if not self._generate_info: 5122 self._generate_info = line 5123 5124 # Reset Helas matrix elements 5125 #self._curr_matrix_elements = helas_objects.HelasLoopInducedMultiProcess() 5126 5127 5128 # Check that we have the same number of initial states as 5129 # existing processes 5130 if self._curr_amps and self._curr_amps[0].get_ninitial() != \ 5131 myprocdef.get_ninitial(): 5132 raise self.InvalidCmd("Can not mix processes with different number of initial states.") 5133 5134 if self._curr_amps and (not isinstance(self._curr_amps[0], loop_diagram_generation.LoopAmplitude) or \ 5135 self._curr_amps[0]['has_born']): 5136 raise self.InvalidCmd("Can not mix loop induced process with not loop induced process") 5137 5138 # Negative coupling order contraints can be given on at most one 5139 # coupling order (and either in squared orders or orders, not both) 5140 if len([1 for val in list(myprocdef.get('orders').values())+\ 5141 list(myprocdef.get('squared_orders').values()) if val<0])>1: 5142 raise MadGraph5Error("Negative coupling order constraints"+\ 5143 " can only be given on one type of coupling and either on"+\ 5144 " squared orders or amplitude orders, not both.") 5145 5146 cpu_time1 = time.time() 5147 5148 # Generate processes 5149 if self.options['group_subprocesses'] == 'Auto': 5150 collect_mirror_procs = True 5151 else: 5152 collect_mirror_procs = self.options['group_subprocesses'] 5153 ignore_six_quark_processes = \ 5154 self.options['ignore_six_quark_processes'] if \ 5155 "ignore_six_quark_processes" in self.options \ 5156 else [] 5157 5158 # Decide here wether one needs a LoopMultiProcess or a MultiProcess 5159 5160 myproc = loop_diagram_generation.LoopInducedMultiProcess(myprocdef, 5161 collect_mirror_procs = collect_mirror_procs, 5162 ignore_six_quark_processes = ignore_six_quark_processes, 5163 optimize=optimize, 5164 loop_filter=loop_filter) 5165 5166 for amp in myproc.get('amplitudes'): 5167 if amp not in self._curr_amps: 5168 self._curr_amps.append(amp) 5169 if amp['has_born']: 5170 raise Exception 5171 elif warning_duplicate: 5172 raise self.InvalidCmd("Duplicate process %s found. Please check your processes." % \ 5173 amp.nice_string_processes()) 5174 5175 # Reset _done_export, since we have new process 5176 self._done_export = False 5177 self._curr_proc_defs.append(myprocdef) 5178 5179 cpu_time2 = time.time() 5180 5181 nprocs = len(myproc.get('amplitudes')) 5182 ndiags = sum([amp.get_number_of_diagrams() for \ 5183 amp in myproc.get('amplitudes')]) 5184 logger.info("%i processes with %i diagrams generated in %0.3f s" % \ 5185 (nprocs, ndiags, (cpu_time2 - cpu_time1))) 5186 ndiags = sum([amp.get_number_of_diagrams() for \ 5187 amp in self._curr_amps]) 5188 logger.info("Total: %i processes with %i diagrams" % \ 5189 (len(self._curr_amps), ndiags))
5190 5191 @staticmethod
5192 - def split_process_line(procline):
5193 """Takes a valid process and return 5194 a tuple (core_process, options). This removes 5195 - any NLO specifications. 5196 - any options 5197 [Used by MadSpin] 5198 """ 5199 5200 # remove the tag "[*]": this tag is used in aMC@LNO , 5201 # but it is not a valid syntax for LO 5202 line=procline 5203 pos1=line.find("[") 5204 if pos1>0: 5205 pos2=line.find("]") 5206 if pos2 >pos1: 5207 line=line[:pos1]+line[pos2+1:] 5208 # 5209 # Extract the options: 5210 # 5211 # A. Remove process number (identified by "@") 5212 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*(.*)$") 5213 proc_number_re = proc_number_pattern.match(line) 5214 if proc_number_re: 5215 line = proc_number_re.group(1) + proc_number_re.group(3) 5216 5217 # B. search for the beginning of the option string 5218 pos=1000 5219 # start with order 5220 order_pattern = re.compile("^(.+)\s+(\w+)\s*=\s*(\d+)\s*$") 5221 order_re = order_pattern.match(line) 5222 if (order_re): 5223 pos_order=line.find(order_re.group(2)) 5224 if pos_order>0 and pos_order < pos : pos=pos_order 5225 5226 # then look for slash or dollar 5227 slash = line.find("/") 5228 if slash > 0 and slash < pos: pos=slash 5229 dollar = line.find("$") 5230 if dollar > 0 and dollar < pos: pos=dollar 5231 5232 if pos<1000: 5233 proc_option=line[pos:] 5234 line=line[:pos] 5235 else: 5236 proc_option="" 5237 5238 return line, proc_option
5239
5240 - def get_final_part(self, procline):
5241 """Takes a valid process and return 5242 a set of id of final states particles. [Used by MadSpin] 5243 """ 5244 5245 if not self._curr_model['case_sensitive']: 5246 procline = procline.lower() 5247 pids = self._curr_model.get('name2pdg') 5248 5249 # method. 5250 # 1) look for decay. 5251 # in presence of decay call this routine recursively and veto 5252 # the particles which are decayed 5253 5254 # Deal with decay chain 5255 if ',' in procline: 5256 core, decay = procline.split(',', 1) 5257 core_final = self.get_final_part(core) 5258 5259 #split the decay 5260 all_decays = decay.split(',') 5261 nb_level, tmp_decay = 0, '' 5262 decays = [] 5263 # deal with () 5264 for one_decay in all_decays: 5265 if '(' in one_decay: 5266 nb_level += 1 5267 if ')' in one_decay: 5268 nb_level -= 1 5269 5270 if nb_level: 5271 if tmp_decay: 5272 tmp_decay += ', %s' % one_decay 5273 else: 5274 tmp_decay = one_decay 5275 elif tmp_decay: 5276 final = '%s,%s' % (tmp_decay, one_decay) 5277 final = final.strip() 5278 assert final[0] == '(' and final[-1] == ')' 5279 final = final[1:-1] 5280 decays.append(final) 5281 tmp_decay = '' 5282 else: 5283 decays.append(one_decay) 5284 # remove from the final states all particles which are decayed 5285 for one_decay in decays: 5286 first = one_decay.split('>',1)[0].strip() 5287 if first in pids: 5288 pid = set([pids[first]]) 5289 elif first in self._multiparticles: 5290 pid = set(self._multiparticles[first]) 5291 else: 5292 raise Exception('invalid particle name: %s. ' % first) 5293 core_final.difference_update(pid) 5294 core_final.update(self.get_final_part(one_decay)) 5295 5296 return core_final 5297 5298 # NO DECAY CHAIN 5299 final = set() 5300 final_states = re.search(r'> ([^\/\$\=\@>]*)(\[|\s\S+\=|\$|\/|\@|$)', procline) 5301 particles = final_states.groups()[0] 5302 for particle in particles.split(): 5303 if '{' in particle: 5304 particle = particle.split('{')[0] 5305 if particle in pids: 5306 final.add(pids[particle]) 5307 elif particle in self._multiparticles: 5308 final.update(set(self._multiparticles[particle])) 5309 elif particle[0].isdigit(): 5310 if particle[1:] in pids: 5311 final.add(pids[particle[1:]]) 5312 elif particle in self._multiparticles: 5313 final.update(set(self._multiparticles[particle[1:]])) 5314 5315 return final
5316
5317 - def extract_particle_ids(self, args):
5318 """Extract particle ids from a list of particle names. If 5319 there are | in the list, this corresponds to an or-list, which 5320 is represented as a list of id lists. An or-list is used to 5321 allow multiple required s-channel propagators to be specified 5322 (e.g. Z/gamma).""" 5323 5324 if isinstance(args, six.string_types): 5325 args.replace("|", " | ") 5326 args = self.split_arg(args) 5327 all_ids = [] 5328 ids=[] 5329 for part_name in args: 5330 mypart = self._curr_model['particles'].get_copy(part_name) 5331 if mypart: 5332 ids.append([mypart.get_pdg_code()]) 5333 elif part_name in self._multiparticles: 5334 ids.append(self._multiparticles[part_name]) 5335 elif part_name == "|": 5336 # This is an "or-multiparticle" 5337 if ids: 5338 all_ids.append(ids) 5339 ids = [] 5340 elif part_name.isdigit() or (part_name.startswith('-') and part_name[1:].isdigit()): 5341 ids.append([int(part_name)]) 5342 else: 5343 raise self.InvalidCmd("No particle %s in model" % part_name) 5344 all_ids.append(ids) 5345 # Flatten id list, to take care of multiparticles and 5346 # or-multiparticles 5347 res_lists = [] 5348 for i, id_list in enumerate(all_ids): 5349 res_lists.extend(diagram_generation.expand_list_list(id_list)) 5350 # Trick to avoid duplication while keeping ordering 5351 for ilist, idlist in enumerate(res_lists): 5352 set_dict = {} 5353 res_lists[ilist] = [set_dict.setdefault(i,i) for i in idlist \ 5354 if i not in set_dict] 5355 5356 if len(res_lists) == 1: 5357 res_lists = res_lists[0] 5358 5359 return res_lists
5360
5361 - def optimize_order(self, pdg_list):
5362 """Optimize the order of particles in a pdg list, so that 5363 similar particles are next to each other. Sort according to: 5364 1. pdg > 0, 2. spin, 3. color, 4. mass > 0""" 5365 5366 if not pdg_list: 5367 return 5368 if not isinstance(pdg_list[0], int): 5369 return 5370 5371 model = self._curr_model 5372 pdg_list.sort(key = lambda i: i < 0) 5373 pdg_list.sort(key = lambda i: model.get_particle(i).is_fermion()) 5374 pdg_list.sort(key = lambda i: model.get_particle(i).get('color'), 5375 reverse = True) 5376 pdg_list.sort(key = lambda i: \ 5377 model.get_particle(i).get('mass').lower() != 'zero')
5378
5379 - def extract_decay_chain_process(self, line, level_down=False, proc_number=0):
5380 """Recursively extract a decay chain process definition from a 5381 string. Returns a ProcessDefinition.""" 5382 5383 # Start with process number (identified by "@") and overall orders 5384 proc_number_pattern = re.compile("^(.+)@\s*(\d+)\s*((\w+\s*\<?=\s*\d+\s*)*)$") 5385 proc_number_re = proc_number_pattern.match(line) 5386 overall_orders = {} 5387 if proc_number_re: 5388 proc_number = int(proc_number_re.group(2)) 5389 line = proc_number_re.group(1) 5390 if proc_number_re.group(3): 5391 order_pattern = re.compile("^(.*?)\s*(\w+)\s*\<?=\s*(\d+)\s*$") 5392 order_line = proc_number_re.group(3) 5393 order_re = order_pattern.match(order_line) 5394 while order_re: 5395 overall_orders[order_re.group(2)] = int(order_re.group(3)) 5396 order_line = order_re.group(1) 5397 order_re = order_pattern.match(order_line) 5398 logger.info(line) 5399 5400 5401 index_comma = line.find(",") 5402 index_par = line.find(")") 5403 min_index = index_comma 5404 if index_par > -1 and (index_par < min_index or min_index == -1): 5405 min_index = index_par 5406 5407 if min_index > -1: 5408 core_process = self.extract_process(line[:min_index], proc_number, 5409 overall_orders) 5410 else: 5411 core_process = self.extract_process(line, proc_number, 5412 overall_orders) 5413 5414 #level_down = False 5415 5416 while index_comma > -1: 5417 line = line[index_comma + 1:] 5418 if not line.strip(): 5419 break 5420 index_par = line.find(')') 5421 # special cases: parenthesis but no , => remove the paranthesis! 5422 if line.lstrip()[0] == '(' and index_par !=-1 and \ 5423 not ',' in line[:index_par]: 5424 par_start = line.find('(') 5425 line = '%s %s' % (line[par_start+1:index_par], line[index_par+1:]) 5426 index_par = line.find(')') 5427 if line.lstrip()[0] == '(': 5428 # Go down one level in process hierarchy 5429 #level_down = True 5430 line = line.lstrip()[1:] 5431 # This is where recursion happens 5432 decay_process, line = \ 5433 self.extract_decay_chain_process(line, 5434 level_down=True) 5435 index_comma = line.find(",") 5436 index_par = line.find(')') 5437 else: 5438 index_comma = line.find(",") 5439 min_index = index_comma 5440 if index_par > -1 and \ 5441 (index_par < min_index or min_index == -1): 5442 min_index = index_par 5443 if min_index > -1: 5444 decay_process = self.extract_process(line[:min_index]) 5445 else: 5446 decay_process = self.extract_process(line) 5447 5448 core_process.get('decay_chains').append(decay_process) 5449 5450 if level_down: 5451 if index_par == -1: 5452 raise self.InvalidCmd("Missing ending parenthesis for decay process") 5453 5454 if index_par < index_comma: 5455 line = line[index_par + 1:] 5456 level_down = False 5457 break 5458 5459 if level_down: 5460 index_par = line.find(')') 5461 if index_par == -1: 5462 raise self.InvalidCmd("Missing ending parenthesis for decay process") 5463 line = line[index_par + 1:] 5464 5465 # Return the core process (ends recursion when there are no 5466 # more decays) 5467 return core_process, line
5468 5469 5470 # Import files
5471 - def do_import(self, line, force=False):
5472 """Main commands: Import files with external formats""" 5473 5474 args = self.split_arg(line) 5475 # Check argument's validity 5476 self.check_import(args) 5477 if args[0].startswith('model'): 5478 self._model_v4_path = None 5479 # Reset amplitudes and matrix elements 5480 self.clean_process() 5481 # Import model 5482 if args[0].endswith('_v4'): 5483 self._curr_model, self._model_v4_path = \ 5484 import_v4.import_model(args[1], self._mgme_dir) 5485 else: 5486 # avoid loading the qcd/qed model twice 5487 if (args[1].startswith('loop_qcd_qed_sm') or\ 5488 args[1].split('/')[-1].startswith('loop_qcd_qed_sm')) and\ 5489 self.options['gauge']!='Feynman': 5490 logger.info('Switching to Feynman gauge because '+\ 5491 'it is the only one supported by the model %s.'%args[1]) 5492 self._curr_model = None 5493 self.do_set('gauge Feynman',log=False) 5494 prefix = not '--noprefix' in args 5495 if prefix: 5496 aloha.aloha_prefix='mdl_' 5497 else: 5498 aloha.aloha_prefix='' 5499 5500 self._curr_model = import_ufo.import_model(args[1], prefix=prefix, 5501 complex_mass_scheme=self.options['complex_mass_scheme']) 5502 if os.path.sep in args[1] and "import" in self.history[-1]: 5503 self.history[-1] = 'import model %s' % self._curr_model.get('modelpath+restriction') 5504 5505 if self.options['gauge'] in ['unitary', 'axial']: 5506 if not force and isinstance(self._curr_model,\ 5507 loop_base_objects.LoopModel) and \ 5508 self._curr_model.get('perturbation_couplings') not in \ 5509 [[],['QCD']]: 5510 if 1 not in self._curr_model.get('gauge') : 5511 logger_stderr.warning('This model does not allow Feynman '+\ 5512 'gauge. You will only be able to do tree level '+\ 5513 'QCD loop cmputations with it.') 5514 else: 5515 logger.info('Change to the gauge to Feynman because '+\ 5516 'this loop model allows for more than just tree level'+\ 5517 ' and QCD perturbations.') 5518 self.do_set('gauge Feynman', log=False) 5519 return 5520 if 0 not in self._curr_model.get('gauge') : 5521 logger_stderr.warning('Change the gauge to Feynman since '+\ 5522 'the model does not allow unitary gauge') 5523 self.do_set('gauge Feynman', log=False) 5524 return 5525 else: 5526 if 1 not in self._curr_model.get('gauge') : 5527 logger_stderr.warning('Change the gauge to unitary since the'+\ 5528 ' model does not allow Feynman gauge.'+\ 5529 ' Please re-import the model') 5530 self._curr_model = None 5531 self.do_set('gauge unitary', log= False) 5532 return 5533 5534 if '-modelname' not in args: 5535 self._curr_model.pass_particles_name_in_mg_default() 5536 5537 # Do post-processing of model 5538 self.process_model() 5539 # Reset amplitudes and matrix elements and global checks 5540 self._curr_amps = diagram_generation.AmplitudeList() 5541 # Reset proc defs 5542 self._curr_proc_defs = base_objects.ProcessDefinitionList() 5543 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 5544 process_checks.store_aloha = [] 5545 5546 elif args[0] == 'command': 5547 5548 if not os.path.isfile(args[1]): 5549 raise self.InvalidCmd("Path %s is not a valid pathname" % args[1]) 5550 else: 5551 # Check the status of export and try to use file position if no 5552 #self._export dir are define 5553 self.check_for_export_dir(args[1]) 5554 # Execute the card 5555 self.import_command_file(args[1]) 5556 5557 elif args[0] == 'banner': 5558 type = madevent_interface.MadEventCmd.detect_card_type(args[1]) 5559 if type != 'banner': 5560 raise self.InvalidCmd('The File should be a valid banner') 5561 ban = banner_module.Banner(args[1]) 5562 # Check that this is MG5 banner 5563 if 'mg5proccard' in ban: 5564 for line in ban['mg5proccard'].split('\n'): 5565 if line.startswith('#') or line.startswith('<'): 5566 continue 5567 self.exec_cmd(line) 5568 else: 5569 raise self.InvalidCmd('Only MG5 banner are supported') 5570 5571 if not self._done_export: 5572 self.exec_cmd('output . -f') 5573 5574 ban.split(self._done_export[0]) 5575 logger.info('All Cards from the banner have been place in directory %s' % pjoin(self._done_export[0], 'Cards')) 5576 if '--no_launch' not in args: 5577 self.exec_cmd('launch') 5578 5579 elif args[0] == 'proc_v4': 5580 5581 if len(args) == 1 and self._export_dir: 5582 proc_card = pjoin(self._export_dir, 'Cards', \ 5583 'proc_card.dat') 5584 elif len(args) == 2: 5585 proc_card = args[1] 5586 # Check the status of export and try to use file position is no 5587 # self._export dir are define 5588 self.check_for_export_dir(os.path.realpath(proc_card)) 5589 else: 5590 raise MadGraph5Error('No default directory in output') 5591 5592 5593 #convert and excecute the card 5594 self.import_mg4_proc_card(proc_card)
5595
5596 - def remove_pointless_decay(self, param_card):
5597 """ For simple decay chain: remove diagram that are not in the BR. 5598 param_card should be a ParamCard instance.""" 5599 5600 assert isinstance(param_card, check_param_card.ParamCard) 5601 5602 # Collect amplitudes 5603 amplitudes = diagram_generation.AmplitudeList() 5604 for amp in self._curr_amps: 5605 amplitudes.extend(amp.get_amplitudes()) 5606 5607 decay_tables = param_card['decay'].decay_table 5608 to_remove = [] 5609 for amp in amplitudes: 5610 mother = [l.get('id') for l in amp['process'].get('legs') \ 5611 if not l.get('state')] 5612 if 1 == len(mother): 5613 try: 5614 decay_table = decay_tables[abs(mother[0])] 5615 except KeyError: 5616 logger.warning("No decay table for %s. decay of this particle with MadSpin should be discarded" % abs(mother[0])) 5617 continue # No BR for this particle -> accept all. 5618 # create the tuple associate to the decay mode 5619 child = [l.get('id') for l in amp['process'].get('legs') \ 5620 if l.get('state')] 5621 if not mother[0] > 0: 5622 child = [x if self._curr_model.get_particle(x)['self_antipart'] 5623 else -x for x in child] 5624 child.sort() 5625 child.insert(0, len(child)) 5626 #check if the decay is present or not: 5627 if tuple(child) not in list(decay_table.keys()): 5628 to_remove.append(amp) 5629 5630 def remove_amp(amps): 5631 for amp in amps[:]: 5632 if amp in to_remove: 5633 amps.remove(amp) 5634 if isinstance(amp, diagram_generation.DecayChainAmplitude): 5635 remove_amp(amp.get('decay_chains')) 5636 for decay in amp.get('decay_chains'): 5637 remove_amp(decay.get('amplitudes'))
5638 remove_amp(self._curr_amps) 5639 5640
5641 - def import_ufo_model(self, model_name):
5642 """ import the UFO model """ 5643 5644 self._curr_model = import_ufo.import_model(model_name)
5645
5646 - def process_model(self):
5647 """Set variables _particle_names and _couplings for tab 5648 completion, define multiparticles""" 5649 5650 # Set variables for autocomplete 5651 self._particle_names = [p.get('name') for p in self._curr_model.get('particles')\ 5652 if p.get('propagating')] + \ 5653 [p.get('antiname') for p in self._curr_model.get('particles') \ 5654 if p.get('propagating')] 5655 5656 self._couplings = list(set(sum([list(i.get('orders').keys()) for i in \ 5657 self._curr_model.get('interactions')], []))) 5658 5659 self.add_default_multiparticles()
5660 5661
5662 - def import_mg4_proc_card(self, filepath):
5663 """ read a V4 proc card, convert it and run it in mg5""" 5664 5665 # change the status of this line in the history -> pass in comment 5666 if self.history and self.history[-1].startswith('import proc_v4'): 5667 self.history[-1] = '#%s' % self.history[-1] 5668 5669 # read the proc_card.dat 5670 reader = files.read_from_file(filepath, import_v4.read_proc_card_v4) 5671 if not reader: 5672 raise self.InvalidCmd('\"%s\" is not a valid path' % filepath) 5673 5674 if self._mgme_dir: 5675 # Add comment to history 5676 self.exec_cmd("# Import the model %s" % reader.model, precmd=True) 5677 line = self.exec_cmd('import model_v4 %s -modelname' % \ 5678 (reader.model), precmd=True) 5679 else: 5680 logging.error('No MG_ME installation detected') 5681 return 5682 5683 5684 # Now that we have the model we can split the information 5685 lines = reader.extract_command_lines(self._curr_model) 5686 for line in lines: 5687 self.exec_cmd(line, precmd=True) 5688 5689 return
5690
5691 - def add_default_multiparticles(self):
5692 """ add default particle from file interface.multiparticles_default.txt 5693 """ 5694 5695 defined_multiparticles = list(self._multiparticles.keys()) 5696 removed_multiparticles = [] 5697 # First check if the defined multiparticles are allowed in the 5698 # new model 5699 5700 for key in list(self._multiparticles.keys()): 5701 try: 5702 for part in self._multiparticles[key]: 5703 self._curr_model.get('particle_dict')[part] 5704 except Exception: 5705 del self._multiparticles[key] 5706 defined_multiparticles.remove(key) 5707 removed_multiparticles.append(key) 5708 5709 # Now add default multiparticles 5710 for line in open(pjoin(MG5DIR, 'input', \ 5711 'multiparticles_default.txt')): 5712 if line.startswith('#'): 5713 continue 5714 try: 5715 if not self._curr_model['case_sensitive']: 5716 multipart_name = line.lower().split()[0] 5717 else: 5718 multipart_name = line.split()[0] 5719 if multipart_name not in self._multiparticles: 5720 #self.do_define(line) 5721 self.exec_cmd('define %s' % line, printcmd=False, precmd=True) 5722 except self.InvalidCmd as why: 5723 logger.warning('impossible to set default multiparticles %s because %s' % 5724 (line.split()[0],why)) 5725 if self.history[-1] == 'define %s' % line.strip(): 5726 self.history.pop(-1) 5727 else: 5728 misc.sprint([self.history[-1], 'define %s' % line.strip()]) 5729 5730 scheme = "old" 5731 for qcd_container in ['p', 'j']: 5732 if qcd_container not in self._multiparticles: 5733 continue 5734 multi = self._multiparticles[qcd_container] 5735 b = self._curr_model.get_particle(5) 5736 if not b: 5737 break 5738 5739 if 5 in multi: 5740 if b['mass'] != 'ZERO': 5741 multi.remove(5) 5742 multi.remove(-5) 5743 scheme = 4 5744 elif b['mass'] == 'ZERO': 5745 multi.append(5) 5746 multi.append(-5) 5747 scheme = 5 5748 5749 if scheme in [4,5]: 5750 logger.warning("Pass the definition of \'j\' and \'p\' to %s flavour scheme." % scheme) 5751 for container in ['p', 'j']: 5752 if container in defined_multiparticles: 5753 defined_multiparticles.remove(container) 5754 self.history.append("define p = %s # pass to %s flavors" % \ 5755 (' ' .join([repr(i) for i in self._multiparticles['p']]), 5756 scheme) 5757 ) 5758 self.history.append("define j = p") 5759 5760 5761 if defined_multiparticles: 5762 if 'all' in defined_multiparticles: 5763 defined_multiparticles.remove('all') 5764 logger.info("Kept definitions of multiparticles %s unchanged" % \ 5765 " / ".join(defined_multiparticles)) 5766 5767 for removed_part in removed_multiparticles: 5768 if removed_part in self._multiparticles: 5769 removed_multiparticles.remove(removed_part) 5770 5771 if removed_multiparticles: 5772 logger.info("Removed obsolete multiparticles %s" % \ 5773 " / ".join(removed_multiparticles)) 5774 5775 # add all tag 5776 line = [] 5777 for part in self._curr_model.get('particles'): 5778 line.append('%s %s' % (part.get('name'), part.get('antiname'))) 5779 line = 'all =' + ' '.join(line) 5780 self.do_define(line)
5781
5782 - def advanced_install(self, tool_to_install, 5783 HepToolsInstaller_web_address=None, 5784 additional_options=[]):
5785 """ Uses the HEPToolsInstaller.py script maintened online to install 5786 HEP tools with more complicated dependences. 5787 Additional options will be added to the list when calling HEPInstaller""" 5788 5789 # prevent border effects 5790 add_options = list(additional_options) 5791 5792 # Always refresh the installer if already present 5793 if not os.path.isdir(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')): 5794 if HepToolsInstaller_web_address is None: 5795 raise MadGraph5Error("The option 'HepToolsInstaller_web_address'"+\ 5796 " must be specified in function advanced_install"+\ 5797 " if the installers are not already downloaded.") 5798 if not os.path.isdir(pjoin(MG5DIR,'HEPTools')): 5799 os.mkdir(pjoin(MG5DIR,'HEPTools')) 5800 elif not HepToolsInstaller_web_address is None: 5801 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5802 if not HepToolsInstaller_web_address is None: 5803 logger.info('Downloading the HEPToolInstaller at:\n %s'% 5804 HepToolsInstaller_web_address) 5805 # Guess if it is a local or web address 5806 if '//' in HepToolsInstaller_web_address: 5807 misc.wget(HepToolsInstaller_web_address, 5808 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz'), 5809 stderr=open(os.devnull,'w'), stdout=open(os.devnull,'w'), 5810 cwd=MG5DIR) 5811 else: 5812 # If it is a local tarball, then just copy it 5813 shutil.copyfile(HepToolsInstaller_web_address, 5814 pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5815 5816 # Untar the file 5817 returncode = misc.call(['tar', '-xzpf', 'HEPToolsInstallers.tar.gz'], 5818 cwd=pjoin(MG5DIR,'HEPTools'), stdout=open(os.devnull, 'w')) 5819 5820 # Remove the tarball 5821 os.remove(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers.tar.gz')) 5822 5823 5824 # FOR DEBUGGING ONLY, Take HEPToolsInstaller locally 5825 if '--local' in add_options: 5826 add_options.remove('--local') 5827 logger.warning('you are using a local installer. This is intended for debugging only!') 5828 shutil.rmtree(pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5829 shutil.copytree(os.path.abspath(pjoin(MG5DIR,os.path.pardir, 5830 'HEPToolsInstallers')),pjoin(MG5DIR,'HEPTools','HEPToolsInstallers')) 5831 5832 # Potential change in naming convention 5833 name_map = {'lhapdf6_py3': 'lhapdf6'} 5834 try: 5835 tool = name_map[tool_to_install] 5836 except: 5837 tool = tool_to_install 5838 5839 # Compiler options 5840 compiler_options = [] 5841 if self.options['cpp_compiler'] is not None: 5842 compiler_options.append('--cpp_compiler=%s'% 5843 self.options['cpp_compiler']) 5844 compiler_options.append('--cpp_standard_lib=%s'% 5845 misc.detect_cpp_std_lib_dependence(self.options['cpp_compiler'])) 5846 elif misc.which('g++'): 5847 compiler_options.append('--cpp_standard_lib=%s'% 5848 misc.detect_cpp_std_lib_dependence('g++')) 5849 else: 5850 compiler_options.append('--cpp_standard_lib=%s'% 5851 misc.detect_cpp_std_lib_dependence(None)) 5852 5853 if not self.options['fortran_compiler'] is None: 5854 compiler_options.append('--fortran_compiler=%s'% 5855 self.options['fortran_compiler']) 5856 5857 if 'heptools_install_dir' in self.options: 5858 prefix = self.options['heptools_install_dir'] 5859 config_file = '~/.mg5/mg5_configuration.txt' 5860 else: 5861 prefix = pjoin(MG5DIR, 'HEPTools') 5862 config_file = '' 5863 5864 # Add the path of pythia8 if known and the MG5 path 5865 if tool=='mg5amc_py8_interface': 5866 #add_options.append('--mg5_path=%s'%MG5DIR) 5867 # Warn about the soft dependency to gnuplot 5868 if misc.which('gnuplot') is None: 5869 logger.warning("==========") 5870 logger.warning("The optional dependency 'gnuplot' for the tool"+\ 5871 " 'mg5amc_py8_interface' was not found. We recommend that you"+\ 5872 " install it so as to be able to view the plots related to "+\ 5873 " merging with Pythia 8.") 5874 logger.warning("==========") 5875 if self.options['pythia8_path']: 5876 add_options.append( 5877 '--with_pythia8=%s'%self.options['pythia8_path']) 5878 5879 # Special rules for certain tools 5880 if tool=='madanalysis5': 5881 add_options.append('--mg5_path=%s'%MG5DIR) 5882 if not any(opt.startswith(('--with_fastjet', '--veto_fastjet')) for opt in add_options): 5883 fastjet_config = misc.which(self.options['fastjet']) 5884 if fastjet_config: 5885 add_options.append('--with_fastjet=%s'%fastjet_config) 5886 5887 if self.options['delphes_path'] and os.path.isdir( 5888 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))): 5889 add_options.append('--with_delphes3=%s'%\ 5890 os.path.normpath(pjoin(MG5DIR,self.options['delphes_path']))) 5891 5892 if tool=='pythia8': 5893 # All what's below is to handle the lhapdf dependency of Pythia8 5894 lhapdf_config = misc.which(self.options['lhapdf']) 5895 lhapdf_version = None 5896 if lhapdf_config is None: 5897 lhapdf_version = None 5898 else: 5899 try: 5900 version = misc.Popen( 5901 [lhapdf_config,'--version'], stdout=subprocess.PIPE) 5902 lhapdf_version = int(version.stdout.read().decode()[0]) 5903 if lhapdf_version not in [5,6]: 5904 raise 5905 except: 5906 raise self.InvalidCmd('Could not detect LHAPDF version. Make'+ 5907 " sure '%s --version ' runs properly."%lhapdf_config) 5908 5909 if lhapdf_version is None: 5910 answer = self.ask(question= 5911 "\033[33;34mLHAPDF was not found. Do you want to install LHPADF6? "+ 5912 "(recommended) \033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >", 5913 default='y',text_format='33;32') 5914 if not answer.lower() in ['y','']: 5915 lhapdf_path = None 5916 else: 5917 self.advanced_install('lhapdf6', 5918 additional_options=add_options) 5919 lhapdf_path = pjoin(MG5DIR,'HEPTools','lhapdf6') 5920 lhapdf_version = 6 5921 else: 5922 lhapdf_path = os.path.abspath(pjoin(os.path.dirname(\ 5923 lhapdf_config),os.path.pardir)) 5924 if lhapdf_version is None: 5925 logger.warning('You decided not to link the Pythia8 installation'+ 5926 ' to LHAPDF. Beware that only built-in PDF sets can be used then.') 5927 else: 5928 logger.info('Pythia8 will be linked to LHAPDF v%d.'%lhapdf_version) 5929 logger.info('Now installing Pythia8. Be patient...','$MG:color:GREEN') 5930 lhapdf_option = [] 5931 if lhapdf_version is None: 5932 lhapdf_option.append('--with_lhapdf6=OFF') 5933 lhapdf_option.append('--with_lhapdf5=OFF') 5934 elif lhapdf_version==5: 5935 lhapdf_option.append('--with_lhapdf5=%s'%lhapdf_path) 5936 lhapdf_option.append('--with_lhapdf6=OFF') 5937 elif lhapdf_version==6: 5938 lhapdf_option.append('--with_lhapdf5=OFF') 5939 lhapdf_option.append('--with_lhapdf6=%s'%lhapdf_path) 5940 # Make sure each otion in add_options appears only once 5941 add_options = list(set(add_options)) 5942 # And that the option '--force' is placed last. 5943 add_options = [opt for opt in add_options if opt!='--force']+\ 5944 (['--force'] if '--force' in add_options else []) 5945 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5946 'HEPToolsInstallers','HEPToolInstaller.py'),'pythia8', 5947 '--prefix=%s' % prefix] 5948 + lhapdf_option + compiler_options + add_options) 5949 else: 5950 logger.info('Now installing %s. Be patient...'%tool) 5951 # Make sure each otion in add_options appears only once 5952 add_options.append('--mg5_path=%s'%MG5DIR) 5953 add_options = list(set(add_options)) 5954 add_options.append('--mg5_path=%s'%MG5DIR) 5955 # And that the option '--force' is placed last. 5956 add_options = [opt for opt in add_options if opt!='--force']+\ 5957 (['--force'] if '--force' in add_options else []) 5958 return_code = misc.call([sys.executable, pjoin(MG5DIR,'HEPTools', 5959 'HEPToolsInstallers', 'HEPToolInstaller.py'), tool,'--prefix=%s'% 5960 prefix] + compiler_options + add_options) 5961 5962 if return_code == 0: 5963 logger.info("%s successfully installed in %s."%( 5964 tool_to_install, prefix),'$MG:color:GREEN') 5965 5966 if tool=='madanalysis5': 5967 if not any(o.startswith(('--with_','--veto_','--update')) for o in add_options): 5968 logger.info(' To install recasting capabilities of madanalysis5 and/or', '$MG:BOLD') 5969 logger.info(' to allow delphes analysis at parton level.','$MG:BOLD') 5970 logger.info(' Please run \'install MadAnalysis5 --with_delphes --update\':', '$MG:BOLD') 5971 5972 elif return_code == 66: 5973 answer = self.ask(question= 5974 """\033[33;34mTool %s already installed in %s."""%(tool_to_install, prefix)+ 5975 """ Do you want to overwrite its installation?\033[0m \033[33;32my\033[0m/\033[33;31mn\033[0m >""" 5976 ,default='y',text_format='33;32') 5977 if not answer.lower() in ['y','']: 5978 logger.info("Installation of %s aborted."%tool_to_install, 5979 '$MG:color:GREEN') 5980 return 5981 else: 5982 return self.advanced_install(tool_to_install, 5983 additional_options=add_options+['--force']) 5984 else: 5985 if tool=='madanalysis5' and '--update' not in add_options and \ 5986 ('--no_MA5_further_install' not in add_options or 5987 '--no_root_in_MA5' in add_options): 5988 if not __debug__: 5989 logger.warning('Default installation of Madanalys5 failed.') 5990 logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.") 5991 logger.warning("This will however limit MA5 applicability for hadron-level analysis.") 5992 logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.") 5993 for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']: 5994 if option not in add_options: 5995 add_options.append(option) 5996 self.advanced_install('madanalysis5', 5997 HepToolsInstaller_web_address=HepToolsInstaller_web_address, 5998 additional_options=add_options) 5999 else: 6000 logger.critical("Default installation of Madanalys5 failed, we suggest you try again with the options '--no_MA5_further_install --no_root_in_MA5'.") 6001 raise self.InvalidCmd("Installation of %s failed."%tool_to_install) 6002 6003 # Post-installation treatment 6004 if tool == 'pythia8': 6005 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 6006 self.exec_cmd('save options %s pythia8_path' % config_file, printcmd=False, log=False) 6007 # Automatically re-install the mg5amc_py8_interface after a fresh 6008 # Pythia8 installation 6009 self.advanced_install('mg5amc_py8_interface', 6010 additional_options=add_options+['--force']) 6011 elif tool == 'lhapdf6': 6012 if six.PY3: 6013 self.options['lhapdf_py3'] = pjoin(prefix,'lhapdf6_py3','bin', 'lhapdf-config') 6014 self.exec_cmd('save options %s lhapdf_py3' % config_file) 6015 self.options['lhapdf'] = self.options['lhapdf_py3'] 6016 else: 6017 self.options['lhapdf_py2'] = pjoin(prefix,'lhapdf6','bin', 'lhapdf-config') 6018 self.exec_cmd('save options %s lhapdf_py2' % config_file) 6019 self.options['lhapdf'] = self.options['lhapdf_py2'] 6020 6021 elif tool == 'lhapdf5': 6022 self.options['lhapdf'] = pjoin(prefix,'lhapdf5','bin', 'lhapdf-config') 6023 self.exec_cmd('save options %s lhapdf' % config_file, printcmd=False, log=False) 6024 elif tool == 'madanalysis5': 6025 self.options['madanalysis5_path'] = pjoin(prefix, 'madanalysis5','madanalysis5') 6026 self.exec_cmd('save options madanalysis5_path', printcmd=False, log=False) 6027 elif tool == 'mg5amc_py8_interface': 6028 # At this stage, pythia is guaranteed to be installed 6029 if self.options['pythia8_path'] in ['',None,'None']: 6030 self.options['pythia8_path'] = pjoin(prefix,'pythia8') 6031 self.options['mg5amc_py8_interface_path'] = pjoin(prefix, 'MG5aMC_PY8_interface') 6032 self.exec_cmd('save options %s mg5amc_py8_interface_path' % config_file, 6033 printcmd=False, log=False) 6034 elif tool == 'collier': 6035 self.options['collier'] = pjoin(prefix,'lib') 6036 self.exec_cmd('save options %s collier' % config_file, printcmd=False, log=False) 6037 elif tool == 'ninja': 6038 if not misc.get_ninja_quad_prec_support(pjoin( 6039 prefix,'ninja','lib')): 6040 logger.warning( 6041 """Successful installation of Ninja, but without support for quadruple precision 6042 arithmetics. If you want to enable this (hence improving the treatment of numerically 6043 unstable points in the loop matrix elements) you can try to reinstall Ninja with: 6044 MG5aMC>install ninja 6045 After having made sure to have selected a C++ compiler in the 'cpp' option of 6046 MG5aMC that supports quadruple precision (typically g++ based on gcc 4.6+).""") 6047 self.options['ninja'] = pjoin(prefix,'lib') 6048 self.exec_cmd('save options %s ninja' % config_file, printcmd=False, log=False) 6049 elif '%s_path' % tool in self.options: 6050 self.options['%s_path' % tool] = pjoin(prefix, tool) 6051 self.exec_cmd('save options %s %s_path' % (config_file,tool), printcmd=False, log=False) 6052 6053 # Now warn the user if he didn't add HEPTools first in his environment 6054 # variables. 6055 path_to_be_set = [] 6056 if sys.platform == "darwin": 6057 library_variables = ["DYLD_LIBRARY_PATH"] 6058 else: 6059 library_variables = ["LD_LIBRARY_PATH"] 6060 for variable in library_variables: 6061 if (variable not in os.environ) or \ 6062 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','lib'))==\ 6063 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6064 path_to_be_set.append((variable, 6065 os.path.abspath(pjoin(MG5DIR,'HEPTools','lib')))) 6066 for variable in ["PATH"]: 6067 if (variable not in os.environ) or \ 6068 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','bin'))==\ 6069 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6070 path_to_be_set.append((variable, 6071 os.path.abspath(pjoin(MG5DIR,'HEPTools','bin')))) 6072 if (variable not in os.environ) or \ 6073 not any(os.path.abspath(pjoin(MG5DIR,'HEPTools','include'))==\ 6074 os.path.abspath(path) for path in os.environ[variable].split(os.pathsep)): 6075 path_to_be_set.append((variable, 6076 os.path.abspath(pjoin(MG5DIR,'HEPTools','include')))) 6077 6078 if len(path_to_be_set)>0: 6079 shell_type = misc.get_shell_type() 6080 if shell_type in ['bash',None]: 6081 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.bashrc"%\ 6082 (r'\n'.join('export %s=%s%s'% 6083 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 6084 elif shell_type=='tcsh': 6085 modification_line = r"printf '\n# MG5aMC paths:\n%s\n' >> ~/.cshrc"%\ 6086 (r'\n'.join('setenv %s %s%s'% 6087 (var,path,'%s$%s'%(os.pathsep,var)) for var,path in path_to_be_set)) 6088 6089 logger.debug("==========") 6090 logger.debug("We recommend that you add to the following paths"+\ 6091 " to your environment variables, so that you are guaranteed that"+\ 6092 " at runtime, MG5_aMC will use the tools you have just installed"+\ 6093 " and not some other versions installed elsewhere on your system.\n"+\ 6094 "You can do so by running the following command in your terminal:" 6095 "\n %s"%modification_line) 6096 logger.debug("==========") 6097 6098 # Return true for successful installation 6099 return True
6100 6101 install_plugin = ['maddm', 'maddump', 'MadSTR'] 6102 install_ad = {'pythia-pgs':['arXiv:0603175'], 6103 'Delphes':['arXiv:1307.6346'], 6104 'Delphes2':['arXiv:0903.2225'], 6105 'SysCalc':['arXiv:1801.08401'], 6106 'Golem95':['arXiv:0807.0605'], 6107 'QCDLoop':['arXiv:0712.1851'], 6108 'pythia8':['arXiv:1410.3012'], 6109 'lhapdf6':['arXiv:1412.7420'], 6110 'lhapdf5':['arXiv:0605240'], 6111 'hepmc':['CPC 134 (2001) 41-46'], 6112 'mg5amc_py8_interface':['arXiv:1410.3012','arXiv:XXXX.YYYYY'], 6113 'ninja':['arXiv:1203.0291','arXiv:1403.1229','arXiv:1604.01363'], 6114 'MadAnalysis5':['arXiv:1206.1599'], 6115 'MadAnalysis':['arXiv:1206.1599'], 6116 'collier':['arXiv:1604.06792'], 6117 'oneloop':['arXiv:1007.4716'], 6118 'maddm':['arXiv:1804.00444'], 6119 'maddump':['arXiv:1812.06771'], 6120 'MadSTR':['arXiv:1612.00440']} 6121 6122 install_server = ['http://madgraph.phys.ucl.ac.be/package_info.dat', 6123 'http://madgraph.physics.illinois.edu/package_info.dat'] 6124 install_name = {'td_mac': 'td', 'td_linux':'td', 'Delphes2':'Delphes', 6125 'Delphes3':'Delphes', 'pythia-pgs':'pythia-pgs', 6126 'ExRootAnalysis': 'ExRootAnalysis','MadAnalysis':'madanalysis5', 6127 'MadAnalysis4':'MadAnalysis', 6128 'SysCalc':'SysCalc', 'Golem95': 'golem95', 6129 'lhapdf6' : 'lhapdf6' if six.PY2 else 'lhapdf6_py3', 6130 'QCDLoop':'QCDLoop','MadAnalysis5':'madanalysis5', 6131 'maddm':'maddm' 6132 } 6133
6134 - def do_install(self, line, paths=None, additional_options=[]):
6135 """Install optional package from the MG suite. 6136 The argument 'additional_options' will be passed to the advanced_install 6137 functions. If it contains the option '--force', then the advanced_install 6138 function will overwrite any existing installation of the tool without 6139 warnings. 6140 """ 6141 6142 # Make sure to avoid any border effect on custom_additional_options 6143 add_options = list(additional_options) 6144 6145 args = self.split_arg(line) 6146 #check the validity of the arguments 6147 install_options = self.check_install(args) 6148 6149 if sys.platform == "darwin": 6150 program = "curl" 6151 else: 6152 program = "wget" 6153 6154 # special command for auto-update 6155 if args[0] == 'update': 6156 self.install_update(['update']+install_options['update_options'],wget=program) 6157 return 6158 elif args[0] == 'looptools': 6159 self.install_reduction_library(force=True) 6160 return 6161 6162 6163 plugin = self.install_plugin 6164 6165 advertisements = self.install_ad 6166 6167 6168 if args[0] in advertisements: 6169 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6170 # logger.info('{:^80}'.format("You are installing '%s', please cite ref(s):"%args[0]), '$MG:BOLD') 6171 # logger.info('{:^80}'.format(', '.join(advertisements[args[0]])), '$MG:color:GREEN') 6172 # logger.info('{:^80}'.format("when using results produced with this tool."), '$MG:BOLD') 6173 # logger.info('{:^80}'.format("-"*70), '$MG:BOLD') 6174 logger.info(" You are installing '%s', please cite ref(s): \033[92m%s\033[0m. " % (args[0], ', '.join(advertisements[args[0]])), '$MG:BOLD') 6175 6176 source = None 6177 # Load file with path of the different program: 6178 import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error 6179 if paths: 6180 path = paths 6181 else: 6182 path = {} 6183 6184 data_path = self.install_server 6185 6186 # Force here to choose one particular server 6187 if any(a.startswith('--source=') for a in args): 6188 source = [a[9:] for a in args if a.startswith('--source=')][-1] 6189 if source == 'uiuc': 6190 r = [1] 6191 elif source == 'ucl': 6192 r = [0] 6193 else: 6194 if source[-1].isdigit() or source[-1] == '/': 6195 source += '/package_info.dat' 6196 data_path.append(source) 6197 r = [2] 6198 else: 6199 r = random.randint(0,1) 6200 r = [r, (1-r)] 6201 if 'MG5aMC_WWW' in os.environ and os.environ['MG5aMC_WWW']: 6202 data_path.append(os.environ['MG5aMC_WWW']+'/package_info.dat') 6203 r.insert(0, 2) 6204 6205 6206 6207 for index in r: 6208 cluster_path = data_path[index] 6209 try: 6210 data = six.moves.urllib.request.urlopen(cluster_path) 6211 except Exception as error: 6212 misc.sprint(str(error), cluster_path) 6213 continue 6214 if data.getcode() != 200: 6215 continue 6216 6217 break 6218 6219 else: 6220 raise MadGraph5Error('''Impossible to connect any of us servers. 6221 Please check your internet connection or retry later''') 6222 for wwwline in data: 6223 split = wwwline.decode().split() 6224 if len(split)!=2: 6225 if '--source' not in line: 6226 source = {0:'uiuc',1:'ucl'}[index] 6227 return self.do_install(line+' --source='+source, paths=paths, additional_options=additional_options) 6228 path[split[0]] = split[1] 6229 6230 ################################################################################ 6231 # TEMPORARY HACK WHERE WE ADD ENTRIES TO WHAT WILL BE EVENTUALLY ON THE WEB 6232 ################################################################################ 6233 # path['XXX'] = 'YYY' 6234 ################################################################################ 6235 6236 if args[0] == 'Delphes': 6237 args[0] = 'Delphes3' 6238 6239 6240 try: 6241 name = self.install_name 6242 name = name[args[0]] 6243 except KeyError: 6244 name = args[0] 6245 if args[0] == 'MadAnalysis4': 6246 args[0] = 'MadAnalysis' 6247 elif args[0] in ['madstr', 'madSTR']: 6248 args[0] = 'MadSTR' 6249 name = 'MadSTR' 6250 6251 if args[0] in self._advanced_install_opts: 6252 # Now launch the advanced installation of the tool args[0] 6253 # path['HEPToolsInstaller'] is the online adress where to downlaod 6254 # the installers if necessary. 6255 # Specify the path of the MG5_aMC_interface 6256 MG5aMC_PY8_interface_path = path['MG5aMC_PY8_interface'] if \ 6257 'MG5aMC_PY8_interface' in path else 'NA' 6258 add_options.append('--mg5amc_py8_interface_tarball=%s'%\ 6259 MG5aMC_PY8_interface_path) 6260 add_options.extend(install_options['options_for_HEPToolsInstaller']) 6261 if not any(opt.startswith('--logging=') for opt in add_options): 6262 add_options.append('--logging=%d' % logger.level) 6263 6264 6265 return self.advanced_install(name, path['HEPToolsInstaller'], 6266 additional_options = add_options) 6267 6268 6269 if args[0] == 'Delphes': 6270 args[0] = 'Delphes3' 6271 6272 6273 #check outdated install 6274 substitution={'Delphes2':'Delphes','pythia-pgs':'pythia8'} 6275 if args[0] in substitution: 6276 logger.warning("Please Note that this package is NOT maintained anymore by their author(s).\n"+\ 6277 " You should consider installing and using %s, with:\n"%substitution[args[0]]+ 6278 " > install %s"%substitution[args[0]]) 6279 6280 try: 6281 os.system('rm -rf %s' % pjoin(MG5DIR, name)) 6282 except Exception: 6283 pass 6284 6285 if args[0] not in path: 6286 if not source: 6287 if index ==1: 6288 othersource = 'ucl' 6289 else: 6290 othersource = 'uiuc' 6291 # try with the mirror 6292 misc.sprint('try other mirror', othersource, ' '.join(args)) 6293 return self.do_install('%s --source=%s' % (' '.join(args), othersource), 6294 paths, additional_options) 6295 else: 6296 if 'xxx' in advertisements[name][0]: 6297 logger.warning("Program not yet released. Please try later") 6298 else: 6299 raise Exception("Online server are corrupted. No tarball available for %s" % name) 6300 return 6301 6302 # Load that path 6303 logger.info('Downloading %s' % path[args[0]]) 6304 misc.wget(path[args[0]], '%s.tgz' % name, cwd=MG5DIR) 6305 6306 # Untar the file 6307 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6308 stdout=open(os.devnull, 'w')) 6309 6310 if returncode: 6311 raise MadGraph5Error('Fail to download correctly the File. Stop') 6312 6313 6314 # Check that the directory has the correct name 6315 if not os.path.exists(pjoin(MG5DIR, name)): 6316 created_name = [n for n in os.listdir(MG5DIR) if n.lower().startswith( 6317 name.lower()) and not n.endswith('gz')] 6318 if not created_name: 6319 raise MadGraph5Error('The file was not loaded correctly. Stop') 6320 else: 6321 created_name = created_name[0] 6322 files.mv(pjoin(MG5DIR, created_name), pjoin(MG5DIR, name)) 6323 6324 if hasattr(self, 'post_install_%s' %name): 6325 return getattr(self, 'post_install_%s' %name)() 6326 6327 logger.info('compile %s. This might take a while.' % name) 6328 6329 # Modify Makefile for pythia-pgs on Mac 64 bit 6330 if args[0] == "pythia-pgs" and sys.maxsize > 2**32: 6331 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 6332 text = open(path).read() 6333 text = text.replace('MBITS=32','MBITS=64') 6334 open(path, 'w').writelines(text) 6335 if not os.path.exists(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')): 6336 os.mkdir(pjoin(MG5DIR, 'pythia-pgs', 'libraries','pylib','lib')) 6337 6338 make_flags = [] #flags for the compilation 6339 # Compile the file 6340 # Check for F77 compiler 6341 if 'FC' not in os.environ or not os.environ['FC']: 6342 if self.options['fortran_compiler'] and self.options['fortran_compiler'] != 'None': 6343 compiler = self.options['fortran_compiler'] 6344 elif misc.which('gfortran'): 6345 compiler = 'gfortran' 6346 elif misc.which('g77'): 6347 compiler = 'g77' 6348 else: 6349 raise self.InvalidCmd('Require g77 or Gfortran compiler') 6350 6351 path = None 6352 base_compiler= ['FC=g77','FC=gfortran'] 6353 if args[0] == "pythia-pgs": 6354 path = os.path.join(MG5DIR, 'pythia-pgs', 'src', 'make_opts') 6355 elif args[0] == 'MadAnalysis': 6356 path = os.path.join(MG5DIR, 'MadAnalysis', 'makefile') 6357 if path: 6358 text = open(path).read() 6359 for base in base_compiler: 6360 text = text.replace(base,'FC=%s' % compiler) 6361 open(path, 'w').writelines(text) 6362 os.environ['FC'] = compiler 6363 6364 # For Golem95, use autotools. 6365 if name == 'golem95': 6366 # Run the configure script 6367 ld_path = misc.Popen(['./configure', 6368 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC']], 6369 cwd=pjoin(MG5DIR,'golem95'),stdout=subprocess.PIPE).communicate()[0].decode() 6370 6371 6372 # For QCDLoop, use autotools. 6373 if name == 'QCDLoop': 6374 # Run the configure script 6375 ld_path = misc.Popen(['./configure', 6376 '--prefix=%s'%str(pjoin(MG5DIR, name)),'FC=%s'%os.environ['FC'], 6377 'F77=%s'%os.environ['FC']], cwd=pjoin(MG5DIR,name), 6378 stdout=subprocess.PIPE).communicate()[0].decode() 6379 6380 # For Delphes edit the makefile to add the proper link to correct library 6381 if args[0] == 'Delphes3': 6382 #change in the makefile 6383 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) 6384 # to 6385 #DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,/Applications/root_v6.04.08/lib/ 6386 rootsys = os.environ['ROOTSYS'] 6387 text = open(pjoin(MG5DIR, 'Delphes','Makefile')).read() 6388 text = text.replace('DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS)', 6389 'DELPHES_LIBS = $(shell $(RC) --libs) -lEG $(SYSLIBS) -Wl,-rpath,%s/lib/' % rootsys) 6390 open(pjoin(MG5DIR, 'Delphes','Makefile'),'w').write(text) 6391 6392 # For SysCalc link to lhapdf 6393 if name == 'SysCalc': 6394 if self.options['lhapdf']: 6395 ld_path = misc.Popen([self.options['lhapdf'], '--libdir'], 6396 stdout=subprocess.PIPE).communicate()[0].decode() 6397 ld_path = ld_path.replace('\n','') 6398 if 'LD_LIBRARY_PATH' not in os.environ: 6399 os.environ['LD_LIBRARY_PATH'] = ld_path 6400 elif not os.environ['LD_LIBRARY_PATH']: 6401 os.environ['LD_LIBRARY_PATH'] = ld_path 6402 elif ld_path not in os.environ['LD_LIBRARY_PATH']: 6403 os.environ['LD_LIBRARY_PATH'] += ';%s' % ld_path 6404 if self.options['lhapdf'] != 'lhapdf-config': 6405 if misc.which('lhapdf-config') != os.path.realpath(self.options['lhapdf']): 6406 os.environ['PATH'] = '%s:%s' % (os.path.realpath(self.options['lhapdf']),os.environ['PATH']) 6407 else: 6408 raise self.InvalidCmd('lhapdf is required to compile/use SysCalc. Specify his path or install it via install lhapdf6') 6409 if self.options['cpp_compiler']: 6410 make_flags.append('CXX=%s' % self.options['cpp_compiler']) 6411 6412 6413 if name in plugin: 6414 logger.info('no compilation needed for plugin. Loading plugin information') 6415 try: 6416 shutil.rmtree(pjoin(MG5DIR, 'PLUGIN', name)) 6417 except Exception: 6418 pass 6419 shutil.move(pjoin(os.path.join(MG5DIR, name)), os.path.join(MG5DIR, 'PLUGIN', name)) 6420 # read the __init__.py to check if we need to add a new executable 6421 try: 6422 __import__('PLUGIN.%s' % name, globals(), locals(), [], -1) 6423 plugin = sys.modules['PLUGIN.%s' % name] 6424 new_interface = plugin.new_interface 6425 new_output = plugin.new_output 6426 latest_validated_version = plugin.latest_validated_version 6427 minimal_mg5amcnlo_version = plugin.minimal_mg5amcnlo_version 6428 maximal_mg5amcnlo_version = plugin.maximal_mg5amcnlo_version 6429 except Exception as error: 6430 raise Exception('Plugin %s fail to be loaded. Please contact the author of the PLUGIN\n Error %s' % (name, error)) 6431 6432 logger.info('Plugin %s correctly interfaced. Latest official validition for MG5aMC version %s.' % (name, '.'.join(repr(i) for i in latest_validated_version))) 6433 if new_interface: 6434 ff = open(pjoin(MG5DIR, 'bin', '%s.py' % name) , 'w') 6435 if __debug__: 6436 text = '''#! /usr/bin/env python 6437 import os 6438 import sys 6439 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 6440 exe_path = os.path.join(root_path,'bin','mg5_aMC') 6441 sys.argv.pop(0) 6442 os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 6443 '''.format(name) 6444 else: 6445 text = '''#! /usr/bin/env python 6446 import os 6447 import sys 6448 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 6449 exe_path = os.path.join(root_path,'bin','mg5_aMC') 6450 sys.argv.pop(0) 6451 os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) 6452 '''.format(name) 6453 ff.write(text) 6454 ff.close() 6455 import stat 6456 os.chmod(pjoin(MG5DIR, 'bin', '%s.py' % name), stat.S_IRWXU) 6457 logger.info('To use this module, you need to quit MG5aMC and run the executable bin/%s.py' % name) 6458 status=0 6459 6460 elif logger.level <= logging.INFO: 6461 devnull = open(os.devnull,'w') 6462 try: 6463 misc.call(['make', 'clean'], stdout=devnull, stderr=-2) 6464 except Exception: 6465 pass 6466 if name == 'pythia-pgs': 6467 #SLC6 needs to have this first (don't ask why) 6468 status = misc.call(['make'], cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6469 if name in ['golem95','QCDLoop']: 6470 status = misc.call(['make','install'], 6471 cwd = os.path.join(MG5DIR, name)) 6472 else: 6473 status = misc.call(['make']+make_flags, cwd = os.path.join(MG5DIR, name)) 6474 devnull.close() 6475 else: 6476 try: 6477 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6478 except Exception: 6479 pass 6480 if name == 'pythia-pgs': 6481 #SLC6 needs to have this first (don't ask why) 6482 status = self.compile(mode='', cwd = pjoin(MG5DIR, name, 'libraries', 'pylib')) 6483 if name in ['golem95','QCDLoop']: 6484 status = misc.compile(['install'], mode='', 6485 cwd = os.path.join(MG5DIR, name)) 6486 else: 6487 status = self.compile(make_flags, mode='', 6488 cwd = os.path.join(MG5DIR, name)) 6489 6490 if not status: 6491 logger.info('Installation succeeded') 6492 else: 6493 # For pythia-pgs check when removing the "-fno-second-underscore" flag 6494 if name == 'pythia-pgs': 6495 to_comment = ['libraries/PGS4/src/stdhep-dir/mcfio/arch_mcfio', 6496 'libraries/PGS4/src/stdhep-dir/src/stdhep_Arch'] 6497 for f in to_comment: 6498 f = pjoin(MG5DIR, name, *f.split('/')) 6499 text = "".join(l for l in open(f) if 'fno-second-underscore' not in l) 6500 fsock = open(f,'w').write(text) 6501 try: 6502 misc.compile(['clean'], mode='', cwd = os.path.join(MG5DIR, name)) 6503 except Exception: 6504 pass 6505 status = self.compile(mode='', cwd = os.path.join(MG5DIR, name)) 6506 if not status: 6507 logger.info('Compilation succeeded') 6508 else: 6509 logger.warning('Error detected during the compilation. Please check the compilation error and run make manually.') 6510 6511 6512 # Special treatment for TD/Ghostscript program (require by MadAnalysis) 6513 if args[0] == 'MadAnalysis': 6514 try: 6515 os.system('rm -rf td') 6516 os.mkdir(pjoin(MG5DIR, 'td')) 6517 except Exception as error: 6518 print(error) 6519 pass 6520 6521 if sys.platform == "darwin": 6522 logger.info('Downloading TD for Mac') 6523 target = 'https://home.fnal.gov/~parke/TD/td_mac_intel64.tar.gz' 6524 misc.wget(target, 'td.tgz', cwd=pjoin(MG5DIR,'td')) 6525 misc.call(['tar', '-xzpvf', 'td.tgz'], 6526 cwd=pjoin(MG5DIR,'td')) 6527 files.mv(MG5DIR + '/td/td_intel_mac64',MG5DIR+'/td/td') 6528 else: 6529 if sys.maxsize > 2**32: 6530 logger.info('Downloading TD for Linux 64 bit') 6531 target = 'https://home.fnal.gov/~parke/TD/td_linux_64bit.tar.gz' 6532 #logger.warning('''td program (needed by MadAnalysis) is not compile for 64 bit computer. 6533 #In 99% of the case, this is perfectly fine. If you do not have plot, please follow 6534 #instruction in https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/TopDrawer .''') 6535 else: 6536 logger.info('Downloading TD for Linux 32 bit') 6537 target = 'http://madgraph.phys.ucl.ac.be/Downloads/td' 6538 misc.wget(target, 'td', cwd=pjoin(MG5DIR,'td')) 6539 os.chmod(pjoin(MG5DIR,'td','td'), 0o775) 6540 self.options['td_path'] = pjoin(MG5DIR,'td') 6541 6542 if not misc.which('gs'): 6543 logger.warning('''gosthscript not install on your system. This is not required to run MA. 6544 but this prevent to create jpg files and therefore to have the plots in the html output.''') 6545 if sys.platform == "darwin": 6546 logger.warning('''You can download this program at the following link: 6547 http://www.macupdate.com/app/mac/9980/gpl-ghostscript''') 6548 6549 if args[0] == 'Delphes2': 6550 data = open(pjoin(MG5DIR, 'Delphes','data','DetectorCard.dat')).read() 6551 data = data.replace('data/', 'DELPHESDIR/data/') 6552 out = open(pjoin(MG5DIR, 'Template','Common', 'Cards', 'delphes_card_default.dat'), 'w') 6553 out.write(data) 6554 if args[0] == 'Delphes3': 6555 if os.path.exists(pjoin(MG5DIR, 'Delphes','cards')): 6556 card_dir = pjoin(MG5DIR, 'Delphes','cards') 6557 else: 6558 card_dir = pjoin(MG5DIR, 'Delphes','examples') 6559 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6560 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_default.dat')) 6561 files.cp(pjoin(card_dir,'delphes_card_CMS.tcl'), 6562 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_CMS.dat')) 6563 files.cp(pjoin(card_dir,'delphes_card_ATLAS.tcl'), 6564 pjoin(MG5DIR,'Template', 'Common', 'Cards', 'delphes_card_ATLAS.dat')) 6565 6566 if not self.options['pythia-pgs_path'] and not self.options['pythia8_path']: 6567 logger.warning("We noticed that no parton-shower module are installed/linked. \n In order to use Delphes from MG5aMC please install/link pythia8.") 6568 6569 #reset the position of the executable 6570 options_name = {'Delphes': 'delphes_path', 6571 'Delphes2': 'delphes_path', 6572 'Delphes3': 'delphes_path', 6573 'ExRootAnalysis': 'exrootanalysis_path', 6574 'MadAnalysis': 'madanalysis_path', 6575 'SysCalc': 'syscalc_path', 6576 'pythia-pgs':'pythia-pgs_path', 6577 'Golem95': 'golem'} 6578 6579 if args[0] in options_name: 6580 opt = options_name[args[0]] 6581 if opt=='golem': 6582 self.options[opt] = pjoin(MG5DIR,name,'lib') 6583 self.exec_cmd('save options %s' % opt, printcmd=False) 6584 elif self.options[opt] != self.options_configuration[opt]: 6585 self.options[opt] = self.options_configuration[opt] 6586 self.exec_cmd('save options %s' % opt, printcmd=False)
6587 6588 6589
6590 - def install_update(self, args, wget):
6591 """ check if the current version of mg5 is up-to-date. 6592 and allow user to install the latest version of MG5 """ 6593 6594 def apply_patch(filetext): 6595 """function to apply the patch""" 6596 text = filetext.read() 6597 6598 pattern = re.compile(r'''=== renamed directory \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6599 #=== renamed directory 'Template' => 'Template/LO' 6600 for orig, new in pattern.findall(text): 6601 shutil.copytree(pjoin(MG5DIR, orig), pjoin(MG5DIR, 'UPDATE_TMP')) 6602 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6603 for i, name in enumerate(full_path): 6604 path = os.path.sep.join(full_path[:i+1]) 6605 if path and not os.path.isdir(path): 6606 os.mkdir(path) 6607 shutil.copytree(pjoin(MG5DIR, 'UPDATE_TMP'), pjoin(MG5DIR, new)) 6608 shutil.rmtree(pjoin(MG5DIR, 'UPDATE_TMP')) 6609 # track rename since patch fail to apply those correctly. 6610 pattern = re.compile(r'''=== renamed file \'(?P<orig>[^\']*)\' => \'(?P<new>[^\']*)\'''') 6611 #=== renamed file 'Template/SubProcesses/addmothers.f' => 'madgraph/iolibs/template_files/addmothers.f' 6612 for orig, new in pattern.findall(text): 6613 print('move %s to %s' % (orig, new)) 6614 try: 6615 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6616 except IOError: 6617 full_path = os.path.dirname(pjoin(MG5DIR, new)).split('/') 6618 for i, name in enumerate(full_path): 6619 path = os.path.sep.join(full_path[:i+1]) 6620 if path and not os.path.isdir(path): 6621 os.mkdir(path) 6622 files.cp(pjoin(MG5DIR, orig), pjoin(MG5DIR, new), error=True) 6623 # track remove/re-added file: 6624 pattern = re.compile(r'''^=== added file \'(?P<new>[^\']*)\'''',re.M) 6625 all_add = pattern.findall(text) 6626 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6627 #all_rm = pattern.findall(text) 6628 pattern=re.compile(r'''=== removed file \'(?P<new>[^\']*)\'(?=.*=== added file \'(?P=new)\')''',re.S) 6629 print('this step can take a few minuts. please be patient') 6630 all_rm_add = pattern.findall(text) 6631 #=== added file 'tests/input_files/full_sm/interactions.dat' 6632 for new in all_add: 6633 if new in all_rm_add: 6634 continue 6635 if os.path.isfile(pjoin(MG5DIR, new)): 6636 os.remove(pjoin(MG5DIR, new)) 6637 #pattern = re.compile(r'''=== removed file \'(?P<new>[^\']*)\'''') 6638 #=== removed file 'tests/input_files/full_sm/interactions.dat' 6639 #for old in pattern.findall(text): 6640 # if not os.path.isfile(pjoin(MG5DIR, old)): 6641 # full_path = os.path.dirname(pjoin(MG5DIR, old)).split('/') 6642 # for i, _ in enumerate(full_path): 6643 # path = os.path.sep.join(full_path[:i+1]) 6644 # if path and not os.path.isdir(path): 6645 # os.mkdir(path) 6646 # subprocess.call(['touch', pjoin(MG5DIR, old)]) 6647 6648 p= subprocess.Popen(['patch', '-p1'], stdin=subprocess.PIPE, 6649 cwd=MG5DIR) 6650 p.communicate(text.encode()) 6651 6652 # check file which are not move 6653 #=== modified file 'Template/LO/Cards/run_card.dat' 6654 #--- old/Template/Cards/run_card.dat 2012-12-06 10:01:04 +0000 6655 #+++ new/Template/LO/Cards/run_card.dat 2013-12-09 02:35:59 +0000 6656 pattern=re.compile('''=== modified file \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P<old>\S*)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6657 for match in pattern.findall(text): 6658 new = pjoin(MG5DIR, match[0]) 6659 old = pjoin(MG5DIR, match[1]) 6660 if new == old: 6661 continue 6662 elif os.path.exists(old): 6663 if not os.path.exists(os.path.dirname(new)): 6664 split = new.split('/') 6665 for i in range(1,len(split)): 6666 path = '/'.join(split[:i]) 6667 if not os.path.exists(path): 6668 print('mkdir', path) 6669 os.mkdir(path) 6670 files.cp(old,new) 6671 #=== renamed file 'Template/bin/internal/run_delphes' => 'Template/Common/bin/internal/run_delphes' 6672 #--- old/Template/bin/internal/run_delphes 2011-12-09 07:28:10 +0000 6673 #+++ new/Template/Common/bin/internal/run_delphes 2012-10-23 02:41:37 +0000 6674 #pattern=re.compile('''=== renamed file \'(?P<old>[^\']*)\' => \'(?P<new>[^\']*)\'[^\n]*\n\-\-\- old/(?P=old)[^\n]*\n\+\+\+ new/(?P=new)''',re.S) 6675 #for match in pattern.findall(text): 6676 # old = pjoin(MG5DIR, match[0]) 6677 # new = pjoin(MG5DIR, match[1]) 6678 # if new == old: 6679 # continue 6680 # elif os.path.exists(old): 6681 # if not os.path.exists(os.path.dirname(new)): 6682 # split = new.split('/') 6683 # for i in range(1,len(split)): 6684 # path = '/'.join(split[:i]) 6685 # if not os.path.exists(path): 6686 # print 'mkdir', path 6687 # os.mkdir(path) 6688 # files.cp(old,new) 6689 6690 # check that all files in bin directory are executable 6691 for path in misc.glob('*', pjoin(MG5DIR, 'bin')): 6692 misc.call(['chmod', '+x', path]) 6693 for path in misc.glob(pjoin('*','bin','*'), pjoin(MG5DIR, 'Template')): 6694 misc.call(['chmod', '+x', path]) 6695 for path in misc.glob(pjoin('*','bin','internal','*'), pjoin(MG5DIR, 'Template')): 6696 misc.call(['chmod', '+x', path]) 6697 for path in misc.glob(pjoin('*','*', '*.py'), pjoin(MG5DIR, 'Template')): 6698 misc.call(['chmod', '+x', path]) 6699 for path in misc.glob(pjoin('*','*','*.sh'), pjoin(MG5DIR, 'Template')): 6700 misc.call(['chmod', '+x', path]) 6701 6702 #add empty files/directory 6703 pattern=re.compile('''^=== touch (file|directory) \'(?P<new>[^\']*)\'''',re.M) 6704 for match in pattern.findall(text): 6705 if match[0] == 'file': 6706 new = os.path.dirname(pjoin(MG5DIR, match[1])) 6707 else: 6708 new = pjoin(MG5DIR, match[1]) 6709 if not os.path.exists(new): 6710 split = new.split('/') 6711 for i in range(1,len(split)+1): 6712 path = '/'.join(split[:i]) 6713 if path and not os.path.exists(path): 6714 print('mkdir', path) 6715 os.mkdir(path) 6716 if match[0] == 'file': 6717 print('touch ', pjoin(MG5DIR, match[1])) 6718 misc.call(['touch', pjoin(MG5DIR, match[1])]) 6719 # add new symlink 6720 pattern=re.compile('''^=== link file \'(?P<new>[^\']*)\' \'(?P<old>[^\']*)\'''', re.M) 6721 for new, old in pattern.findall(text): 6722 if not os.path.exists(pjoin(MG5DIR, new)): 6723 files.ln(pjoin(MG5DIR,old), os.path.dirname(pjoin(MG5DIR,new)), os.path.basename(new)) 6724 6725 # Re-compile CutTools and IREGI 6726 if os.path.isfile(pjoin(MG5DIR,'vendor','CutTools','includects','libcts.a')): 6727 misc.compile(arg=['-j1'],cwd=pjoin(MG5DIR,'vendor','CutTools'),nb_core=1) 6728 if os.path.isfile(pjoin(MG5DIR,'vendor','IREGI','src','libiregi.a')): 6729 misc.compile(cwd=pjoin(MG5DIR,'vendor','IREGI','src')) 6730 6731 # check if it need to download binary: 6732 pattern = re.compile("""^Binary files old/(\S*).*and new/(\S*).*$""", re.M) 6733 if pattern.search(text): 6734 return True 6735 else: 6736 return False
6737 6738 mode = [arg.split('=',1)[1] for arg in args if arg.startswith('--mode=')] 6739 if mode: 6740 mode = mode[-1] 6741 else: 6742 mode = "userrequest" 6743 force = any([arg=='-f' for arg in args]) 6744 timeout = [arg.split('=',1)[1] for arg in args if arg.startswith('--timeout=')] 6745 if timeout: 6746 try: 6747 timeout = int(timeout[-1]) 6748 except ValueError: 6749 raise self.InvalidCmd('%s: invalid argument for timeout (integer expected)'%timeout[-1]) 6750 else: 6751 timeout = self.options['timeout'] 6752 input_path = [arg.split('=',1)[1] for arg in args if arg.startswith('--input=')] 6753 6754 if input_path: 6755 fsock = open(input_path[0]) 6756 need_binary = apply_patch(fsock) 6757 logger.info('manual patch apply. Please test your version.') 6758 if need_binary: 6759 logger.warning('Note that some files need to be loaded separately!') 6760 sys.exit(0) 6761 6762 options = ['y','n','on_exit'] 6763 if mode == 'mg5_start': 6764 timeout = 2 6765 default = 'n' 6766 update_delay = self.options['auto_update'] * 24 * 3600 6767 if update_delay == 0: 6768 return 6769 elif mode == 'mg5_end': 6770 timeout = 5 6771 default = 'n' 6772 update_delay = self.options['auto_update'] * 24 * 3600 6773 if update_delay == 0: 6774 return 6775 options.remove('on_exit') 6776 elif mode == "userrequest": 6777 default = 'y' 6778 update_delay = 0 6779 else: 6780 raise self.InvalidCmd('Unknown mode for command install update') 6781 6782 if not os.path.exists(os.path.join(MG5DIR,'input','.autoupdate')) or \ 6783 os.path.exists(os.path.join(MG5DIR,'.bzr')): 6784 error_text = """This version of MG5 doesn\'t support auto-update. Common reasons are: 6785 1) This version was loaded via bazaar (use bzr pull to update instead). 6786 2) This version is a beta release of MG5.""" 6787 if mode == 'userrequest': 6788 raise self.ConfigurationError(error_text) 6789 return 6790 6791 if not misc.which('patch'): 6792 error_text = """Not able to find program \'patch\'. Please reload a clean version 6793 or install that program and retry.""" 6794 if mode == 'userrequest': 6795 raise self.ConfigurationError(error_text) 6796 return 6797 6798 # read the data present in .autoupdate 6799 data = {} 6800 for line in open(os.path.join(MG5DIR,'input','.autoupdate')): 6801 if not line.strip(): 6802 continue 6803 sline = line.split() 6804 data[sline[0]] = int(sline[1]) 6805 6806 #check validity of the file 6807 if 'version_nb' not in data: 6808 if mode == 'userrequest': 6809 error_text = 'This version of MG5 doesn\'t support auto-update. (Invalid information)' 6810 raise self.ConfigurationError(error_text) 6811 return 6812 elif 'last_check' not in data: 6813 data['last_check'] = time.time() 6814 6815 #check if we need to update. 6816 if time.time() - float(data['last_check']) < float(update_delay): 6817 return 6818 6819 logger.info('Checking if MG5 is up-to-date... (takes up to %ss)' % timeout) 6820 class TimeOutError(Exception): pass 6821 6822 def handle_alarm(signum, frame): 6823 raise TimeOutError 6824 6825 signal.signal(signal.SIGALRM, handle_alarm) 6826 signal.alarm(timeout) 6827 to_update = 0 6828 try: 6829 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/mg5amc_build_nb') 6830 signal.alarm(0) 6831 web_version = int(filetext.read().strip()) 6832 except (TimeOutError, ValueError, IOError): 6833 signal.alarm(0) 6834 print('failed to connect server') 6835 if mode == 'mg5_end': 6836 # wait 24h before next check 6837 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6838 fsock.write("version_nb %s\n" % data['version_nb']) 6839 fsock.write("last_check %s\n" % \ 6840 int(time.time()) - 3600 * 24 * (self.options['auto_update'] -1)) 6841 fsock.close() 6842 return 6843 6844 if web_version == data['version_nb']: 6845 logger.info('No new version of MG5 available') 6846 # update .autoupdate to prevent a too close check 6847 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6848 fsock.write("version_nb %s\n" % data['version_nb']) 6849 fsock.write("last_check %s\n" % int(time.time())) 6850 fsock.close() 6851 return 6852 elif data['version_nb'] > web_version: 6853 logger_stderr.info('impossible to update: local %s web %s' % (data['version_nb'], web_version)) 6854 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6855 fsock.write("version_nb %s\n" % data['version_nb']) 6856 fsock.write("last_check %s\n" % int(time.time())) 6857 fsock.close() 6858 return 6859 else: 6860 if not force: 6861 answer = self.ask('New Version of MG5 available! Do you want to update your current version?', 6862 default, options) 6863 else: 6864 answer = default 6865 6866 6867 if answer == 'y': 6868 logger.info('start updating code') 6869 fail = 0 6870 for i in range(data['version_nb'], web_version): 6871 try: 6872 filetext = six.moves.urllib.request.urlopen('http://madgraph.phys.ucl.ac.be/patch/build%s.patch' %(i+1)) 6873 except Exception: 6874 print('fail to load patch to build #%s' % (i+1)) 6875 fail = i 6876 break 6877 need_binary = apply_patch(filetext) 6878 if need_binary: 6879 path = "http://madgraph.phys.ucl.ac.be/binary/binary_file%s.tgz" %(i+1) 6880 name = "extra_file%i" % (i+1) 6881 misc.wget(path, '%s.tgz' % name, cwd=MG5DIR) 6882 # Untar the file 6883 returncode = misc.call(['tar', '-xzpf', '%s.tgz' % name], cwd=MG5DIR, 6884 stdout=open(os.devnull, 'w')) 6885 6886 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6887 if not fail: 6888 fsock.write("version_nb %s\n" % web_version) 6889 else: 6890 fsock.write("version_nb %s\n" % fail) 6891 fsock.write("last_check %s\n" % int(time.time())) 6892 fsock.close() 6893 logger.info('Refreshing installation of MG5aMC_PY8_interface.') 6894 self.do_install('mg5amc_py8_interface',additional_options=['--force']) 6895 logger.info('Checking current version. (type ctrl-c to bypass the check)') 6896 subprocess.call([os.path.join('tests','test_manager.py')], 6897 cwd=MG5DIR) 6898 print('new version installed, please relaunch mg5') 6899 try: 6900 os.remove(pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6901 shutil.copy(pjoin(MG5DIR, 'Template','LO','Source','.make_opts'), 6902 pjoin(MG5DIR, 'Template','LO','Source','make_opts')) 6903 except: 6904 pass 6905 sys.exit(0) 6906 elif answer == 'n': 6907 # prevent for a future check 6908 fsock = open(os.path.join(MG5DIR,'input','.autoupdate'),'w') 6909 fsock.write("version_nb %s\n" % data['version_nb']) 6910 fsock.write("last_check %s\n" % int(time.time())) 6911 fsock.close() 6912 logger.info('Update bypassed.') 6913 logger.info('The next check for a new version will be performed in %s days' \ 6914 % abs(self.options['auto_update'])) 6915 logger.info('In order to change this delay. Enter the command:') 6916 logger.info('set auto_update X') 6917 logger.info('Putting X to zero will prevent this check at anytime.') 6918 logger.info('You can upgrade your version at any time by typing:') 6919 logger.info('install update') 6920 else: #answer is on_exit 6921 #ensure that the test will be done on exit 6922 #Do not use the set command here!! 6923 self.options['auto_update'] = -1 * self.options['auto_update'] 6924 6925 6926
6927 - def set_configuration(self, config_path=None, final=True):
6928 """ assign all configuration variable from file 6929 ./input/mg5_configuration.txt. assign to default if not define """ 6930 6931 if not self.options: 6932 self.options = dict(self.options_configuration) 6933 self.options.update(self.options_madgraph) 6934 self.options.update(self.options_madevent) 6935 6936 if not config_path: 6937 if 'MADGRAPH_BASE' in os.environ: 6938 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 6939 self.set_configuration(config_path, final=False) 6940 if 'HOME' in os.environ: 6941 config_path = pjoin(os.environ['HOME'],'.mg5', 6942 'mg5_configuration.txt') 6943 if os.path.exists(config_path): 6944 self.set_configuration(config_path, final=False) 6945 config_path = os.path.relpath(pjoin(MG5DIR,'input', 6946 'mg5_configuration.txt')) 6947 return self.set_configuration(config_path, final) 6948 6949 if not os.path.exists(config_path): 6950 files.cp(pjoin(MG5DIR,'input','.mg5_configuration_default.txt'), config_path) 6951 config_file = open(config_path) 6952 6953 # read the file and extract information 6954 logger.info('load MG5 configuration from %s ' % config_file.name) 6955 for line in config_file: 6956 if '#' in line: 6957 line = line.split('#',1)[0] 6958 line = line.replace('\n','').replace('\r\n','') 6959 try: 6960 name, value = line.split('=') 6961 except ValueError: 6962 pass 6963 else: 6964 name = name.strip() 6965 value = value.strip() 6966 if name != 'mg5_path': 6967 self.options[name] = value 6968 if value.lower() == "none" or value=="": 6969 self.options[name] = None 6970 config_file.close() 6971 self.options['stdout_level'] = logging.getLogger('madgraph').level 6972 if not final: 6973 return self.options # the return is usefull for unittest 6974 6975 # Treat each expected input 6976 # 1: Pythia8_path and hewrig++ paths 6977 # try absolute and relative path 6978 for key in self.options: 6979 if key in ['pythia8_path', 'hwpp_path', 'thepeg_path', 'hepmc_path', 6980 'mg5amc_py8_interface_path','madanalysis5_path']: 6981 if self.options[key] in ['None', None]: 6982 self.options[key] = None 6983 continue 6984 path = self.options[key] 6985 #this is for pythia8 6986 if key == 'pythia8_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Pythia8', 'Pythia.h')): 6987 if not os.path.isfile(pjoin(path, 'include', 'Pythia8', 'Pythia.h')): 6988 self.options['pythia8_path'] = None 6989 else: 6990 continue 6991 #this is for mg5amc_py8_interface_path 6992 if key == 'mg5amc_py8_interface_path' and not os.path.isfile(pjoin(MG5DIR, path, 'MG5aMC_PY8_interface')): 6993 if not os.path.isfile(pjoin(path, 'MG5aMC_PY8_interface')): 6994 self.options['mg5amc_py8_interface_path'] = None 6995 else: 6996 continue 6997 #this is for madanalysis5 6998 if key == 'madanalysis5_path' and not os.path.isfile(pjoin(MG5DIR, path,'bin','ma5')): 6999 if not os.path.isfile(pjoin(path,'bin','ma5')): 7000 self.options['madanalysis5_path'] = None 7001 else: 7002 ma5path = pjoin(MG5DIR, path) if os.path.isfile(pjoin(MG5DIR, path)) else path 7003 message = misc.is_MA5_compatible_with_this_MG5(ma5path) 7004 if not message is None: 7005 self.options['madanalysis5_path'] = None 7006 logger.warning(message) 7007 continue 7008 7009 #this is for hw++ 7010 if key == 'hwpp_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 7011 if not os.path.isfile(pjoin(path, 'include', 'Herwig++', 'Analysis', 'BasicConsistency.hh')): 7012 self.options['hwpp_path'] = None 7013 else: 7014 continue 7015 # this is for thepeg 7016 elif key == 'thepeg_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 7017 if not os.path.isfile(pjoin(path, 'include', 'ThePEG', 'ACDC', 'ACDCGenCell.h')): 7018 self.options['thepeg_path'] = None 7019 else: 7020 continue 7021 # this is for hepmc 7022 elif key == 'hepmc_path' and not os.path.isfile(pjoin(MG5DIR, path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 7023 if not os.path.isfile(pjoin(path, 'include', 'HepMC', 'HEPEVT_Wrapper.h')): 7024 self.options['hepmc_path'] = None 7025 else: 7026 continue 7027 7028 elif key in ['golem','samurai']: 7029 if isinstance(self.options[key],str) and self.options[key].lower() == 'auto': 7030 # try to find it automatically on the system 7031 program = misc.which_lib('lib%s.a'%key) 7032 if program != None: 7033 fpath, _ = os.path.split(program) 7034 logger.info('Using %s library in %s' % (key,fpath)) 7035 self.options[key]=fpath 7036 else: 7037 # Try to look for it locally 7038 local_install = { 'golem':'golem95', 7039 'samurai':'samurai'} 7040 if os.path.isfile(pjoin(MG5DIR,local_install[key],'lib', 'lib%s.a' % key)): 7041 self.options[key]=pjoin(MG5DIR,local_install[key],'lib') 7042 else: 7043 self.options[key]=None 7044 # Make sure that samurai version is recent enough 7045 if key=='samurai' and \ 7046 isinstance(self.options[key],str) and \ 7047 self.options[key].lower() != 'auto': 7048 if os.path.isfile(pjoin(self.options[key],os.pardir,'AUTHORS')): 7049 try: 7050 version = open(pjoin(self.options[key],os.pardir, 7051 'VERSION'),'r').read() 7052 except IOError: 7053 version = None 7054 if version is None: 7055 self.options[key] = None 7056 logger.info('--------') 7057 logger.info( 7058 """The version of 'samurai' automatically detected seems too old to be compatible 7059 with MG5aMC and it will be turned off. Ask the authors for the latest version if 7060 you want to use samurai. 7061 If you want to enforce its use as-it-is, then specify directly its library folder 7062 in the MG5aMC option 'samurai' (instead of leaving it to its default 'auto').""") 7063 logger.info('--------') 7064 7065 elif key.endswith('path'): 7066 pass 7067 elif key in ['run_mode', 'auto_update']: 7068 self.options[key] = int(self.options[key]) 7069 elif key in ['cluster_type','automatic_html_opening']: 7070 pass 7071 elif key in ['notification_center']: 7072 if self.options[key] in ['False', 'True']: 7073 self.allow_notification_center = eval(self.options[key]) 7074 self.options[key] = self.allow_notification_center 7075 elif key not in ['text_editor','eps_viewer','web_browser', 'stdout_level']: 7076 # Default: try to set parameter 7077 try: 7078 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 7079 except MadGraph5Error as error: 7080 print(error) 7081 logger.warning("Option %s from config file not understood" \ 7082 % key) 7083 else: 7084 if key in self.options_madgraph: 7085 self.history.append('set %s %s' % (key, self.options[key])) 7086 7087 warnings = madevent_interface.MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options) 7088 if warnings: 7089 logger.warning(warnings) 7090 7091 # Configure the way to open a file: 7092 launch_ext.open_file.configure(self.options) 7093 return self.options
7094
7095 - def check_for_export_dir(self, filepath):
7096 """Check if the files is in a valid export directory and assign it to 7097 export path if if is""" 7098 7099 # keep previous if a previous one is defined 7100 if self._export_dir: 7101 return 7102 7103 if os.path.exists(pjoin(os.getcwd(), 'Cards')): 7104 self._export_dir = os.getcwd() 7105 return 7106 7107 path_split = filepath.split(os.path.sep) 7108 if len(path_split) > 2 and path_split[-2] == 'Cards': 7109 self._export_dir = os.path.sep.join(path_split[:-2]) 7110 return
7111
7112 - def do_launch(self, line):
7113 """Main commands: Ask for editing the parameter and then 7114 Execute the code (madevent/standalone/...) 7115 """ 7116 7117 #ensure that MG option are not modified by the launch routine 7118 current_options = dict([(name, self.options[name]) for name in self.options_madgraph]) 7119 start_cwd = os.getcwd() 7120 7121 args = self.split_arg(line) 7122 # check argument validity and normalise argument 7123 (options, args) = _launch_parser.parse_args(args) 7124 self.check_launch(args, options) 7125 options = options.__dict__ 7126 # args is now MODE PATH 7127 7128 if args[0].startswith('standalone'): 7129 if os.path.isfile(os.path.join(os.getcwd(),args[1],'Cards',\ 7130 'MadLoopParams.dat')) and not os.path.isfile(os.path.join(\ 7131 os.getcwd(),args[1],'SubProcesses','check_poles.f')): 7132 ext_program = launch_ext.MadLoopLauncher(self, args[1], \ 7133 options=self.options, **options) 7134 else: 7135 ext_program = launch_ext.SALauncher(self, args[1], \ 7136 options=self.options, **options) 7137 elif args[0] == 'madevent': 7138 if options['interactive']: 7139 7140 if isinstance(self, cmd.CmdShell): 7141 ME = madevent_interface.MadEventCmdShell(me_dir=args[1], options=self.options) 7142 else: 7143 ME = madevent_interface.MadEventCmd(me_dir=args[1],options=self.options) 7144 ME.pass_in_web_mode() 7145 stop = self.define_child_cmd_interface(ME) 7146 return stop 7147 7148 #check if this is a cross-section 7149 if not self._generate_info: 7150 # This relaunch an old run -> need to check if this is a 7151 # cross-section or a width 7152 info = open(pjoin(args[1],'SubProcesses','procdef_mg5.dat')).read() 7153 generate_info = info.split('# Begin PROCESS',1)[1].split('\n')[1] 7154 generate_info = generate_info.split('#')[0] 7155 else: 7156 generate_info = self._generate_info 7157 7158 if len(generate_info.split('>')[0].strip().split())>1: 7159 ext_program = launch_ext.MELauncher(args[1], self, 7160 shell = isinstance(self, cmd.CmdShell), 7161 options=self.options,**options) 7162 else: 7163 # This is a width computation 7164 ext_program = launch_ext.MELauncher(args[1], self, unit='GeV', 7165 shell = isinstance(self, cmd.CmdShell), 7166 options=self.options,**options) 7167 7168 elif args[0] == 'pythia8': 7169 ext_program = launch_ext.Pythia8Launcher( args[1], self, **options) 7170 7171 elif args[0] == 'aMC@NLO': 7172 if options['interactive']: 7173 if isinstance(self, cmd.CmdShell): 7174 ME = amcatnlo_run.aMCatNLOCmdShell(me_dir=args[1], options=self.options) 7175 else: 7176 ME = amcatnlo_run.aMCatNLOCmd(me_dir=args[1],options=self.options) 7177 ME.pass_in_web_mode() 7178 # transfer interactive configuration 7179 config_line = [l for l in self.history if l.strip().startswith('set')] 7180 for line in config_line: 7181 ME.exec_cmd(line) 7182 stop = self.define_child_cmd_interface(ME) 7183 return stop 7184 ext_program = launch_ext.aMCatNLOLauncher( args[1], self, 7185 shell = isinstance(self, cmd.CmdShell), 7186 **options) 7187 elif args[0] == 'madweight': 7188 import madgraph.interface.madweight_interface as madweight_interface 7189 if options['interactive']: 7190 if isinstance(self, cmd.CmdShell): 7191 MW = madweight_interface.MadWeightCmdShell(me_dir=args[1], options=self.options) 7192 else: 7193 MW = madweight_interface.MadWeightCmd(me_dir=args[1],options=self.options) 7194 # transfer interactive configuration 7195 config_line = [l for l in self.history if l.strip().startswith('set')] 7196 for line in config_line: 7197 MW.exec_cmd(line) 7198 stop = self.define_child_cmd_interface(MW) 7199 return stop 7200 ext_program = launch_ext.MWLauncher( self, args[1], 7201 shell = isinstance(self, cmd.CmdShell), 7202 options=self.options,**options) 7203 else: 7204 os.chdir(start_cwd) #ensure to go to the initial path 7205 raise self.InvalidCmd('%s cannot be run from MG5 interface' % args[0]) 7206 7207 7208 ext_program.run() 7209 os.chdir(start_cwd) #ensure to go to the initial path 7210 # ensure that MG options are not changed! 7211 for key, value in current_options.items(): 7212 self.options[key] = value
7213
7214 - def do_load(self, line):
7215 """Not in help: Load information from file""" 7216 7217 args = self.split_arg(line) 7218 # check argument validity 7219 self.check_load(args) 7220 7221 cpu_time1 = time.time() 7222 if args[0] == 'model': 7223 self._curr_model = save_load_object.load_from_file(args[1]) 7224 if self._curr_model.get('parameters'): 7225 # This is a UFO model 7226 self._model_v4_path = None 7227 else: 7228 # This is a v4 model 7229 self._model_v4_path = import_v4.find_model_path(\ 7230 self._curr_model.get('name').replace("_v4", ""), 7231 self._mgme_dir) 7232 7233 # Do post-processing of model 7234 self.process_model() 7235 7236 #save_model.save_model(args[1], self._curr_model) 7237 if isinstance(self._curr_model, base_objects.Model): 7238 cpu_time2 = time.time() 7239 logger.info("Loaded model from file in %0.3f s" % \ 7240 (cpu_time2 - cpu_time1)) 7241 else: 7242 raise self.RWError('Could not load model from file %s' \ 7243 % args[1]) 7244 elif args[0] == 'processes': 7245 amps,proc_defs = save_load_object.load_from_file(args[1]) 7246 if isinstance(amps, diagram_generation.AmplitudeList): 7247 cpu_time2 = time.time() 7248 logger.info("Loaded processes from file in %0.3f s" % \ 7249 (cpu_time2 - cpu_time1)) 7250 if amps: 7251 model = amps[0].get('process').get('model') 7252 if not model.get('parameters'): 7253 # This is a v4 model. Look for path. 7254 self._model_v4_path = import_v4.find_model_path(\ 7255 model.get('name').replace("_v4", ""), 7256 self._mgme_dir) 7257 else: 7258 self._model_v4_path = None 7259 # If not exceptions from previous steps, set 7260 # _curr_amps and _curr_model 7261 self._curr_amps = amps 7262 self._curr_model = model 7263 self._curr_proc_defs = proc_defs 7264 logger.info("Model set from process.") 7265 # Do post-processing of model 7266 self.process_model() 7267 self._done_export = None 7268 else: 7269 raise self.RWError('Could not load processes from file %s' % args[1])
7270 7271
7272 - def do_customize_model(self, line):
7273 """create a restriction card in a interactive way""" 7274 7275 args = self.split_arg(line) 7276 self.check_customize_model(args) 7277 7278 model_path = self._curr_model.get('modelpath') 7279 if not os.path.exists(pjoin(model_path,'build_restrict.py')): 7280 raise self.InvalidCmd('''Model not compatible with this option.''') 7281 7282 # (re)import the full model (get rid of the default restriction) 7283 self._curr_model = import_ufo.import_model(model_path, restrict=False) 7284 7285 #1) create the full param_card 7286 out_path = StringIO.StringIO() 7287 param_writer.ParamCardWriter(self._curr_model, out_path) 7288 # and load it to a python object 7289 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 7290 7291 7292 all_categories = self.ask('','0',[], ask_class=AskforCustomize) 7293 put_to_one = [] 7294 ## Make a Temaplate for the restriction card. (card with no restrict) 7295 for block in param_card: 7296 value_dict = {} 7297 for param in param_card[block]: 7298 value = param.value 7299 if value == 0: 7300 param.value = 0.000001e-99 7301 elif value == 1: 7302 if block != 'qnumbers': 7303 put_to_one.append((block,param.lhacode)) 7304 param.value = random.random() 7305 elif abs(value) in value_dict: 7306 param.value += value_dict[abs(value)] * 1e-4 * param.value 7307 value_dict[abs(value)] += 1 7308 else: 7309 value_dict[abs(value)] = 1 7310 7311 for category in all_categories: 7312 for options in category: 7313 if not options.status: 7314 continue 7315 param = param_card[options.lhablock].get(options.lhaid) 7316 param.value = options.value 7317 7318 logger.info('Loading the resulting model') 7319 # Applying the restriction 7320 self._curr_model = import_ufo.RestrictModel(self._curr_model) 7321 model_name = self._curr_model.get('name') 7322 if model_name == 'mssm': 7323 keep_external=True 7324 else: 7325 keep_external=False 7326 self._curr_model.restrict_model(param_card,keep_external=keep_external) 7327 7328 if args: 7329 name = args[0].split('=',1)[1] 7330 path = pjoin(model_path,'restrict_%s.dat' % name) 7331 logger.info('Save restriction file as %s' % path) 7332 param_card.write(path) 7333 self._curr_model['name'] += '-%s' % name 7334 7335 # if some need to put on one 7336 if put_to_one: 7337 out_path = StringIO.StringIO() 7338 param_writer.ParamCardWriter(self._curr_model, out_path) 7339 # and load it to a python object 7340 param_card = check_param_card.ParamCard(out_path.getvalue().split('\n')) 7341 7342 for (block, lhacode) in put_to_one: 7343 try: 7344 param_card[block].get(lhacode).value = 1 7345 except: 7346 pass # was removed of the model! 7347 self._curr_model.set_parameters_and_couplings(param_card) 7348 7349 if args: 7350 name = args[0].split('=',1)[1] 7351 path = pjoin(model_path,'paramcard_%s.dat' % name) 7352 logger.info('Save default card file as %s' % path) 7353 param_card.write(path)
7354
7355 - def do_save(self, line, check=True, to_keep={}, log=True):
7356 """Not in help: Save information to file""" 7357 7358 7359 args = self.split_arg(line) 7360 # Check argument validity 7361 if check: 7362 self.check_save(args) 7363 7364 if args[0] == 'model': 7365 if self._curr_model: 7366 #save_model.save_model(args[1], self._curr_model) 7367 if save_load_object.save_to_file(args[1], self._curr_model): 7368 logger.info('Saved model to file %s' % args[1]) 7369 else: 7370 raise self.InvalidCmd('No model to save!') 7371 elif args[0] == 'processes': 7372 if self._curr_amps: 7373 if save_load_object.save_to_file(args[1], (self._curr_amps,self._curr_proc_defs) ): 7374 logger.info('Saved processes to file %s' % args[1]) 7375 else: 7376 raise self.InvalidCmd('No processes to save!') 7377 7378 elif args[0] == 'options': 7379 partial_save = False 7380 to_define = {} 7381 7382 if any(not arg.startswith('--') and arg in self.options 7383 for arg in args): 7384 # store in file only those ones 7385 partial_save = True 7386 all_arg = [arg for arg in args[1:] if not arg.startswith('--') and 7387 arg in self.options] 7388 for key in all_arg: 7389 to_define[key] = self.options[key] 7390 else: 7391 # First look at options which should be put in MG5DIR/input 7392 for key, default in self.options_configuration.items(): 7393 if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None: 7394 to_define[key] = self.options[key] 7395 7396 if not '--auto' in args: 7397 for key, default in self.options_madevent.items(): 7398 if self.options_madevent[key] != self.options[key] != None: 7399 if '_path' in key and os.path.basename(self.options[key]) == 'None': 7400 continue 7401 to_define[key] = self.options[key] 7402 elif key == 'cluster_queue' and self.options[key] is None: 7403 to_define[key] = self.options[key] 7404 7405 if '--all' in args: 7406 for key, default in self.options_madgraph.items(): 7407 if self.options_madgraph[key] != self.options[key] != None and \ 7408 key != 'stdout_level': 7409 to_define[key] = self.options[key] 7410 elif not '--auto' in args: 7411 for key, default in self.options_madgraph.items(): 7412 if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level': 7413 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 7414 % (key,self.options_madgraph[key]) ) 7415 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 7416 7417 if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options: 7418 filepath = args[1] 7419 else: 7420 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 7421 7422 basedir = MG5DIR 7423 if partial_save: 7424 basefile = filepath 7425 else: 7426 basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt') 7427 7428 7429 7430 if to_keep: 7431 to_define = to_keep 7432 self.write_configuration(filepath, basefile, basedir, to_define)
7433 7434 # Set an option
7435 - def do_set(self, line, log=True, model_reload=True):
7436 """Set an option, which will be default for coming generations/outputs. 7437 """ 7438 7439 # Be careful: 7440 # This command is associated to a post_cmd: post_set. 7441 args = self.split_arg(line) 7442 7443 # Check the validity of the arguments 7444 self.check_set(args) 7445 7446 if args[0] == 'ignore_six_quark_processes': 7447 if args[1].lower() == 'false': 7448 self.options[args[0]] = False 7449 return 7450 self.options[args[0]] = list(set([abs(p) for p in \ 7451 self._multiparticles[args[1]]\ 7452 if self._curr_model.get_particle(p).\ 7453 is_fermion() and \ 7454 self._curr_model.get_particle(abs(p)).\ 7455 get('color') == 3])) 7456 if log: 7457 logger.info('Ignore processes with >= 6 quarks (%s)' % \ 7458 ",".join([\ 7459 self._curr_model.get_particle(q).get('name') \ 7460 for q in self.options[args[0]]])) 7461 7462 elif args[0] == 'group_subprocesses': 7463 if args[1].lower() not in ['auto', 'nlo']: 7464 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, name="group_subprocesses") 7465 else: 7466 if args[1].lower() == 'nlo': 7467 self.options[args[0]] = "NLO" 7468 else: 7469 self.options[args[0]] = "Auto" 7470 if log: 7471 logger.info('Set group_subprocesses to %s' % \ 7472 str(self.options[args[0]])) 7473 logger.info('Note that you need to regenerate all processes') 7474 self._curr_amps = diagram_generation.AmplitudeList() 7475 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7476 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7477 7478 elif args[0] == "stdout_level": 7479 if args[1].isdigit(): 7480 level = int(args[1]) 7481 else: 7482 level = eval('logging.' + args[1]) 7483 logging.root.setLevel(level) 7484 logging.getLogger('madgraph').setLevel(level) 7485 logging.getLogger('madevent').setLevel(level) 7486 self.options[args[0]] = level 7487 if log: 7488 logger.info('set output information to level: %s' % level) 7489 elif args[0].lower() == "ewscheme": 7490 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." %\ 7491 (self._curr_model.get('name'), args[1])) 7492 logger.info("Importing a model will restore the default scheme") 7493 self._curr_model.change_electroweak_mode(args[1]) 7494 elif args[0] == "complex_mass_scheme": 7495 old = self.options[args[0]] 7496 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, "complex_mass_scheme") 7497 aloha.complex_mass = self.options[args[0]] 7498 aloha_lib.KERNEL.clean() 7499 if self.options[args[0]]: 7500 if old: 7501 if log: 7502 logger.info('Complex mass already activated.') 7503 return 7504 if log: 7505 logger.info('Activate complex mass scheme.') 7506 else: 7507 if not old: 7508 if log: 7509 logger.info('Complex mass already desactivated.') 7510 return 7511 if log: 7512 logger.info('Desactivate complex mass scheme.') 7513 if not self._curr_model: 7514 return 7515 self.exec_cmd('import model %s' % self._curr_model.get('name')) 7516 7517 elif args[0] == "gauge": 7518 # Treat the case where they are no model loaded 7519 if not self._curr_model: 7520 if args[1] == 'unitary': 7521 aloha.unitary_gauge = True 7522 elif args[1] == 'axial': 7523 aloha.unitary_gauge = 2 7524 else: 7525 aloha.unitary_gauge = False 7526 aloha_lib.KERNEL.clean() 7527 self.options[args[0]] = args[1] 7528 if log: logger.info('Passing to gauge %s.' % args[1]) 7529 return 7530 7531 # They are a valid model 7532 able_to_mod = True 7533 if args[1] == 'unitary': 7534 if 0 in self._curr_model.get('gauge'): 7535 aloha.unitary_gauge = True 7536 else: 7537 able_to_mod = False 7538 if log: logger.warning('Note that unitary gauge is not allowed for your current model %s' \ 7539 % self._curr_model.get('name')) 7540 elif args[1] == 'axial': 7541 if 0 in self._curr_model.get('gauge'): 7542 aloha.unitary_gauge = 2 7543 else: 7544 able_to_mod = False 7545 if log: logger.warning('Note that parton-shower gauge is not allowed for your current model %s' \ 7546 % self._curr_model.get('name')) 7547 else: 7548 if 1 in self._curr_model.get('gauge'): 7549 aloha.unitary_gauge = False 7550 else: 7551 able_to_mod = False 7552 if log: logger.warning('Note that Feynman gauge is not allowed for your current model %s' \ 7553 % self._curr_model.get('name')) 7554 7555 if self.options['gauge'] == args[1]: 7556 return 7557 7558 7559 self.options[args[0]] = args[1] 7560 7561 if able_to_mod and log and args[0] == 'gauge' and \ 7562 args[1] == 'unitary' and not self.options['gauge']=='unitary' and \ 7563 isinstance(self._curr_model,loop_base_objects.LoopModel) and \ 7564 not self._curr_model['perturbation_couplings'] in [[],['QCD']]: 7565 logger.warning('You will only be able to do tree level'+\ 7566 ' and QCD corrections in the unitary gauge.') 7567 7568 7569 7570 #re-init all variable 7571 model_name = self._curr_model.get('modelpath+restriction') 7572 self._curr_model = None 7573 self._curr_amps = diagram_generation.AmplitudeList() 7574 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7575 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7576 self._curr_helas_model = None 7577 self._curr_exporter = None 7578 self._done_export = False 7579 import_ufo._import_once = [] 7580 logger.info('Passing to gauge %s.' % args[1]) 7581 7582 if able_to_mod: 7583 # We don't want to go through the MasterCommand again 7584 # because it messes with the interface switching when 7585 # importing a loop model from MG5 7586 if 'modelname' in self.history.get('full_model_line'): 7587 opts = '--modelname' 7588 else: 7589 opts='' 7590 MadGraphCmd.do_import(self,'model %s %s' % (model_name, opts), force=True) 7591 elif log: 7592 logger.info('Note that you have to reload the model') 7593 7594 elif args[0] == 'fortran_compiler': 7595 if args[1] != 'None': 7596 if log: 7597 logger.info('set fortran compiler to %s' % args[1]) 7598 self.options['fortran_compiler'] = args[1] 7599 else: 7600 self.options['fortran_compiler'] = None 7601 elif args[0] == 'default_unset_couplings': 7602 self.options['default_unset_couplings'] = banner_module.ConfigFile.format_variable(args[1], int, name="default_unset_couplings") 7603 elif args[0].startswith('f2py_compiler'): 7604 to_do = True 7605 if args[0].endswith('_py2') and six.PY3: 7606 to_do = False 7607 elif args[0].endswith('_py3') and six.PY2: 7608 to_do = False 7609 if to_do: 7610 if args[1] != 'None': 7611 if log: 7612 logger.info('set f2py compiler to %s' % args[1]) 7613 7614 self.options['f2py_compiler'] = args[1] 7615 else: 7616 self.options['f2py_compiler'] = None 7617 7618 elif args[0] == 'loop_optimized_output': 7619 7620 if log: 7621 logger.info('set loop optimized output to %s' % args[1]) 7622 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7623 self.options[args[0]] = args[1] 7624 if not self.options['loop_optimized_output'] and \ 7625 self.options['loop_color_flows']: 7626 logger.warning("Turning off option 'loop_color_flows'"+\ 7627 " since it is not available for non-optimized loop output.") 7628 self.do_set('loop_color_flows False',log=False) 7629 elif args[0] == 'loop_color_flows': 7630 if log: 7631 logger.info('set loop color flows to %s' % args[1]) 7632 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7633 self.options[args[0]] = args[1] 7634 if self.options['loop_color_flows'] and \ 7635 not self.options['loop_optimized_output']: 7636 logger.warning("Turning on option 'loop_optimized'"+\ 7637 " needed for loop color flow computation.") 7638 self.do_set('loop_optimized_output True',False) 7639 7640 elif args[0] == 'fastjet': 7641 try: 7642 p = subprocess.Popen([args[1], '--version'], stdout=subprocess.PIPE, 7643 stderr=subprocess.PIPE) 7644 output, error = p.communicate() 7645 output = output.decode() 7646 res = 0 7647 except Exception: 7648 res = 1 7649 7650 if res != 0 or error: 7651 logger.info('%s does not seem to correspond to a valid fastjet-config ' % args[1] + \ 7652 'executable (v3+). We will use fjcore instead.\n Please set the \'fastjet\'' + \ 7653 'variable to the full (absolute) /PATH/TO/fastjet-config (including fastjet-config).' + 7654 '\n MG5_aMC> set fastjet /PATH/TO/fastjet-config\n') 7655 self.options[args[0]] = None 7656 if self.history and 'fastjet' in self.history[-1]: 7657 self.history.pop() 7658 elif int(output.split('.')[0]) < 3: 7659 logger.warning('%s is not ' % args[1] + \ 7660 'v3 or greater. Please install FastJet v3+.') 7661 self.options[args[0]] = None 7662 self.history.pop() 7663 else: #everything is fine 7664 logger.info('set fastjet to %s' % args[1]) 7665 self.options[args[0]] = args[1] 7666 7667 elif args[0] in ['golem','samurai','ninja','collier'] and \ 7668 not (args[0] in ['ninja','collier'] and args[1]=='./HEPTools/lib'): 7669 if args[1] in ['None',"''",'""']: 7670 self.options[args[0]] = None 7671 else: 7672 program = misc.which_lib(os.path.join(args[1],'lib%s.a'%args[0])) 7673 if program!=None: 7674 res = 0 7675 logger.info('set %s to %s' % (args[0],args[1])) 7676 self.options[args[0]] = args[1] 7677 else: 7678 res = 1 7679 7680 if res != 0 : 7681 logger.warning('%s does not seem to correspond to a valid %s lib ' % (args[1],args[0]) + \ 7682 '. Please enter the full PATH/TO/%s/lib .\n'%args[0] + \ 7683 'You will NOT be able to run %s otherwise.\n'%args[0]) 7684 7685 elif args[0].startswith('lhapdf'): 7686 to_do = True 7687 if args[0].endswith('_py2') and six.PY3: 7688 to_do = False 7689 elif args[0].endswith('_py3') and six.PY2: 7690 to_do = False 7691 if to_do: 7692 try: 7693 res = misc.call([args[1], '--version'], stdout=subprocess.PIPE, 7694 stderr=subprocess.PIPE) 7695 logger.info('set lhapdf to %s' % args[1]) 7696 self.options['lhapdf'] = args[1] 7697 self.options[args[0]] = args[1] 7698 except Exception: 7699 res = 1 7700 if res != 0: 7701 logger.info('%s does not seem to correspond to a valid lhapdf-config ' % args[1] + \ 7702 'executable. \nPlease set the \'lhapdf\' variable to the (absolute) ' + \ 7703 '/PATH/TO/lhapdf-config (including lhapdf-config).\n' + \ 7704 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n' + \ 7705 ' MG5_aMC> set lhapdf /PATH/TO/lhapdf-config\n') 7706 7707 elif args[0] in ['timeout', 'auto_update', 'cluster_nb_retry', 'max_t_for_channel', 7708 'cluster_retry_wait', 'cluster_size', 'max_npoint_for_channel']: 7709 self.options[args[0]] = int(args[1]) 7710 7711 elif args[0] in ['cluster_local_path']: 7712 self.options[args[0]] = args[1].strip() 7713 7714 elif args[0] == 'cluster_status_update': 7715 if '(' in args[1]: 7716 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 7717 data = data.replace('(','').replace(')','').replace(',',' ').split() 7718 first, second = data[:2] 7719 else: 7720 first, second = args[1:3] 7721 7722 self.options[args[0]] = (int(first), int(second)) 7723 7724 elif args[0] == 'madanalysis5_path': 7725 ma5path = pjoin(MG5DIR, args[1]) if os.path.isfile(pjoin(MG5DIR, args[1])) else args[1] 7726 message = misc.is_MA5_compatible_with_this_MG5(ma5path) 7727 if message is None: 7728 self.options['madanalysis5_path'] = args[1] 7729 else: 7730 logger.warning(message) 7731 7732 elif args[0] == 'OLP': 7733 if six.PY3 and self.options['low_mem_multicore_nlo_generation']: 7734 raise self.InvalidCmd('Not possible to set OLP with both \"low_mem_multicore_nlo_generation\" and python3') 7735 # Reset the amplitudes, MatrixElements and exporter as they might 7736 # depend on this option 7737 self._curr_amps = diagram_generation.AmplitudeList() 7738 self._curr_proc_defs = base_objects.ProcessDefinitionList() 7739 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 7740 self._curr_exporter = None 7741 self.options[args[0]] = args[1] 7742 7743 elif args[0] =='output_dependencies': 7744 self.options[args[0]] = args[1] 7745 elif args[0] =='notification_center': 7746 if args[1] in ['None','True','False']: 7747 self.options[args[0]] = eval(args[1]) 7748 self.allow_notification_center = self.options[args[0]] 7749 else: 7750 raise self.InvalidCmd('expected bool for notification_center') 7751 # True/False formatting 7752 elif args[0] in ['crash_on_error']: 7753 try: 7754 tmp = banner_module.ConfigFile.format_variable(args[1], bool, 'crash_on_error') 7755 except Exception: 7756 if args[1].lower() in ['never']: 7757 tmp = args[1].lower() 7758 else: 7759 raise 7760 self.options[args[0]] = tmp 7761 elif args[0] in ['zerowidth_tchannel']: 7762 self.options[args[0]] = banner_module.ConfigFile.format_variable(args[1], bool, args[0]) 7763 elif args[0] in ['cluster_queue']: 7764 self.options[args[0]] = args[1].strip() 7765 elif args[0] in ['low_mem_multicore_nlo_generation']: 7766 if six.PY3 and self.options['OLP'] != 'MadLoop': 7767 raise self.InvalidCmd('Not possible to set \"low_mem_multicore_nlo_generation\" for an OLP different of MadLoop when running python3') 7768 else: 7769 self.options[args[0]] = args[1] 7770 elif args[0] in self.options: 7771 if args[1] in ['None','True','False']: 7772 self.options[args[0]] = eval(args[1]) 7773 else: 7774 self.options[args[0]] = args[1]
7775
7776 - def post_set(self, stop, line):
7777 """Check if we need to save this in the option file""" 7778 7779 args = self.split_arg(line) 7780 # Check the validity of the arguments 7781 try: 7782 self.check_set(args, log=False) 7783 except Exception: 7784 return stop 7785 7786 if args[0] in self.options_configuration and '--no_save' not in args: 7787 self.exec_cmd('save options %s' % args[0] , log=False) 7788 elif args[0] in self.options_madevent: 7789 if not '--no_save' in line: 7790 logger.info('This option will be the default in any output that you are going to create in this session.') 7791 logger.info('In order to keep this changes permanent please run \'save options\'') 7792 else: 7793 #MadGraph5_aMC@NLO configuration 7794 if not self.history or self.history[-1].split() != line.split(): 7795 self.history.append('set %s' % line) 7796 self.avoid_history_duplicate('set %s' % args[0], ['define', 'set']) 7797 return stop
7798
7799 - def do_open(self, line):
7800 """Open a text file/ eps file / html file""" 7801 7802 args = self.split_arg(line) 7803 # Check Argument validity and modify argument to be the real path 7804 self.check_open(args) 7805 file_path = args[0] 7806 7807 launch_ext.open_file(file_path)
7808
7809 - def do_output(self, line):
7810 """Main commands: Initialize a new Template or reinitialize one""" 7811 7812 args = self.split_arg(line) 7813 # Check Argument validity 7814 self.check_output(args) 7815 7816 noclean = '-noclean' in args 7817 force = '-f' in args 7818 nojpeg = '-nojpeg' in args 7819 if '--noeps=True' in args: 7820 nojpeg = True 7821 flaglist = [] 7822 7823 if '--postpone_model' in args: 7824 flaglist.append('store_model') 7825 7826 line_options = dict(arg[2:].split('=') for arg in args if arg.startswith('--') and '=' in arg) 7827 main_file_name = "" 7828 try: 7829 main_file_name = args[args.index('-name') + 1] 7830 except Exception: 7831 pass 7832 7833 7834 ################ 7835 # ALOHA OUTPUT # 7836 ################ 7837 if self._export_format == 'aloha': 7838 # catch format 7839 format = [d[9:] for d in args if d.startswith('--format=')] 7840 if not format: 7841 format = 'Fortran' 7842 else: 7843 format = format[-1] 7844 # catch output dir 7845 output = [d for d in args if d.startswith('--output=')] 7846 if not output: 7847 output = import_ufo.find_ufo_path(self._curr_model['name']) 7848 output = pjoin(output, format) 7849 if not os.path.isdir(output): 7850 os.mkdir(output) 7851 else: 7852 output = output[-1] 7853 if not os.path.isdir(output): 7854 raise self.InvalidCmd('%s is not a valid directory' % output) 7855 logger.info('creating routines in directory %s ' % output) 7856 # build the calling list for aloha 7857 names = [d for d in args if not d.startswith('-')] 7858 wanted_lorentz = aloha_fct.guess_routine_from_name(names) 7859 # Create and write ALOHA Routine 7860 aloha_model = create_aloha.AbstractALOHAModel(self._curr_model.get('name')) 7861 aloha_model.add_Lorentz_object(self._curr_model.get('lorentz')) 7862 if wanted_lorentz: 7863 aloha_model.compute_subset(wanted_lorentz) 7864 else: 7865 aloha_model.compute_all(save=False) 7866 aloha_model.write(output, format) 7867 return 7868 7869 ################# 7870 ## Other Output # 7871 ################# 7872 # Configuration of what to do: 7873 # check: check status of the directory 7874 # exporter: which exporter to use (v4/cpp/...) 7875 # output: [Template/dir/None] copy the Template, just create dir or do nothing 7876 config = {} 7877 config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7878 config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'} 7879 config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7880 config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7881 config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7882 config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'} 7883 config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'} 7884 config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'} 7885 config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} 7886 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'} 7887 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'} 7888 7889 if self._export_format == 'plugin': 7890 options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output} 7891 else: 7892 options = config[self._export_format] 7893 7894 # check 7895 if os.path.realpath(self._export_dir) == os.getcwd(): 7896 if len(args) == 0: 7897 i=0 7898 while 1: 7899 if os.path.exists('Pythia8_proc_%i' %i): 7900 i+=1 7901 else: 7902 break 7903 os.mkdir('Pythia8_proc_%i' %i) 7904 self._export_dir = pjoin(self._export_dir, 'Pythia8_proc_%i' %i) 7905 logger.info('Create output in %s' % self._export_dir) 7906 elif not args[0] in ['.', '-f']: 7907 raise self.InvalidCmd('Wrong path directory to create in local directory use \'.\'') 7908 elif not noclean and os.path.isdir(self._export_dir) and options['check']: 7909 if not force: 7910 # Don't ask if user already specified force or noclean 7911 logger.info('INFO: directory %s already exists.' % self._export_dir) 7912 logger.info('If you continue this directory will be deleted and replaced.') 7913 answer = self.ask('Do you want to continue?', 'y', ['y','n']) 7914 else: 7915 answer = 'y' 7916 if answer != 'y': 7917 raise self.InvalidCmd('Stopped by user request') 7918 else: 7919 shutil.rmtree(self._export_dir) 7920 7921 # Choose here whether to group subprocesses or not, if the option was 7922 # set to 'Auto' and propagate this choice down the line: 7923 if self.options['group_subprocesses'] in [True, False]: 7924 group_processes = self.options['group_subprocesses'] 7925 elif self.options['group_subprocesses'] == 'Auto': 7926 # By default we set it to True 7927 group_processes = True 7928 # But we turn if off for decay processes which 7929 # have been defined with multiparticle labels, because then 7930 # branching ratios necessitates to keep subprocesses independent. 7931 # That applies only if there is more than one subprocess of course. 7932 if self._curr_amps[0].get_ninitial() == 1 and \ 7933 len(self._curr_amps)>1: 7934 7935 processes = [amp.get('process') for amp in self._curr_amps if 'process' in list(amp.keys())] 7936 if len(set(proc.get('id') for proc in processes))!=len(processes): 7937 # Special warning for loop-induced 7938 if any(proc['perturbation_couplings'] != [] for proc in 7939 processes) and self._export_format == 'madevent': 7940 logger.warning(""" 7941 || The loop-induced decay process you have specified contains several 7942 || subprocesses and, in order to be able to compute individual branching ratios, 7943 || MG5_aMC will *not* group them. Integration channels will also be considered 7944 || for each diagrams and as a result integration will be inefficient. 7945 || It is therefore recommended to perform this simulation by setting the MG5_aMC 7946 || option 'group_subprocesses' to 'True' (before the output of the process). 7947 || Notice that when doing so, processes for which one still wishes to compute 7948 || branching ratios independently can be specified using the syntax: 7949 || -> add process <proc_def> 7950 """) 7951 group_processes = False 7952 7953 #Exporter + Template 7954 if options['exporter'] == 'v4': 7955 self._curr_exporter = export_v4.ExportV4Factory(self, noclean, 7956 group_subprocesses=group_processes, 7957 cmd_options=line_options) 7958 elif options['exporter'] == 'cpp': 7959 self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes, 7960 cmd_options=line_options) 7961 7962 self._curr_exporter.pass_information_from_cmd(self) 7963 7964 if options['output'] == 'Template': 7965 self._curr_exporter.copy_template(self._curr_model) 7966 elif options['output'] == 'dir' and not os.path.isdir(self._export_dir): 7967 os.makedirs(self._export_dir) 7968 7969 # Reset _done_export, since we have new directory 7970 self._done_export = False 7971 7972 if self._export_format == "madevent": 7973 # for MadEvent with MadLoop decide if we keep the box as channel of 7974 #integration or not. Forbid them for matching and for h+j 7975 if self.options['max_npoint_for_channel']: 7976 base_objects.Vertex.max_n_loop_for_multichanneling = self.options['max_npoint_for_channel'] 7977 else: 7978 base_objects.Vertex.max_n_loop_for_multichanneling = 3 7979 base_objects.Vertex.max_tpropa = self.options['max_t_for_channel'] 7980 7981 # Perform export and finalize right away 7982 self.export(nojpeg, main_file_name, group_processes, args) 7983 7984 # Automatically run finalize 7985 self.finalize(nojpeg, flaglist=flaglist) 7986 7987 # Remember that we have done export 7988 self._done_export = (self._export_dir, self._export_format) 7989 7990 # Reset _export_dir, so we don't overwrite by mistake later 7991 self._export_dir = None
7992 7993 # Export a matrix element
7994 - def export(self, nojpeg = False, main_file_name = "", group_processes=True, 7995 args=[]):
7996 """Export a generated amplitude to file.""" 7997 7998 7999 # Define the helas call writer 8000 if self._curr_exporter.exporter == 'cpp': 8001 self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model) 8002 elif self._model_v4_path: 8003 assert self._curr_exporter.exporter == 'v4' 8004 self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model) 8005 else: 8006 assert self._curr_exporter.exporter == 'v4' 8007 options = {'zerowidth_tchannel': True} 8008 if self._curr_amps and self._curr_amps[0].get_ninitial() == 1: 8009 options['zerowidth_tchannel'] = False 8010 8011 self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model) 8012 8013 version = [arg[10:] for arg in args if arg.startswith('--version=')] 8014 if version: 8015 version = version[-1] 8016 else: 8017 version = '8.2' 8018 8019 def generate_matrix_elements(self, group_processes=True): 8020 """Helper function to generate the matrix elements before 8021 exporting. Uses the main function argument 'group_processes' to decide 8022 whether to use group_subprocess or not. (it has been set in do_output to 8023 the appropriate value if the MG5 option 'group_subprocesses' was set 8024 to 'Auto'.""" 8025 8026 if self._export_format in ['standalone_msP', 'standalone_msF', 'standalone_mw']: 8027 to_distinguish = [] 8028 for part in self._curr_model.get('particles'): 8029 if part.get('name') in args and part.get('antiname') in args and\ 8030 part.get('name') != part.get('antiname'): 8031 to_distinguish.append(abs(part.get('pdg_code'))) 8032 # Sort amplitudes according to number of diagrams, 8033 # to get most efficient multichannel output 8034 self._curr_amps.sort(key=lambda x: x.get_number_of_diagrams(),reverse=True) 8035 8036 cpu_time1 = time.time() 8037 ndiags = 0 8038 if not self._curr_matrix_elements.get_matrix_elements(): 8039 if group_processes: 8040 cpu_time1 = time.time() 8041 dc_amps = diagram_generation.DecayChainAmplitudeList(\ 8042 [amp for amp in self._curr_amps if isinstance(amp, \ 8043 diagram_generation.DecayChainAmplitude)]) 8044 non_dc_amps = diagram_generation.AmplitudeList(\ 8045 [amp for amp in self._curr_amps if not \ 8046 isinstance(amp, \ 8047 diagram_generation.DecayChainAmplitude)]) 8048 subproc_groups = group_subprocs.SubProcessGroupList() 8049 matrix_elements_opts = {'optimized_output': 8050 self.options['loop_optimized_output']} 8051 8052 grouping_criteria = self._curr_exporter.grouped_mode 8053 if non_dc_amps: 8054 subproc_groups.extend(\ 8055 group_subprocs.SubProcessGroup.group_amplitudes(\ 8056 non_dc_amps,grouping_criteria, 8057 matrix_elements_opts=matrix_elements_opts)) 8058 8059 if dc_amps: 8060 dc_subproc_group = \ 8061 group_subprocs.DecayChainSubProcessGroup.\ 8062 group_amplitudes(dc_amps, grouping_criteria, 8063 matrix_elements_opts=matrix_elements_opts) 8064 subproc_groups.extend(dc_subproc_group.\ 8065 generate_helas_decay_chain_subproc_groups()) 8066 8067 ndiags = sum([len(m.get('diagrams')) for m in \ 8068 subproc_groups.get_matrix_elements()]) 8069 self._curr_matrix_elements = subproc_groups 8070 # assign a unique id number to all groups 8071 uid = 0 8072 for group in subproc_groups: 8073 uid += 1 # update the identification number 8074 for me in group.get('matrix_elements'): 8075 me.get('processes')[0].set('uid', uid) 8076 else: # Not grouped subprocesses 8077 mode = {} 8078 if self._export_format in [ 'standalone_msP' , 8079 'standalone_msF', 'standalone_rw']: 8080 mode['mode'] = 'MadSpin' 8081 # The conditional statement tests whether we are dealing 8082 # with a loop induced process. 8083 if isinstance(self._curr_amps[0], 8084 loop_diagram_generation.LoopAmplitude): 8085 mode['optimized_output']=self.options['loop_optimized_output'] 8086 HelasMultiProcessClass = loop_helas_objects.LoopHelasProcess 8087 compute_loop_nc = True 8088 else: 8089 HelasMultiProcessClass = helas_objects.HelasMultiProcess 8090 compute_loop_nc = False 8091 8092 self._curr_matrix_elements = HelasMultiProcessClass( 8093 self._curr_amps, compute_loop_nc=compute_loop_nc, 8094 matrix_element_opts=mode) 8095 8096 ndiags = sum([len(me.get('diagrams')) for \ 8097 me in self._curr_matrix_elements.\ 8098 get_matrix_elements()]) 8099 # assign a unique id number to all process 8100 uid = 0 8101 for me in self._curr_matrix_elements.get_matrix_elements()[:]: 8102 uid += 1 # update the identification number 8103 me.get('processes')[0].set('uid', uid) 8104 8105 cpu_time2 = time.time() 8106 8107 8108 return ndiags, cpu_time2 - cpu_time1
8109 8110 # Start of the actual routine 8111 8112 ndiags, cpu_time = generate_matrix_elements(self,group_processes) 8113 8114 calls = 0 8115 8116 path = self._export_dir 8117 8118 cpu_time1 = time.time() 8119 8120 # First treat madevent and pythia8 exports, where we need to 8121 # distinguish between grouped and ungrouped subprocesses 8122 8123 # MadEvent 8124 if self._export_format == 'madevent': 8125 calls += self._curr_exporter.export_processes(self._curr_matrix_elements, 8126 self._curr_helas_model) 8127 8128 #try: 8129 # cmd.Cmd.onecmd(self, 'history .') 8130 #except Exception: 8131 # misc.sprint('command history fails.', 10) 8132 # pass 8133 8134 # Pythia 8 8135 elif self._export_format == 'pythia8': 8136 # Output the process files 8137 process_names = [] 8138 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList): 8139 for (group_number, me_group) in enumerate(self._curr_matrix_elements): 8140 exporter = self._curr_exporter.generate_process_directory(\ 8141 me_group.get('matrix_elements'), self._curr_helas_model, 8142 process_string = me_group.get('name'), 8143 process_number = group_number+1, 8144 version = version) 8145 process_names.append(exporter.process_name) 8146 else: 8147 exporter = self._curr_exporter.generate_process_directory(\ 8148 self._curr_matrix_elements, self._curr_helas_model, 8149 process_string = self._generate_info, version = version) 8150 process_names.append(exporter.process_file_name) 8151 8152 # Output the model parameter and ALOHA files 8153 model_name, model_path = exporter.convert_model_to_pythia8(\ 8154 self._curr_model, self._export_dir) 8155 8156 # Generate the main program file 8157 filename, make_filename = \ 8158 self._curr_exporter.generate_example_file_pythia8(path, 8159 model_path, 8160 process_names, 8161 exporter, 8162 main_file_name) 8163 8164 8165 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8166 # Just the matrix.f files 8167 if self._export_format == 'matrix': 8168 for me in matrix_elements: 8169 filename = pjoin(path, 'matrix_' + \ 8170 me.get('processes')[0].shell_string() + ".f") 8171 if os.path.isfile(filename): 8172 logger.warning("Overwriting existing file %s" % filename) 8173 else: 8174 logger.info("Creating new file %s" % filename) 8175 calls = calls + self._curr_exporter.write_matrix_element_v4(\ 8176 writers.FortranWriter(filename),\ 8177 me, self._curr_helas_model) 8178 elif self._export_format in ['madevent', 'pythia8']: 8179 pass 8180 # grouping mode 8181 elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\ 8182 self._curr_exporter.grouped_mode: 8183 modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements) 8184 if modify: 8185 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8186 8187 for me_number, me in enumerate(self._curr_matrix_elements): 8188 calls = calls + \ 8189 self._curr_exporter.generate_subprocess_directory(\ 8190 me, self._curr_helas_model, me_number) 8191 8192 # ungroup mode 8193 else: 8194 for nb,me in enumerate(matrix_elements[:]): 8195 new_calls = self._curr_exporter.generate_subprocess_directory(\ 8196 me, self._curr_helas_model, nb) 8197 if isinstance(new_calls, int): 8198 if new_calls ==0: 8199 matrix_elements.remove(me) 8200 else: 8201 calls = calls + new_calls 8202 8203 if self._generate_info and hasattr(self._curr_exporter, 'write_procdef_mg5'): 8204 # Write the procdef_mg5.dat file with process info 8205 card_path = pjoin(self._export_dir ,'SubProcesses', \ 8206 'procdef_mg5.dat') 8207 self._curr_exporter.write_procdef_mg5(card_path, 8208 self._curr_model['name'], 8209 self._generate_info) 8210 8211 8212 cpu_time2 = time.time() - cpu_time1 8213 8214 logger.info(("Generated helas calls for %d subprocesses " + \ 8215 "(%d diagrams) in %0.3f s") % \ 8216 (len(matrix_elements), 8217 ndiags, cpu_time)) 8218 8219 if calls: 8220 if "cpu_time2" in locals(): 8221 logger.info("Wrote files for %d helas calls in %0.3f s" % \ 8222 (calls, cpu_time2)) 8223 else: 8224 logger.info("Wrote files for %d helas calls" % \ 8225 (calls)) 8226 8227 if self._export_format == 'pythia8': 8228 logger.info("- All necessary files for Pythia 8 generated.") 8229 logger.info("- Run \"launch\" and select %s.cc," % filename) 8230 logger.info(" or go to %s/examples and run" % path) 8231 logger.info(" make -f %s" % make_filename) 8232 logger.info(" (with process_name replaced by process name).") 8233 logger.info(" You can then run ./%s to produce events for the process" % \ 8234 filename) 8235 8236 # Replace the amplitudes with the actual amplitudes from the 8237 # matrix elements, which allows proper diagram drawing also of 8238 # decay chain processes 8239 matrix_elements = self._curr_matrix_elements.get_matrix_elements() 8240 self._curr_amps = diagram_generation.AmplitudeList(\ 8241 [me.get('base_amplitude') for me in \ 8242 matrix_elements]) 8243
8244 - def finalize(self, nojpeg, online = False, flaglist=[]):
8245 """Make the html output, write proc_card_mg5.dat and create 8246 madevent.tar.gz for a MadEvent directory""" 8247 8248 compiler_dict = {'fortran': self.options['fortran_compiler'], 8249 'cpp': self.options['cpp_compiler'], 8250 'f2py': self.options['f2py_compiler']} 8251 8252 # Handling of the model. 8253 if self._model_v4_path: 8254 logger.info('Copy %s model files to directory %s' % \ 8255 (os.path.basename(self._model_v4_path), self._export_dir)) 8256 self._curr_exporter.export_model_files(self._model_v4_path) 8257 self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS')) 8258 else: 8259 # wanted_lorentz are the lorentz structures which are 8260 # actually used in the wavefunctions and amplitudes in 8261 # these processes 8262 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz() 8263 wanted_couplings = self._curr_matrix_elements.get_used_couplings() 8264 # For a unique output of multiple type of exporter need to store this 8265 # information. 8266 if hasattr(self, 'previous_lorentz'): 8267 wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz)) 8268 wanted_couplings = list(set(self.previous_couplings + wanted_couplings)) 8269 del self.previous_lorentz 8270 del self.previous_couplings 8271 if 'store_model' in flaglist: 8272 self.previous_lorentz = wanted_lorentz 8273 self.previous_couplings = wanted_couplings 8274 else: 8275 self._curr_exporter.convert_model(self._curr_model, 8276 wanted_lorentz, 8277 wanted_couplings) 8278 8279 # move the old options to the flaglist system. 8280 if nojpeg: 8281 flaglist.append('nojpeg') 8282 if online: 8283 flaglist.append('online') 8284 8285 8286 8287 if self._export_format in ['NLO']: 8288 ## write fj_lhapdf_opts file 8289 # Create configuration file [path to executable] for amcatnlo 8290 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt') 8291 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path', 8292 'hepmc_path'] 8293 to_keep = {} 8294 for opt in opts_to_keep: 8295 if self.options[opt]: 8296 to_keep[opt] = self.options[opt] 8297 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, \ 8298 to_keep = to_keep) 8299 8300 elif self._export_format in ['madevent', 'madweight']: 8301 # Create configuration file [path to executable] for madevent 8302 filename = os.path.join(self._export_dir, 'Cards', 'me5_configuration.txt') 8303 self.do_save('options %s' % filename.replace(' ', '\ '), check=False, 8304 to_keep={'mg5_path':MG5DIR}) 8305 8306 # Dedicated finalize function. 8307 self._curr_exporter.finalize(self._curr_matrix_elements, 8308 self.history, 8309 self.options, 8310 flaglist) 8311 8312 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']: 8313 logger.info('Output to directory ' + self._export_dir + ' done.') 8314 8315 if self._export_format in ['madevent', 'NLO']: 8316 logger.info('Type \"launch\" to generate events from this process, or see') 8317 logger.info(self._export_dir + '/README') 8318 logger.info('Run \"open index.html\" to see more information about this process.')
8319
8320 - def do_help(self, line):
8321 """ propose some usefull possible action """ 8322 8323 super(MadGraphCmd,self).do_help(line) 8324 8325 if line: 8326 return 8327 8328 if len(self.history) == 0: 8329 last_action_2 = 'mg5_start' 8330 last_action = 'mg5_start' 8331 else: 8332 args = self.history[-1].split() 8333 last_action = args[0] 8334 if len(args)>1: 8335 last_action_2 = '%s %s' % (last_action, args[1]) 8336 else: 8337 last_action_2 = 'none'
8338 8339 8340 8341 # Calculate decay width
8342 - def do_compute_widths(self, line, model=None, do2body=True, decaymodel=None):
8343 """Documented commands:Generate amplitudes for decay width calculation, with fixed 8344 number of final particles (called level) 8345 syntax; compute_widths particle [other particles] [--options=] 8346 8347 - particle/other particles can also be multiparticle name (can also be 8348 pid of the particle) 8349 8350 --body_decay=X [default=4.0025] allow to choose the precision. 8351 if X is an integer: compute all X body decay 8352 if X is a float <1: compute up to the time that total error < X 8353 if X is a float >1: stops at the first condition. 8354 8355 --path=X. Use a given file for the param_card. (default UFO built-in) 8356 8357 special argument: 8358 - skip_2body: allow to not consider those decay (use FR) 8359 - model: use the model pass in argument. 8360 8361 """ 8362 8363 8364 8365 self.change_principal_cmd('MadGraph') 8366 if '--nlo' not in line: 8367 warning_text = """Please note that the automatic computation of the width is 8368 only valid in narrow-width approximation and at tree-level.""" 8369 logger.warning(warning_text) 8370 8371 if not model: 8372 modelname = self._curr_model.get('modelpath+restriction') 8373 with misc.MuteLogger(['madgraph'], ['INFO']): 8374 model = import_ufo.import_model(modelname, decay=True) 8375 self._curr_model = model 8376 8377 if not isinstance(model, model_reader.ModelReader): 8378 model = model_reader.ModelReader(model) 8379 8380 if '--nlo' in line: 8381 # call SMWidth to calculate NLO Width 8382 self.compute_widths_SMWidth(line, model=model) 8383 return 8384 8385 # check the argument and return those in a dictionary format 8386 particles, opts = self.check_compute_widths(self.split_arg(line)) 8387 8388 if opts['path']: 8389 correct = True 8390 param_card = check_param_card.ParamCard(opts['path']) 8391 for param in param_card['decay']: 8392 if param.value == "auto": 8393 param.value = 1 8394 param.format = 'float' 8395 correct = False 8396 if not correct: 8397 if opts['output']: 8398 param_card.write(opts['output']) 8399 opts['path'] = opts['output'] 8400 else: 8401 param_card.write(opts['path']) 8402 8403 data = model.set_parameters_and_couplings(opts['path']) 8404 8405 8406 # find UFO particles linked to the require names. 8407 if do2body: 8408 skip_2body = True 8409 decay_info = {} 8410 for pid in particles: 8411 particle = model.get_particle(pid) 8412 if not hasattr(particle, 'partial_widths'): 8413 skip_2body = False 8414 break 8415 elif not decay_info: 8416 logger_mg.info('Get two body decay from FeynRules formula') 8417 decay_info[pid] = [] 8418 mass = abs(eval(str(particle.get('mass')), data).real) 8419 data = model.set_parameters_and_couplings(opts['path'], scale= mass) 8420 total = 0 8421 8422 # check if the value of alphas is set to zero and raise warning if appropriate 8423 if 'aS' in data and data['aS'] == 0 and particle.get('color') != 1: 8424 logger.warning("aS set to zero for this particle since the running is not defined for such low mass.") 8425 8426 for mode, expr in particle.partial_widths.items(): 8427 tmp_mass = mass 8428 for p in mode: 8429 try: 8430 value_mass = eval(str(p.mass), data) 8431 except Exception: 8432 # the p object can still be UFO reference. since the 8433 # mass name might hve change load back the MG5 one. 8434 value_mass = eval(str(model.get_particle(p.pdg_code).get('mass')), data) 8435 tmp_mass -= abs(value_mass) 8436 if tmp_mass <=0: 8437 continue 8438 8439 decay_to = [p.get('pdg_code') for p in mode] 8440 value = eval(expr,{'cmath':cmath},data).real 8441 if -1e-10 < value < 0: 8442 value = 0 8443 if -1e-5 < value < 0: 8444 logger.warning('Partial width for %s > %s negative: %s automatically set to zero' % 8445 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 8446 value = 0 8447 elif value < 0: 8448 raise Exception('Partial width for %s > %s negative: %s' % \ 8449 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)) 8450 elif 0 < value < 0.1 and particle['color'] !=1: 8451 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 8452 % (particle.get('name'), value, decay_to)) 8453 value = 0 8454 8455 decay_info[particle.get('pdg_code')].append([decay_to, value]) 8456 total += value 8457 else: 8458 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 8459 opts['path'], opts['output']) 8460 if float(opts['body_decay']) == 2: 8461 return decay_info 8462 else: 8463 skip_2body = True 8464 8465 # 8466 # add info from decay module 8467 # 8468 8469 self.do_decay_diagram('%s %s' % (' '.join([repr(id) for id in particles]), 8470 ' '.join('--%s=%s' % (key,value) 8471 for key,value in opts.items() 8472 if key not in ['precision_channel']) 8473 ), skip_2body=skip_2body, model=decaymodel) 8474 8475 if self._curr_amps: 8476 logger.info('Pass to numerical integration for computing the widths:') 8477 else: 8478 logger.info('No need for N body-decay (N>2). Results are in %s' % opts['output']) 8479 8480 8481 8482 return decay_info 8483 8484 # Do the MadEvent integration!! 8485 with misc.TMP_directory(dir=os.getcwd()) as path: 8486 decay_dir = pjoin(path,'temp_decay') 8487 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir)) 8488 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]): 8489 self.exec_cmd('output madevent %s -f' % decay_dir,child=False) 8490 8491 #modify some parameter of the default run_card 8492 run_card = banner_module.RunCard(pjoin(decay_dir,'Cards','run_card.dat')) 8493 if run_card['ickkw']: 8494 run_card['ickkw'] = 0 8495 run_card['xqcut'] = 0 8496 run_card.remove_all_cut() 8497 run_card.write(pjoin(decay_dir,'Cards','run_card.dat')) 8498 8499 # Need to write the correct param_card in the correct place !!! 8500 if os.path.exists(opts['output']): 8501 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 8502 else: 8503 files.cp(opts['path'], pjoin(decay_dir, 'Cards', 'param_card.dat')) 8504 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 8505 check_param_card.convert_to_slha1(pjoin(decay_dir, 'Cards', 'param_card.dat')) 8506 # call a ME interface and define as it as child for correct error handling 8507 me_cmd = madevent_interface.MadEventCmd(decay_dir) 8508 for name, val in self.options.items(): 8509 if name in me_cmd.options and me_cmd.options[name] != val: 8510 self.exec_cmd('set %s %s --no_save' % (name, val)) 8511 #me_cmd.options.update(self.options) 8512 #me_cmd.configure_run_mode(self.options['run_mode']) 8513 #self.define_child_cmd_interface(me_cmd, interface=False) 8514 me_cmd.model_name = self._curr_model['name'] #needed for mssm 8515 me_cmd.options['automatic_html_opening'] = False 8516 8517 me_opts=[('accuracy', opts['precision_channel']), # default 0.01 8518 ('points', 1000), 8519 ('iterations',9)] 8520 me_cmd.exec_cmd('survey decay -f %s' % ( 8521 " ".join(['--%s=%s' % val for val in me_opts])), 8522 postcmd=False) 8523 me_cmd.exec_cmd('combine_events', postcmd=False) 8524 #me_cmd.exec_cmd('store_events', postcmd=False) 8525 me_cmd.collect_decay_widths() 8526 me_cmd.do_quit('') 8527 # cleaning 8528 del me_cmd 8529 8530 param = check_param_card.ParamCard(pjoin(decay_dir, 'Events', 'decay','param_card.dat')) 8531 8532 for pid in particles: 8533 width = param['decay'].get((pid,)).value 8534 particle = self._curr_model.get_particle(pid) 8535 #if particle['color'] !=1 and 0 < width.real < 0.1: 8536 # logger.warning("width of colored particle \"%s(%s)\" lower than QCD scale: %s. Set width to zero " 8537 # % (particle.get('name'), pid, width.real)) 8538 # width = 0 8539 8540 8541 if not pid in param['decay'].decay_table: 8542 continue 8543 if pid not in decay_info: 8544 decay_info[pid] = [] 8545 for BR in param['decay'].decay_table[pid]: 8546 if len(BR.lhacode) == 3 and skip_2body: 8547 continue 8548 if 0 < BR.value * width <0.1 and particle['color'] !=1: 8549 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \ 8550 % (particle.get('name'), BR.value * width, BR.lhacode[1:])) 8551 8552 continue 8553 8554 decay_info[pid].append([BR.lhacode[1:], BR.value * width]) 8555 8556 madevent_interface.MadEventCmd.update_width_in_param_card(decay_info, 8557 opts['path'], opts['output']) 8558 8559 if self._curr_model['name'] == 'mssm' or self._curr_model['name'].startswith('mssm-'): 8560 check_param_card.convert_to_slha1(opts['output']) 8561 return decay_info
8562 8563 8564 8565 # Calculate decay width with SMWidth
8566 - def compute_widths_SMWidth(self, line, model=None):
8567 """Compute widths with SMWidth. 8568 """ 8569 8570 # check the argument and return those in a dictionary format 8571 particles, opts = self.check_compute_widths(self.split_arg(line)) 8572 8573 if opts['path']: 8574 correct = True 8575 param_card = check_param_card.ParamCard(opts['path']) 8576 for param in param_card['decay']: 8577 if param.value == "auto": 8578 param.value = 1 8579 param.format = 'float' 8580 correct = False 8581 if not correct: 8582 if opts['output']: 8583 param_card.write(opts['output']) 8584 opts['path'] = opts['output'] 8585 else: 8586 param_card.write(opts['path']) 8587 8588 if not model: 8589 model_path = self._curr_model.get('modelpath') 8590 model_name = self._curr_model.get('name') 8591 currmodel = self._curr_model 8592 else: 8593 model_path = model.get('modelpath') 8594 model_name = model.get('name') 8595 currmodel = model 8596 8597 if not os.path.exists(pjoin(model_path, 'SMWidth')): 8598 raise self.InvalidCmd("Model %s is not valid for computing NLO width with SMWidth"%model_name) 8599 8600 # determine the EW scheme 8601 externparam = [(param.lhablock.lower(),param.name.lower()) for param \ 8602 in currmodel.get('parameters')[('external',)]] 8603 8604 if ('sminputs','aewm1') in externparam: 8605 # alpha(MZ) scheme 8606 arg2 = "1" 8607 elif ('sminputs','mdl_gf') in externparam or ('sminputs','gf') in externparam: 8608 # Gmu scheme 8609 arg2 = "2" 8610 else: 8611 raise Exception("Do not know the EW scheme in the model %s"%model_name) 8612 8613 #compile the code 8614 if not os.path.exists(pjoin(model_path, 'SMWidth','smwidth')): 8615 logger.info('Compiling SMWidth. This has to be done only once and'+\ 8616 ' can take a couple of minutes.','$MG:BOLD') 8617 current = misc.detect_current_compiler(pjoin(model_path, 'SMWidth', 8618 'makefile_MW5')) 8619 new = 'gfortran' if self.options_configuration['fortran_compiler'] is None else \ 8620 self.options_configuration['fortran_compiler'] 8621 if current != new: 8622 misc.mod_compilator(pjoin(model_path, 'SMWidth'), new, current) 8623 misc.mod_compilator(pjoin(model_path, 'SMWidth','oneloop'), new, current) 8624 misc.mod_compilator(pjoin(model_path, 'SMWidth','hdecay'), new, current) 8625 misc.compile(cwd=pjoin(model_path, 'SMWidth')) 8626 8627 # look for the ident_card.dat 8628 identpath=" " 8629 carddir=os.path.dirname(opts['path']) 8630 if 'ident_card.dat' in os.listdir(carddir): 8631 identpath=pjoin(carddir,'ident_card.dat') 8632 #run the code 8633 output,error = misc.Popen(['./smwidth',opts['path'],identpath,arg2], 8634 stdout=subprocess.PIPE, 8635 stdin=subprocess.PIPE, 8636 cwd=pjoin(model_path, 'SMWidth')).communicate() 8637 pattern = re.compile(r''' decay\s+(\+?\-?\d+)\s+(\+?\-?\d+\.\d+E\+?\-?\d+)''',re.I) 8638 width_list = pattern.findall(output.decode()) 8639 width_dict = {} 8640 for pid,width in width_list: 8641 width_dict[int(pid)] = float(width) 8642 8643 for pid in particles: 8644 if not pid in width_dict: 8645 width = 0 8646 else: 8647 width = width_dict[pid] 8648 param = param_card['decay'].get((pid,)) 8649 param.value = width 8650 param.format = 'float' 8651 if pid not in param_card['decay'].decay_table: 8652 continue 8653 del param_card['decay'].decay_table[pid] # reset the BR 8654 # write the output file. (the new param_card) 8655 if opts['output']: 8656 param_card.write(opts['output']) 8657 logger.info('Results are written in %s' % opts['output']) 8658 else: 8659 param_card.write(opts['path']) 8660 logger.info('Results are written in %s' % opts['path']) 8661 return
8662 8663 # Calculate decay width
8664 - def do_decay_diagram(self, line, skip_2body=False, model=None):
8665 """Not in help: Generate amplitudes for decay width calculation, with fixed 8666 number of final particles (called level) 8667 syntax; decay_diagram part_name level param_path 8668 args; part_name level param_path 8669 part_name = name of the particle you want to calculate width 8670 level = a.) when level is int, 8671 it means the max number of decay products 8672 b.) when level is float, 8673 it means the required precision for width. 8674 param_path = path for param_card 8675 (this is necessary to determine whether a channel is onshell or not) 8676 e.g. calculate width for higgs up to 2-body decays. 8677 calculate_width h 2 [path] 8678 N.B. param_card must be given so that the program knows which channel 8679 is on shell and which is not. 8680 8681 special argument: 8682 - skip_2body: allow to not consider those decay (use FR) 8683 - model: use the model pass in argument. 8684 """ 8685 8686 if model: 8687 self._curr_decaymodel = model 8688 8689 8690 args = self.split_arg(line) 8691 #check the validity of the arguments 8692 particles, args = self.check_decay_diagram(args) 8693 #print args 8694 pids = particles 8695 level = float(args['body_decay']) 8696 param_card_path = args['path'] 8697 min_br = float(args['min_br']) 8698 8699 # Reset amplitudes 8700 self._curr_amps = diagram_generation.AmplitudeList() 8701 self._curr_proc_defs = base_objects.ProcessDefinitionList() 8702 # Reset Helas matrix elements 8703 self._curr_matrix_elements = helas_objects.HelasMultiProcess() 8704 # Reset _done_export, since we have new process 8705 self._done_export = False 8706 # Also reset _export_format and _export_dir 8707 self._export_format = None 8708 8709 8710 # Setup before find_channels 8711 if not model: 8712 self._curr_decaymodel = decay_objects.DecayModel(self._curr_model, 8713 True) 8714 self._curr_decaymodel.read_param_card(param_card_path) 8715 else: 8716 self._curr_decaymodel = model 8717 model = self._curr_decaymodel 8718 8719 if isinstance(pids, int): 8720 pids = [pids] 8721 8722 first =True 8723 for part_nb,pid in enumerate(pids): 8724 part = self._curr_decaymodel.get_particle(pid) 8725 if part.get('width').lower() == 'zero': 8726 continue 8727 logger_mg.info('get decay diagram for %s' % part['name']) 8728 # Find channels as requested 8729 if level // 1 == level and level >1: 8730 level = int(level) 8731 self._curr_decaymodel.find_channels(part, level, min_br) 8732 if not skip_2body: 8733 amp = part.get_amplitudes(2) 8734 if amp: 8735 self._curr_amps.extend(amp) 8736 8737 for l in range(3, level+1): 8738 amp = part.get_amplitudes(l) 8739 if amp: 8740 self._curr_amps.extend(amp) 8741 else: 8742 max_level = level // 1 8743 if max_level < 2: 8744 max_level = 999 8745 precision = level % 1 8746 if first: 8747 model.find_all_channels(2,generate_abstract=False) 8748 first = False 8749 if not skip_2body: 8750 amp = part.get_amplitudes(2) 8751 if amp: 8752 self._curr_amps.extend(amp) 8753 clevel = 2 8754 while part.get('apx_decaywidth_err').real > precision: 8755 clevel += 1 8756 if clevel > max_level: 8757 logger_mg.info(' stop to %s body-decay. approximate error: %s' % 8758 (max_level, part.get('apx_decaywidth_err')) ) 8759 break 8760 if clevel > 3: 8761 logger_mg.info(' current estimated error: %s go to %s-body decay:' %\ 8762 (part.get('apx_decaywidth_err'), clevel)) 8763 part.find_channels_nextlevel(model, min_br) 8764 #part.group_channels_2_amplitudes(clevel, model, min_br) 8765 amp = part.get_amplitudes(clevel) 8766 if amp: 8767 self._curr_amps.extend(amp) 8768 part.update_decay_attributes(False, True, True, model) 8769 8770 8771 # Set _generate_info 8772 if len(self._curr_amps) > 0: 8773 process = self._curr_amps[0]['process'].nice_string() 8774 #print process 8775 self._generate_info = process[9:] 8776 #print self._generate_info 8777 else: 8778 logger.info("No decay is found")
8779
8780 -class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd):
8781 """Temporary parser"""
8782 8783 #=============================================================================== 8784 # Command Parser 8785 #=============================================================================== 8786 # DRAW 8787 _draw_usage = "draw FILEPATH [options]\n" + \ 8788 "-- draw the diagrams in eps format\n" + \ 8789 " Files will be FILEPATH/diagrams_\"process_string\".eps \n" + \ 8790 " Example: draw plot_dir . \n" 8791 _draw_parser = misc.OptionParser(usage=_draw_usage) 8792 _draw_parser.add_option("", "--horizontal", default=False, 8793 action='store_true', help="force S-channel to be horizontal") 8794 _draw_parser.add_option("", "--external", default=0, type='float', 8795 help="authorizes external particles to end at top or " + \ 8796 "bottom of diagram. If bigger than zero this tune the " + \ 8797 "length of those line.") 8798 _draw_parser.add_option("", "--max_size", default=1.5, type='float', 8799 help="this forbids external line bigger than max_size") 8800 _draw_parser.add_option("", "--non_propagating", default=True, \ 8801 dest="contract_non_propagating", action='store_false', 8802 help="avoid contractions of non propagating lines") 8803 _draw_parser.add_option("", "--add_gap", default=0, type='float', \ 8804 help="set the x-distance between external particles") 8805 8806 # LAUNCH PROGRAM 8807 _launch_usage = "launch [DIRPATH] [options]\n" + \ 8808 "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \ 8809 " By default DIRPATH is the latest created directory \n" + \ 8810 " (for pythia8, it should be the Pythia 8 main directory) \n" + \ 8811 " Example: launch PROC_sm_1 --name=run2 \n" + \ 8812 " Example: launch ../pythia8 \n" 8813 _launch_parser = misc.OptionParser(usage=_launch_usage) 8814 _launch_parser.add_option("-f", "--force", default=False, action='store_true', 8815 help="Use the card present in the directory in order to launch the different program") 8816 _launch_parser.add_option("-n", "--name", default='', type='str', 8817 help="Provide a name to the run (for madevent run)") 8818 _launch_parser.add_option("-c", "--cluster", default=False, action='store_true', 8819 help="submit the job on the cluster") 8820 _launch_parser.add_option("-m", "--multicore", default=False, action='store_true', 8821 help="submit the job on multicore core") 8822 8823 _launch_parser.add_option("-i", "--interactive", default=False, action='store_true', 8824 help="Use Interactive Console [if available]") 8825 _launch_parser.add_option("-s", "--laststep", default='', 8826 help="last program run in MadEvent run. [auto|parton|pythia|pgs|delphes]") 8827 _launch_parser.add_option("-R", "--reweight", default=False, action='store_true', 8828 help="Run the reweight module (reweighting by different model parameter") 8829 _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', 8830 help="Run the madspin package")
8831 8832 #=============================================================================== 8833 # Interface for customize question. 8834 #=============================================================================== 8835 -class AskforCustomize(cmd.SmartQuestion):
8836 """A class for asking a question where in addition you can have the 8837 set command define and modifying the param_card/run_card correctly""" 8838
8839 - def __init__(self, question, allow_arg=[], default=None, 8840 mother_interface=None, *arg, **opt):
8841 8842 model_path = mother_interface._curr_model.get('modelpath') 8843 #2) Import the option available in the model 8844 ufo_model = ufomodels.load_model(model_path) 8845 self.all_categories = ufo_model.build_restrict.all_categories 8846 8847 question = self.get_question() 8848 # determine the possible value and how they are linked to the restriction 8849 #options. 8850 allow_arg = ['0'] 8851 self.name2options = {} 8852 for category in self.all_categories: 8853 for options in category: 8854 if not options.first: 8855 continue 8856 self.name2options[str(len(allow_arg))] = options 8857 self.name2options[options.name.replace(' ','')] = options 8858 allow_arg.append(len(allow_arg)) 8859 allow_arg.append('done') 8860 8861 cmd.SmartQuestion.__init__(self, question, allow_arg, default, mother_interface)
8862 8863 8864
8865 - def default(self, line):
8866 """Default action if line is not recognized""" 8867 8868 line = line.strip() 8869 args = line.split() 8870 if line == '' and self.default_value is not None: 8871 self.value = self.default_value 8872 # check if input is a file 8873 elif hasattr(self, 'do_%s' % args[0]): 8874 self.do_set(' '.join(args[1:])) 8875 elif line.strip() != '0' and line.strip() != 'done' and \ 8876 str(line) != 'EOF' and line.strip() in self.allow_arg: 8877 option = self.name2options[line.strip()] 8878 option.status = not option.status 8879 self.value = 'repeat' 8880 else: 8881 self.value = line 8882 8883 return self.all_categories
8884
8885 - def reask(self, reprint_opt=True):
8886 """ """ 8887 reprint_opt = True 8888 self.question = self.get_question() 8889 cmd.SmartQuestion.reask(self, reprint_opt)
8890
8891 - def do_set(self, line):
8892 """ """ 8893 self.value = 'repeat' 8894 8895 args = line.split() 8896 if args[0] not in self.name2options: 8897 logger.warning('Invalid set command. %s not recognize options. Valid options are: \n %s' % 8898 (args[0], ', '.join(list(self.name2options.keys())) )) 8899 return 8900 elif len(args) != 2: 8901 logger.warning('Invalid set command. Not correct number of argument') 8902 return 8903 8904 8905 if args[1] in ['True','1','.true.','T',1,True,'true','TRUE']: 8906 self.name2options[args[0]].status = True 8907 elif args[1] in ['False','0','.false.','F',0,False,'false','FALSE']: 8908 self.name2options[args[0]].status = False 8909 else: 8910 logger.warning('%s is not True/False. Didn\'t do anything.' % args[1])
8911 8912 8913
8914 - def get_question(self):
8915 """define the current question.""" 8916 question = '' 8917 i=0 8918 for category in self.all_categories: 8919 question += category.name + ':\n' 8920 for options in category: 8921 if not options.first: 8922 continue 8923 i+=1 8924 question += ' %s: %s [%s]\n' % (i, options.name, 8925 options.display(options.status)) 8926 question += 'Enter a number to change it\'s status or press enter to validate.\n' 8927 question += 'For scripting this function, please type: \'help\'' 8928 return question
8929 8930
8931 - def complete_set(self, text, line, begidx, endidx):
8932 """ Complete the set command""" 8933 signal.alarm(0) # avoid timer if any 8934 args = self.split_arg(line[0:begidx]) 8935 8936 if len(args) == 1: 8937 possibilities = [x for x in self.name2options if not x.isdigit()] 8938 return self.list_completion(text, possibilities, line) 8939 else: 8940 return self.list_completion(text,['True', 'False'], line)
8941 8942
8943 - def do_help(self, line):
8944 '''help message''' 8945 8946 print('This allows you to optimize your model to your needs.') 8947 print('Enter the number associate to the possible restriction/add-on') 8948 print(' to change the status of this restriction/add-on.') 8949 print('') 8950 print('In order to allow scripting of this function you can use the ') 8951 print('function \'set\'. This function takes two argument:') 8952 print('set NAME VALUE') 8953 print(' NAME is the description of the option where you remove all spaces') 8954 print(' VALUE is either True or False') 8955 print(' Example: For the question') 8956 print(''' sm customization: 8957 1: diagonal ckm [True] 8958 2: c mass = 0 [True] 8959 3: b mass = 0 [False] 8960 4: tau mass = 0 [False] 8961 5: muon mass = 0 [True] 8962 6: electron mass = 0 [True] 8963 Enter a number to change it's status or press enter to validate.''') 8964 print(''' you can answer by''') 8965 print(' set diagonalckm False') 8966 print(' set taumass=0 True')
8967
8968 - def cmdloop(self, intro=None):
8969 cmd.SmartQuestion.cmdloop(self, intro) 8970 return self.all_categories
8971 8972 8973 8974 #=============================================================================== 8975 # __main__ 8976 #=============================================================================== 8977 8978 if __name__ == '__main__': 8979 8980 run_option = sys.argv 8981 if len(run_option) > 1: 8982 # The first argument of sys.argv is the name of the program 8983 input_file = open(run_option[1], 'rU') 8984 cmd_line = MadGraphCmd(stdin=input_file) 8985 cmd_line.use_rawinput = False #put it in non interactive mode 8986 cmd_line.cmdloop() 8987 else: 8988 # Interactive mode 8989 MadGraphCmd().cmdloop() 8990