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