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

Source Code for Module madgraph.interface.madevent_interface

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2011 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. 
  16     Uses the cmd package for command interpretation and tab completion. 
  17  """ 
  18  from __future__ import division 
  19   
  20  import atexit 
  21  import collections 
  22  import cmath 
  23  import glob 
  24  import logging 
  25  import math 
  26  import optparse 
  27  import os 
  28  import pydoc 
  29  import random 
  30  import re 
  31  import signal 
  32  import shutil 
  33  import stat 
  34  import subprocess 
  35  import sys 
  36  import traceback 
  37  import time 
  38  import tarfile 
  39  import StringIO 
  40  import shutil 
  41  import copy 
  42  import xml.dom.minidom as minidom 
  43   
  44  try: 
  45      import readline 
  46      GNU_SPLITTING = ('GNU' in readline.__doc__) 
  47  except: 
  48      GNU_SPLITTING = True 
  49   
  50  root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 
  51  root_path = os.path.split(root_path)[0] 
  52  sys.path.insert(0, os.path.join(root_path,'bin')) 
  53   
  54  # usefull shortcut 
  55  pjoin = os.path.join 
  56  # Special logger for the Cmd Interface 
  57  logger = logging.getLogger('madevent.stdout') # -> stdout 
  58  logger_stderr = logging.getLogger('madevent.stderr') # ->stderr 
  59    
  60  try: 
  61      import madgraph 
  62   
  63       
  64  except ImportError:  
  65      # import from madevent directory 
  66      MADEVENT = True 
  67      import internal.extended_cmd as cmd 
  68      import internal.common_run_interface as common_run 
  69      import internal.banner as banner_mod 
  70      import internal.misc as misc 
  71      from internal import InvalidCmd, MadGraph5Error, ReadWrite 
  72      import internal.files as files 
  73      import internal.gen_crossxhtml as gen_crossxhtml 
  74      import internal.gen_ximprove as gen_ximprove 
  75      import internal.save_load_object as save_load_object 
  76      import internal.cluster as cluster 
  77      import internal.check_param_card as check_param_card 
  78      import internal.sum_html as sum_html 
  79      import internal.combine_runs as combine_runs 
  80      import internal.lhe_parser as lhe_parser 
  81      import internal.histograms as histograms 
  82      from internal.files import ln 
  83  else: 
  84      # import from madgraph directory 
  85      MADEVENT = False 
  86      import madgraph.interface.extended_cmd as cmd 
  87      import madgraph.interface.common_run_interface as common_run 
  88      import madgraph.iolibs.files as files 
  89      import madgraph.iolibs.save_load_object as save_load_object 
  90      import madgraph.madevent.gen_crossxhtml as gen_crossxhtml 
  91      import madgraph.madevent.gen_ximprove as gen_ximprove 
  92      import madgraph.madevent.sum_html as sum_html 
  93      import madgraph.various.banner as banner_mod 
  94      import madgraph.various.cluster as cluster 
  95      import madgraph.various.misc as misc 
  96      import madgraph.madevent.combine_runs as combine_runs 
  97      import madgraph.various.lhe_parser as lhe_parser 
  98      import madgraph.various.histograms as histograms 
  99   
 100      import models.check_param_card as check_param_card 
 101      from madgraph.iolibs.files import ln     
 102      from madgraph import InvalidCmd, MadGraph5Error, MG5DIR, ReadWrite 
103 104 105 106 107 -class MadEventError(Exception):
108 pass
109
110 -class ZeroResult(MadEventError):
111 pass
112
113 -class SysCalcError(InvalidCmd): pass
114 115 MadEventAlreadyRunning = common_run.MadEventAlreadyRunning
116 117 #=============================================================================== 118 # CmdExtended 119 #=============================================================================== 120 -class CmdExtended(common_run.CommonRunCmd):
121 """Particularisation of the cmd command for MadEvent""" 122 123 #suggested list of command 124 next_possibility = { 125 'start': [], 126 } 127 128 debug_output = 'ME5_debug' 129 error_debug = 'Please report this bug on https://bugs.launchpad.net/mg5amcnlo\n' 130 error_debug += 'More information is found in \'%(debug)s\'.\n' 131 error_debug += 'Please attach this file to your report.' 132 133 config_debug = 'If you need help with this issue please contact us on https://answers.launchpad.net/mg5amcnlo\n' 134 135 136 keyboard_stop_msg = """stopping all operation 137 in order to quit MadGraph5_aMC@NLO please enter exit""" 138 139 # Define the Error 140 InvalidCmd = InvalidCmd 141 ConfigurationError = MadGraph5Error 142
143 - def __init__(self, me_dir, options, *arg, **opt):
144 """Init history and line continuation""" 145 146 # Tag allowing/forbiding question 147 self.force = False 148 149 # If possible, build an info line with current version number 150 # and date, from the VERSION text file 151 info = misc.get_pkg_info() 152 info_line = "" 153 if info and info.has_key('version') and info.has_key('date'): 154 len_version = len(info['version']) 155 len_date = len(info['date']) 156 if len_version + len_date < 30: 157 info_line = "#* VERSION %s %s %s *\n" % \ 158 (info['version'], 159 (30 - len_version - len_date) * ' ', 160 info['date']) 161 else: 162 version = open(pjoin(root_path,'MGMEVersion.txt')).readline().strip() 163 info_line = "#* VERSION %s %s *\n" % \ 164 (version, (24 - len(version)) * ' ') 165 166 # Create a header for the history file. 167 # Remember to fill in time at writeout time! 168 self.history_header = \ 169 '#************************************************************\n' + \ 170 '#* MadGraph5_aMC@NLO/MadEvent *\n' + \ 171 '#* *\n' + \ 172 "#* * * *\n" + \ 173 "#* * * * * *\n" + \ 174 "#* * * * * 5 * * * * *\n" + \ 175 "#* * * * * *\n" + \ 176 "#* * * *\n" + \ 177 "#* *\n" + \ 178 "#* *\n" + \ 179 info_line + \ 180 "#* *\n" + \ 181 "#* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \ 182 "#* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \ 183 '#* *\n' + \ 184 '#************************************************************\n' + \ 185 '#* *\n' + \ 186 '#* Command File for MadEvent *\n' + \ 187 '#* *\n' + \ 188 '#* run as ./bin/madevent.py filename *\n' + \ 189 '#* *\n' + \ 190 '#************************************************************\n' 191 192 if info_line: 193 info_line = info_line[1:] 194 195 logger.info(\ 196 "************************************************************\n" + \ 197 "* *\n" + \ 198 "* W E L C O M E to *\n" + \ 199 "* M A D G R A P H 5 _ a M C @ N L O *\n" + \ 200 "* M A D E V E N T *\n" + \ 201 "* *\n" + \ 202 "* * * *\n" + \ 203 "* * * * * *\n" + \ 204 "* * * * * 5 * * * * *\n" + \ 205 "* * * * * *\n" + \ 206 "* * * *\n" + \ 207 "* *\n" + \ 208 info_line + \ 209 "* *\n" + \ 210 "* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \ 211 "* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \ 212 "* *\n" + \ 213 "* Type 'help' for in-line help. *\n" + \ 214 "* *\n" + \ 215 "************************************************************") 216 super(CmdExtended, self).__init__(me_dir, options, *arg, **opt)
217
218 - def get_history_header(self):
219 """return the history header""" 220 return self.history_header % misc.get_time_info()
221
222 - def stop_on_keyboard_stop(self):
223 """action to perform to close nicely on a keyboard interupt""" 224 try: 225 if hasattr(self, 'cluster'): 226 logger.info('rm jobs on queue') 227 self.cluster.remove() 228 if hasattr(self, 'results'): 229 self.update_status('Stop by the user', level=None, makehtml=False, error=True) 230 self.add_error_log_in_html(KeyboardInterrupt) 231 except: 232 pass
233
234 - def postcmd(self, stop, line):
235 """ Update the status of the run for finishing interactive command """ 236 237 stop = super(CmdExtended, self).postcmd(stop, line) 238 # relaxing the tag forbidding question 239 self.force = False 240 241 if not self.use_rawinput: 242 return stop 243 244 if self.results and not self.results.current: 245 return stop 246 247 arg = line.split() 248 if len(arg) == 0: 249 return stop 250 if isinstance(self.results.status, str) and self.results.status.startswith('Error'): 251 return stop 252 if isinstance(self.results.status, str) and self.results.status == 'Stop by the user': 253 self.update_status('%s Stop by the user' % arg[0], level=None, error=True) 254 return stop 255 elif not self.results.status: 256 return stop 257 elif str(arg[0]) in ['exit','quit','EOF']: 258 return stop 259 260 try: 261 self.update_status('Command \'%s\' done.<br> Waiting for instruction.' % arg[0], 262 level=None, error=True) 263 except Exception: 264 misc.sprint('update_status fails') 265 pass
266 267
268 - def nice_user_error(self, error, line):
269 """If a ME run is currently running add a link in the html output""" 270 271 self.add_error_log_in_html() 272 cmd.Cmd.nice_user_error(self, error, line)
273
274 - def nice_config_error(self, error, line):
275 """If a ME run is currently running add a link in the html output""" 276 277 self.add_error_log_in_html() 278 cmd.Cmd.nice_config_error(self, error, line) 279 280 281 try: 282 debug_file = open(self.debug_output, 'a') 283 debug_file.write(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat'))) 284 debug_file.close() 285 except: 286 pass
287 288
289 - def nice_error_handling(self, error, line):
290 """If a ME run is currently running add a link in the html output""" 291 292 if isinstance(error, ZeroResult): 293 self.add_error_log_in_html(error) 294 logger.warning('Zero result detected: %s' % error) 295 # create a banner if needed 296 try: 297 if not self.banner: 298 self.banner = banner_mod.Banner() 299 if 'slha' not in self.banner: 300 self.banner.add(pjoin(self.me_dir,'Cards','param_card.dat')) 301 if 'mgruncard' not in self.banner: 302 self.banner.add(pjoin(self.me_dir,'Cards','run_card.dat')) 303 if 'mg5proccard' not in self.banner: 304 proc_card = pjoin(self.me_dir,'Cards','proc_card_mg5.dat') 305 if os.path.exists(proc_card): 306 self.banner.add(proc_card) 307 308 out_dir = pjoin(self.me_dir, 'Events', self.run_name) 309 if not os.path.isdir(out_dir): 310 os.mkdir(out_dir) 311 output_path = pjoin(out_dir, '%s_%s_banner.txt' % \ 312 (self.run_name, self.run_tag)) 313 self.banner.write(output_path) 314 except Exception: 315 if __debug__: 316 raise 317 else: 318 pass 319 else: 320 self.add_error_log_in_html() 321 cmd.Cmd.nice_error_handling(self, error, line) 322 try: 323 debug_file = open(self.debug_output, 'a') 324 debug_file.write(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat'))) 325 debug_file.close() 326 except: 327 pass
328
329 330 #=============================================================================== 331 # HelpToCmd 332 #=============================================================================== 333 -class HelpToCmd(object):
334 """ The Series of help routine for the MadEventCmd""" 335
336 - def help_pythia(self):
337 logger.info("syntax: pythia [RUN] [--run_options]") 338 logger.info("-- run pythia on RUN (current one by default)") 339 self.run_options_help([('-f','answer all question by default'), 340 ('--tag=', 'define the tag for the pythia run'), 341 ('--no_default', 'not run if pythia_card not present')])
342
343 - def help_pythia8(self):
344 logger.info("syntax: pythia8 [RUN] [--run_options]") 345 logger.info("-- run pythia8 on RUN (current one by default)") 346 self.run_options_help([('-f','answer all question by default'), 347 ('--tag=', 'define the tag for the pythia8 run'), 348 ('--no_default', 'not run if pythia8_card not present')])
349
350 - def help_banner_run(self):
351 logger.info("syntax: banner_run Path|RUN [--run_options]") 352 logger.info("-- Reproduce a run following a given banner") 353 logger.info(" One of the following argument is require:") 354 logger.info(" Path should be the path of a valid banner.") 355 logger.info(" RUN should be the name of a run of the current directory") 356 self.run_options_help([('-f','answer all question by default'), 357 ('--name=X', 'Define the name associated with the new run')])
358
359 - def help_open(self):
360 logger.info("syntax: open FILE ") 361 logger.info("-- open a file with the appropriate editor.") 362 logger.info(' If FILE belongs to index.html, param_card.dat, run_card.dat') 363 logger.info(' the path to the last created/used directory is used') 364 logger.info(' The program used to open those files can be chosen in the') 365 logger.info(' configuration file ./input/mg5_configuration.txt')
366 367
368 - def run_options_help(self, data):
369 if data: 370 logger.info('-- local options:') 371 for name, info in data: 372 logger.info(' %s : %s' % (name, info)) 373 374 logger.info("-- session options:") 375 logger.info(" Note that those options will be kept for the current session") 376 logger.info(" --cluster : Submit to the cluster. Current cluster: %s" % self.options['cluster_type']) 377 logger.info(" --multicore : Run in multi-core configuration") 378 logger.info(" --nb_core=X : limit the number of core to use to X.")
379 380
381 - def help_generate_events(self):
382 logger.info("syntax: generate_events [run_name] [options]",) 383 logger.info("-- Launch the full chain of script for the generation of events") 384 logger.info(" Including possible plotting, shower and detector resolution.") 385 logger.info(" Those steps are performed if the related program are installed") 386 logger.info(" and if the related card are present in the Cards directory.") 387 self.run_options_help([('-f', 'Use default for all questions.'), 388 ('--laststep=', 'argument might be parton/pythia/pgs/delphes and indicate the last level to be run.'), 389 ('-M', 'in order to add MadSpin'), 390 ('-R', 'in order to add the reweighting module')])
391
392 - def help_initMadLoop(self):
393 logger.info("syntax: initMadLoop [options]",'$MG:color:GREEN') 394 logger.info( 395 """-- Command only useful when MadEvent simulates loop-induced processes. This command compiles and run 396 the MadLoop output for the matrix element computation so as to initialize the filter for analytically 397 zero helicity configurations and loop topologies. If you suspect that a change you made in the model 398 parameters can have affected these filters, this command allows you to automatically refresh them. """) 399 logger.info(" The available options are:",'$MG:color:BLUE') 400 logger.info(" -f : Bypass the edition of MadLoopParams.dat.",'$MG:color:BLUE') 401 logger.info(" -r : Refresh of the existing filters (erasing them if already present).",'$MG:color:BLUE') 402 logger.info(" --nPS=<int> : Specify how many phase-space points should be tried to set up the filters.",'$MG:color:BLUE')
403
404 - def help_add_time_of_flight(self):
405 logger.info("syntax: add_time_of_flight [run_name|path_to_file] [--threshold=]") 406 logger.info('-- Add in the lhe files the information') 407 logger.info(' of how long it takes to a particle to decay.') 408 logger.info(' threshold option allows to change the minimal value required to') 409 logger.info(' a non zero value for the particle (default:1e-12s)')
410
412 413 if self.ninitial != 1: 414 logger.warning("This command is only valid for processes of type A > B C.") 415 logger.warning("This command can not be run in current context.") 416 logger.warning("") 417 418 logger.info("syntax: calculate_decay_widths [run_name] [options])") 419 logger.info("-- Calculate decay widths and enter widths and BRs in param_card") 420 logger.info(" for a series of processes of type A > B C ...") 421 self.run_options_help([('-f', 'Use default for all questions.'), 422 ('--accuracy=', 'accuracy (for each partial decay width).'\ 423 + ' Default is 0.01.')])
424
425 - def help_multi_run(self):
426 logger.info("syntax: multi_run NB_RUN [run_name] [--run_options])") 427 logger.info("-- Launch the full chain of script for the generation of events") 428 logger.info(" NB_RUN times. This chains includes possible plotting, shower") 429 logger.info(" and detector resolution.") 430 self.run_options_help([('-f', 'Use default for all questions.'), 431 ('--laststep=', 'argument might be parton/pythia/pgs/delphes and indicate the last level to be run.')])
432
433 - def help_survey(self):
434 logger.info("syntax: survey [run_name] [--run_options])") 435 logger.info("-- evaluate the different channel associate to the process") 436 self.run_options_help([("--" + key,value[-1]) for (key,value) in \ 437 self._survey_options.items()])
438
439 - def help_launch(self):
440 """exec generate_events for 2>N and calculate_width for 1>N""" 441 logger.info("syntax: launch [run_name] [options])") 442 logger.info(" --alias for either generate_events/calculate_decay_widths") 443 logger.info(" depending of the number of particles in the initial state.") 444 445 if self.ninitial == 1: 446 logger.info("For this directory this is equivalent to calculate_decay_widths") 447 self.help_calculate_decay_widths() 448 else: 449 logger.info("For this directory this is equivalent to $generate_events") 450 self.help_generate_events()
451
452 - def help_refine(self):
453 logger.info("syntax: refine require_precision [max_channel] [--run_options]") 454 logger.info("-- refine the LAST run to achieve a given precision.") 455 logger.info(" require_precision: can be either the targeted number of events") 456 logger.info(' or the required relative error') 457 logger.info(' max_channel:[5] maximal number of channel per job') 458 self.run_options_help([])
459
460 - def help_combine_events(self):
461 """ """ 462 logger.info("syntax: combine_events [run_name] [--tag=tag_name] [--run_options]") 463 logger.info("-- Combine the last run in order to write the number of events") 464 logger.info(" asked in the run_card.") 465 self.run_options_help([])
466
467 - def help_store_events(self):
468 """ """ 469 logger.info("syntax: store_events [--run_options]") 470 logger.info("-- Write physically the events in the files.") 471 logger.info(" should be launch after \'combine_events\'") 472 self.run_options_help([])
473
474 - def help_create_gridpack(self):
475 """ """ 476 logger.info("syntax: create_gridpack [--run_options]") 477 logger.info("-- create the gridpack. ") 478 logger.info(" should be launch after \'store_events\'") 479 self.run_options_help([])
480
481 - def help_import(self):
482 """ """ 483 logger.info("syntax: import command PATH") 484 logger.info("-- Execute the command present in the file") 485 self.run_options_help([])
486
487 - def help_syscalc(self):
488 logger.info("syntax: syscalc [RUN] [%s] [-f | --tag=]" % '|'.join(self._plot_mode)) 489 logger.info("-- calculate systematics information for the RUN (current run by default)") 490 logger.info(" at different stages of the event generation for scale/pdf/...")
491
492 - def help_remove(self):
493 logger.info("syntax: remove RUN [all|parton|pythia|pgs|delphes|banner] [-f] [--tag=]") 494 logger.info("-- Remove all the files linked to previous run RUN") 495 logger.info(" if RUN is 'all', then all run will be cleaned.") 496 logger.info(" The optional argument precise which part should be cleaned.") 497 logger.info(" By default we clean all the related files but the banners.") 498 logger.info(" the optional '-f' allows to by-pass all security question") 499 logger.info(" The banner can be remove only if all files are removed first.")
500
501 502 503 #=============================================================================== 504 # CheckValidForCmd 505 #=============================================================================== 506 -class CheckValidForCmd(object):
507 """ The Series of check routine for the MadEventCmd""" 508
509 - def check_banner_run(self, args):
510 """check the validity of line""" 511 512 if len(args) == 0: 513 self.help_banner_run() 514 raise self.InvalidCmd('banner_run requires at least one argument.') 515 516 tag = [a[6:] for a in args if a.startswith('--tag=')] 517 518 519 if os.path.exists(args[0]): 520 type ='banner' 521 format = self.detect_card_type(args[0]) 522 if format != 'banner': 523 raise self.InvalidCmd('The file is not a valid banner.') 524 elif tag: 525 args[0] = pjoin(self.me_dir,'Events', args[0], '%s_%s_banner.txt' % \ 526 (args[0], tag)) 527 if not os.path.exists(args[0]): 528 raise self.InvalidCmd('No banner associates to this name and tag.') 529 else: 530 name = args[0] 531 type = 'run' 532 banners = misc.glob('*_banner.txt', pjoin(self.me_dir,'Events', args[0])) 533 if not banners: 534 raise self.InvalidCmd('No banner associates to this name.') 535 elif len(banners) == 1: 536 args[0] = banners[0] 537 else: 538 #list the tag and propose those to the user 539 tags = [os.path.basename(p)[len(args[0])+1:-11] for p in banners] 540 tag = self.ask('which tag do you want to use?', tags[0], tags) 541 args[0] = pjoin(self.me_dir,'Events', args[0], '%s_%s_banner.txt' % \ 542 (args[0], tag)) 543 544 run_name = [arg[7:] for arg in args if arg.startswith('--name=')] 545 if run_name: 546 try: 547 self.exec_cmd('remove %s all banner -f' % run_name) 548 except Exception: 549 pass 550 self.set_run_name(args[0], tag=None, level='parton', reload_card=True) 551 elif type == 'banner': 552 self.set_run_name(self.find_available_run_name(self.me_dir)) 553 elif type == 'run': 554 if not self.results[name].is_empty(): 555 run_name = self.find_available_run_name(self.me_dir) 556 logger.info('Run %s is not empty so will use run_name: %s' % \ 557 (name, run_name)) 558 self.set_run_name(run_name) 559 else: 560 try: 561 self.exec_cmd('remove %s all banner -f' % run_name) 562 except Exception: 563 pass 564 self.set_run_name(name)
565
566 - def check_history(self, args):
567 """check the validity of line""" 568 569 if len(args) > 1: 570 self.help_history() 571 raise self.InvalidCmd('\"history\" command takes at most one argument') 572 573 if not len(args): 574 return 575 elif args[0] != 'clean': 576 dirpath = os.path.dirname(args[0]) 577 if dirpath and not os.path.exists(dirpath) or \ 578 os.path.isdir(args[0]): 579 raise self.InvalidCmd("invalid path %s " % dirpath)
580
581 - def check_save(self, args):
582 """ check the validity of the line""" 583 584 if len(args) == 0: 585 args.append('options') 586 587 if args[0] not in self._save_opts: 588 raise self.InvalidCmd('wrong \"save\" format') 589 590 if args[0] != 'options' and len(args) != 2: 591 self.help_save() 592 raise self.InvalidCmd('wrong \"save\" format') 593 elif args[0] != 'options' and len(args) == 2: 594 basename = os.path.dirname(args[1]) 595 if not os.path.exists(basename): 596 raise self.InvalidCmd('%s is not a valid path, please retry' % \ 597 args[1]) 598 599 if args[0] == 'options': 600 has_path = None 601 for arg in args[1:]: 602 if arg in ['--auto', '--all']: 603 continue 604 elif arg.startswith('--'): 605 raise self.InvalidCmd('unknow command for \'save options\'') 606 else: 607 basename = os.path.dirname(arg) 608 if not os.path.exists(basename): 609 raise self.InvalidCmd('%s is not a valid path, please retry' % \ 610 arg) 611 elif has_path: 612 raise self.InvalidCmd('only one path is allowed') 613 else: 614 args.remove(arg) 615 args.insert(1, arg) 616 has_path = True 617 if not has_path: 618 if '--auto' in arg and self.options['mg5_path']: 619 args.insert(1, pjoin(self.options['mg5_path'],'input','mg5_configuration.txt')) 620 else: 621 args.insert(1, pjoin(self.me_dir,'Cards','me5_configuration.txt'))
622
623 - def check_set(self, args):
624 """ check the validity of the line""" 625 626 if len(args) < 2: 627 self.help_set() 628 raise self.InvalidCmd('set needs an option and an argument') 629 630 if args[0] not in self._set_options + self.options.keys(): 631 self.help_set() 632 raise self.InvalidCmd('Possible options for set are %s' % \ 633 self._set_options) 634 635 if args[0] in ['stdout_level']: 636 if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] \ 637 and not args[1].isdigit(): 638 raise self.InvalidCmd('output_level needs ' + \ 639 'a valid level') 640 641 if args[0] in ['timeout']: 642 if not args[1].isdigit(): 643 raise self.InvalidCmd('timeout values should be a integer')
644
645 - def check_open(self, args):
646 """ check the validity of the line """ 647 648 if len(args) != 1: 649 self.help_open() 650 raise self.InvalidCmd('OPEN command requires exactly one argument') 651 652 if args[0].startswith('./'): 653 if not os.path.isfile(args[0]): 654 raise self.InvalidCmd('%s: not such file' % args[0]) 655 return True 656 657 # if special : create the path. 658 if not self.me_dir: 659 if not os.path.isfile(args[0]): 660 self.help_open() 661 raise self.InvalidCmd('No MadEvent path defined. Unable to associate this name to a file') 662 else: 663 return True 664 665 path = self.me_dir 666 if os.path.isfile(os.path.join(path,args[0])): 667 args[0] = os.path.join(path,args[0]) 668 elif os.path.isfile(os.path.join(path,'Cards',args[0])): 669 args[0] = os.path.join(path,'Cards',args[0]) 670 elif os.path.isfile(os.path.join(path,'HTML',args[0])): 671 args[0] = os.path.join(path,'HTML',args[0]) 672 # special for card with _default define: copy the default and open it 673 elif '_card.dat' in args[0]: 674 name = args[0].replace('_card.dat','_card_default.dat') 675 if os.path.isfile(os.path.join(path,'Cards', name)): 676 files.cp(os.path.join(path,'Cards', name), os.path.join(path,'Cards', args[0])) 677 args[0] = os.path.join(path,'Cards', args[0]) 678 else: 679 raise self.InvalidCmd('No default path for this file') 680 elif not os.path.isfile(args[0]): 681 raise self.InvalidCmd('No default path for this file')
682
683 - def check_initMadLoop(self, args):
684 """ check initMadLoop command arguments are valid.""" 685 686 opt = {'refresh': False, 'nPS': None, 'force': False} 687 688 for arg in args: 689 if arg in ['-r','--refresh']: 690 opt['refresh'] = True 691 if arg in ['-f','--force']: 692 opt['force'] = True 693 elif arg.startswith('--nPS='): 694 n_attempts = arg.split('=')[1] 695 try: 696 opt['nPS'] = int(n_attempts) 697 except ValueError: 698 raise InvalidCmd("The number of attempts specified "+ 699 "'%s' is not a valid integer."%n_attempts) 700 701 return opt
702
703 - def check_treatcards(self, args):
704 """check that treatcards arguments are valid 705 [param|run|all] [--output_dir=] [--param_card=] [--run_card=] 706 """ 707 708 opt = {'output_dir':pjoin(self.me_dir,'Source'), 709 'param_card':pjoin(self.me_dir,'Cards','param_card.dat'), 710 'run_card':pjoin(self.me_dir,'Cards','run_card.dat'), 711 'forbid_MadLoopInit': False} 712 mode = 'all' 713 for arg in args: 714 if arg.startswith('--') and '=' in arg: 715 key,value =arg[2:].split('=',1) 716 if not key in opt: 717 self.help_treatcards() 718 raise self.InvalidCmd('Invalid option for treatcards command:%s ' \ 719 % key) 720 if key in ['param_card', 'run_card']: 721 if os.path.isfile(value): 722 card_name = self.detect_card_type(value) 723 if card_name != key: 724 raise self.InvalidCmd('Format for input file detected as %s while expecting %s' 725 % (card_name, key)) 726 opt[key] = value 727 elif os.path.isfile(pjoin(self.me_dir,value)): 728 card_name = self.detect_card_type(pjoin(self.me_dir,value)) 729 if card_name != key: 730 raise self.InvalidCmd('Format for input file detected as %s while expecting %s' 731 % (card_name, key)) 732 opt[key] = value 733 else: 734 raise self.InvalidCmd('No such file: %s ' % value) 735 elif key in ['output_dir']: 736 if os.path.isdir(value): 737 opt[key] = value 738 elif os.path.isdir(pjoin(self.me_dir,value)): 739 opt[key] = pjoin(self.me_dir, value) 740 else: 741 raise self.InvalidCmd('No such directory: %s' % value) 742 elif arg in ['loop','param','run','all']: 743 mode = arg 744 elif arg == '--no_MadLoopInit': 745 opt['forbid_MadLoopInit'] = True 746 else: 747 self.help_treatcards() 748 raise self.InvalidCmd('Unvalid argument %s' % arg) 749 750 return mode, opt
751 752
753 - def check_survey(self, args, cmd='survey'):
754 """check that the argument for survey are valid""" 755 756 757 self.opts = dict([(key,value[1]) for (key,value) in \ 758 self._survey_options.items()]) 759 760 # Treat any arguments starting with '--' 761 while args and args[-1].startswith('--'): 762 arg = args.pop(-1) 763 try: 764 for opt,value in self._survey_options.items(): 765 if arg.startswith('--%s=' % opt): 766 exec('self.opts[\'%s\'] = %s(arg.split(\'=\')[-1])' % \ 767 (opt, value[0])) 768 arg = "" 769 if arg != "": raise Exception 770 except Exception: 771 self.help_survey() 772 raise self.InvalidCmd('invalid %s argument'% arg) 773 774 if len(args) > 1: 775 self.help_survey() 776 raise self.InvalidCmd('Too many argument for %s command' % cmd) 777 elif not args: 778 # No run name assigned -> assigned one automaticaly 779 self.set_run_name(self.find_available_run_name(self.me_dir)) 780 else: 781 self.set_run_name(args[0], None,'parton', True) 782 args.pop(0) 783 784 return True
785
786 - def check_generate_events(self, args):
787 """check that the argument for generate_events are valid""" 788 789 run = None 790 if args and args[-1].startswith('--laststep='): 791 run = args[-1].split('=')[-1] 792 if run not in ['auto','parton', 'pythia', 'pgs', 'delphes']: 793 self.help_generate_events() 794 raise self.InvalidCmd('invalid %s argument'% args[-1]) 795 if run != 'parton' and not self.options['pythia-pgs_path']: 796 raise self.InvalidCmd('''pythia-pgs not install. Please install this package first. 797 To do so type: \'install pythia-pgs\' in the mg5 interface''') 798 if run == 'delphes' and not self.options['delphes_path']: 799 raise self.InvalidCmd('''delphes not install. Please install this package first. 800 To do so type: \'install Delphes\' in the mg5 interface''') 801 del args[-1] 802 803 804 #if len(args) > 1: 805 # self.help_generate_events() 806 # raise self.InvalidCmd('Too many argument for generate_events command: %s' % cmd) 807 808 return run
809
810 - def check_add_time_of_flight(self, args):
811 """check that the argument are correct""" 812 813 814 if len(args) >2: 815 self.help_time_of_flight() 816 raise self.InvalidCmd('Too many arguments') 817 818 # check if the threshold is define. and keep it's value 819 if args and args[-1].startswith('--threshold='): 820 try: 821 threshold = float(args[-1].split('=')[1]) 822 except ValueError: 823 raise self.InvalidCmd('threshold options require a number.') 824 args.remove(args[-1]) 825 else: 826 threshold = 1e-12 827 828 if len(args) == 1 and os.path.exists(args[0]): 829 event_path = args[0] 830 else: 831 if len(args) and self.run_name != args[0]: 832 self.set_run_name(args.pop(0)) 833 elif not self.run_name: 834 self.help_add_time_of_flight() 835 raise self.InvalidCmd('Need a run_name to process') 836 event_path = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz') 837 if not os.path.exists(event_path): 838 event_path = event_path[:-3] 839 if not os.path.exists(event_path): 840 raise self.InvalidCmd('No unweighted events associate to this run.') 841 842 843 844 #reformat the data 845 args[:] = [event_path, threshold]
846
847 - def check_calculate_decay_widths(self, args):
848 """check that the argument for calculate_decay_widths are valid""" 849 850 if self.ninitial != 1: 851 raise self.InvalidCmd('Can only calculate decay widths for decay processes A > B C ...') 852 853 accuracy = 0.01 854 run = None 855 if args and args[-1].startswith('--accuracy='): 856 try: 857 accuracy = float(args[-1].split('=')[-1]) 858 except Exception: 859 raise self.InvalidCmd('Argument error in calculate_decay_widths command') 860 del args[-1] 861 if len(args) > 1: 862 self.help_calculate_decay_widths() 863 raise self.InvalidCmd('Too many argument for calculate_decay_widths command: %s' % cmd) 864 865 return accuracy
866 867 868
869 - def check_multi_run(self, args):
870 """check that the argument for survey are valid""" 871 872 run = None 873 874 if not len(args): 875 self.help_multi_run() 876 raise self.InvalidCmd("""multi_run command requires at least one argument for 877 the number of times that it call generate_events command""") 878 879 if args[-1].startswith('--laststep='): 880 run = args[-1].split('=')[-1] 881 if run not in ['parton', 'pythia', 'pgs', 'delphes']: 882 self.help_multi_run() 883 raise self.InvalidCmd('invalid %s argument'% args[-1]) 884 if run != 'parton' and not self.options['pythia-pgs_path']: 885 raise self.InvalidCmd('''pythia-pgs not install. Please install this package first. 886 To do so type: \'install pythia-pgs\' in the mg5 interface''') 887 if run == 'delphes' and not self.options['delphes_path']: 888 raise self.InvalidCmd('''delphes not install. Please install this package first. 889 To do so type: \'install Delphes\' in the mg5 interface''') 890 del args[-1] 891 892 893 elif not args[0].isdigit(): 894 self.help_multi_run() 895 raise self.InvalidCmd("The first argument of multi_run should be a integer.") 896 #pass nb run to an integer 897 nb_run = args.pop(0) 898 args.insert(0, int(nb_run)) 899 900 901 return run
902
903 - def check_refine(self, args):
904 """check that the argument for survey are valid""" 905 906 # if last argument is not a number -> it's the run_name (Not allow anymore) 907 try: 908 float(args[-1]) 909 except ValueError: 910 self.help_refine() 911 raise self.InvalidCmd('Not valid arguments') 912 except IndexError: 913 self.help_refine() 914 raise self.InvalidCmd('require_precision argument is require for refine cmd') 915 916 917 if not self.run_name: 918 if self.results.lastrun: 919 self.set_run_name(self.results.lastrun) 920 else: 921 raise self.InvalidCmd('No run_name currently define. Unable to run refine') 922 923 if len(args) > 2: 924 self.help_refine() 925 raise self.InvalidCmd('Too many argument for refine command') 926 else: 927 try: 928 [float(arg) for arg in args] 929 except ValueError: 930 self.help_refine() 931 raise self.InvalidCmd('refine arguments are suppose to be number') 932 933 return True
934
935 - def check_combine_events(self, arg):
936 """ Check the argument for the combine events command """ 937 938 tag = [a for a in arg if a.startswith('--tag=')] 939 if tag: 940 arg.remove(tag[0]) 941 tag = tag[0][6:] 942 elif not self.run_tag: 943 tag = 'tag_1' 944 else: 945 tag = self.run_tag 946 self.run_tag = tag 947 948 if len(arg) > 1: 949 self.help_combine_events() 950 raise self.InvalidCmd('Too many argument for combine_events command') 951 952 if len(arg) == 1: 953 self.set_run_name(arg[0], self.run_tag, 'parton', True) 954 955 if not self.run_name: 956 if not self.results.lastrun: 957 raise self.InvalidCmd('No run_name currently define. Unable to run combine') 958 else: 959 self.set_run_name(self.results.lastrun) 960 961 return True
962
963 - def check_pythia(self, args):
964 """Check the argument for pythia command 965 syntax: pythia [NAME] 966 Note that other option are already removed at this point 967 """ 968 969 mode = None 970 laststep = [arg for arg in args if arg.startswith('--laststep=')] 971 if laststep and len(laststep)==1: 972 mode = laststep[0].split('=')[-1] 973 if mode not in ['auto', 'pythia', 'pgs', 'delphes']: 974 self.help_pythia() 975 raise self.InvalidCmd('invalid %s argument'% args[-1]) 976 elif laststep: 977 raise self.InvalidCmd('only one laststep argument is allowed') 978 979 if not self.options['pythia-pgs_path']: 980 logger.info('Retry to read configuration file to find pythia-pgs path') 981 self.set_configuration() 982 983 if not self.options['pythia-pgs_path'] or not \ 984 os.path.exists(pjoin(self.options['pythia-pgs_path'],'src')): 985 error_msg = 'No valid pythia-pgs path set.\n' 986 error_msg += 'Please use the set command to define the path and retry.\n' 987 error_msg += 'You can also define it in the configuration file.\n' 988 raise self.InvalidCmd(error_msg) 989 990 991 992 tag = [a for a in args if a.startswith('--tag=')] 993 if tag: 994 args.remove(tag[0]) 995 tag = tag[0][6:] 996 997 if len(args) == 0 and not self.run_name: 998 if self.results.lastrun: 999 args.insert(0, self.results.lastrun) 1000 else: 1001 raise self.InvalidCmd('No run name currently define. Please add this information.') 1002 1003 if len(args) >= 1: 1004 if args[0] != self.run_name and\ 1005 not os.path.exists(pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe.gz')): 1006 raise self.InvalidCmd('No events file corresponding to %s run. '% args[0]) 1007 self.set_run_name(args[0], tag, 'pythia') 1008 else: 1009 if tag: 1010 self.run_card['run_tag'] = tag 1011 self.set_run_name(self.run_name, tag, 'pythia') 1012 1013 input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe') 1014 output_file = pjoin(self.me_dir, 'Events', 'unweighted_events.lhe') 1015 if not os.path.exists('%s.gz' % input_file): 1016 if not os.path.exists(input_file): 1017 raise self.InvalidCmd('No events file corresponding to %s run. '% self.run_name) 1018 files.ln(input_file, os.path.dirname(output_file)) 1019 else: 1020 misc.gunzip(input_file, keep=True, stdout=output_file) 1021 1022 args.append(mode)
1023
1024 - def check_pythia8(self, args):
1025 """Check the argument for pythia command 1026 syntax: pythia8 [NAME] 1027 Note that other option are already removed at this point 1028 """ 1029 mode = None 1030 laststep = [arg for arg in args if arg.startswith('--laststep=')] 1031 if laststep and len(laststep)==1: 1032 mode = laststep[0].split('=')[-1] 1033 if mode not in ['auto', 'pythia','pythia8','delphes']: 1034 self.help_pythia8() 1035 raise self.InvalidCmd('invalid %s argument'% args[-1]) 1036 elif laststep: 1037 raise self.InvalidCmd('only one laststep argument is allowed') 1038 1039 # If not pythia-pgs path 1040 if not self.options['pythia8_path']: 1041 logger.info('Retry reading configuration file to find pythia8 path') 1042 self.set_configuration() 1043 1044 if not self.options['pythia8_path'] or not \ 1045 os.path.exists(pjoin(self.options['pythia8_path'],'bin','pythia8-config')): 1046 error_msg = 'No valid pythia8 path set.\n' 1047 error_msg += 'Please use the set command to define the path and retry.\n' 1048 error_msg += 'You can also define it in the configuration file.\n' 1049 error_msg += 'Finally, it can be installed automatically using the' 1050 error_msg += ' install command.\n' 1051 raise self.InvalidCmd(error_msg) 1052 1053 tag = [a for a in args if a.startswith('--tag=')] 1054 if tag: 1055 args.remove(tag[0]) 1056 tag = tag[0][6:] 1057 1058 if len(args) == 0 and not self.run_name: 1059 if self.results.lastrun: 1060 args.insert(0, self.results.lastrun) 1061 else: 1062 raise self.InvalidCmd('No run name currently define. '+ 1063 'Please add this information.') 1064 1065 if len(args) >= 1: 1066 if args[0] != self.run_name and\ 1067 not os.path.exists(pjoin(self.me_dir,'Events',args[0], 1068 'unweighted_events.lhe.gz')): 1069 raise self.InvalidCmd('No events file corresponding to %s run. ' 1070 % args[0]) 1071 self.set_run_name(args[0], tag, 'pythia8') 1072 else: 1073 if tag: 1074 self.run_card['run_tag'] = tag 1075 self.set_run_name(self.run_name, tag, 'pythia8') 1076 1077 input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe') 1078 if not os.path.exists('%s.gz'%input_file): 1079 if os.path.exists(input_file): 1080 misc.gzip(input_file, keep=True, stdout='%s.gz'%input_file) 1081 else: 1082 raise self.InvalidCmd('No event file corresponding to %s run. ' 1083 % self.run_name) 1084 1085 args.append(mode)
1086
1087 - def check_remove(self, args):
1088 """Check that the remove command is valid""" 1089 1090 tmp_args = args[:] 1091 1092 tag = [a[6:] for a in tmp_args if a.startswith('--tag=')] 1093 if tag: 1094 tag = tag[0] 1095 tmp_args.remove('--tag=%s' % tag) 1096 1097 1098 if len(tmp_args) == 0: 1099 self.help_remove() 1100 raise self.InvalidCmd('clean command require the name of the run to clean') 1101 elif len(tmp_args) == 1: 1102 return tmp_args[0], tag, ['all'] 1103 else: 1104 for arg in tmp_args[1:]: 1105 if arg not in self._clean_mode: 1106 self.help_remove() 1107 raise self.InvalidCmd('%s is not a valid options for clean command'\ 1108 % arg) 1109 return tmp_args[0], tag, tmp_args[1:]
1110
1111 - def check_plot(self, args):
1112 """Check the argument for the plot command 1113 plot run_name modes""" 1114 1115 madir = self.options['madanalysis_path'] 1116 td = self.options['td_path'] 1117 1118 if not madir or not td: 1119 logger.info('Retry to read configuration file to find madanalysis/td') 1120 self.set_configuration() 1121 1122 madir = self.options['madanalysis_path'] 1123 td = self.options['td_path'] 1124 1125 if not madir: 1126 error_msg = 'No valid MadAnalysis path set.\n' 1127 error_msg += 'Please use the set command to define the path and retry.\n' 1128 error_msg += 'You can also define it in the configuration file.\n' 1129 raise self.InvalidCmd(error_msg) 1130 if not td: 1131 error_msg = 'No valid td path set.\n' 1132 error_msg += 'Please use the set command to define the path and retry.\n' 1133 error_msg += 'You can also define it in the configuration file.\n' 1134 raise self.InvalidCmd(error_msg) 1135 1136 if len(args) == 0: 1137 if not hasattr(self, 'run_name') or not self.run_name: 1138 self.help_plot() 1139 raise self.InvalidCmd('No run name currently define. Please add this information.') 1140 args.append('all') 1141 return 1142 1143 1144 if args[0] not in self._plot_mode: 1145 self.set_run_name(args[0], level='plot') 1146 del args[0] 1147 if len(args) == 0: 1148 args.append('all') 1149 elif not self.run_name: 1150 self.help_plot() 1151 raise self.InvalidCmd('No run name currently define. Please add this information.') 1152 1153 for arg in args: 1154 if arg not in self._plot_mode and arg != self.run_name: 1155 self.help_plot() 1156 raise self.InvalidCmd('unknown options %s' % arg)
1157
1158 - def check_syscalc(self, args):
1159 """Check the argument for the syscalc command 1160 syscalc run_name modes""" 1161 1162 scdir = self.options['syscalc_path'] 1163 1164 if not scdir: 1165 logger.info('Retry to read configuration file to find SysCalc') 1166 self.set_configuration() 1167 1168 scdir = self.options['syscalc_path'] 1169 1170 if not scdir: 1171 error_msg = 'No valid SysCalc path set.\n' 1172 error_msg += 'Please use the set command to define the path and retry.\n' 1173 error_msg += 'You can also define it in the configuration file.\n' 1174 error_msg += 'Please note that you need to compile SysCalc first.' 1175 raise self.InvalidCmd(error_msg) 1176 1177 if len(args) == 0: 1178 if not hasattr(self, 'run_name') or not self.run_name: 1179 self.help_syscalc() 1180 raise self.InvalidCmd('No run name currently defined. Please add this information.') 1181 args.append('all') 1182 return 1183 1184 #deal options 1185 tag = [a for a in args if a.startswith('--tag=')] 1186 if tag: 1187 args.remove(tag[0]) 1188 tag = tag[0][6:] 1189 1190 if args[0] not in self._syscalc_mode: 1191 self.set_run_name(args[0], tag=tag, level='syscalc') 1192 del args[0] 1193 if len(args) == 0: 1194 args.append('all') 1195 elif not self.run_name: 1196 self.help_syscalc() 1197 raise self.InvalidCmd('No run name currently defined. Please add this information.') 1198 elif tag and tag != self.run_tag: 1199 self.set_run_name(self.run_name, tag=tag, level='syscalc') 1200 1201 for arg in args: 1202 if arg not in self._syscalc_mode and arg != self.run_name: 1203 self.help_syscalc() 1204 raise self.InvalidCmd('unknown options %s' % arg) 1205 1206 if self.run_card['use_syst'] not in self.true: 1207 raise self.InvalidCmd('Run %s does not include ' % self.run_name + \ 1208 'systematics information needed for syscalc.')
1209 1210
1211 - def check_pgs(self, arg, no_default=False):
1212 """Check the argument for pythia command 1213 syntax is "pgs [NAME]" 1214 Note that other option are already remove at this point 1215 """ 1216 1217 # If not pythia-pgs path 1218 if not self.options['pythia-pgs_path']: 1219 logger.info('Retry to read configuration file to find pythia-pgs path') 1220 self.set_configuration() 1221 1222 if not self.options['pythia-pgs_path'] or not \ 1223 os.path.exists(pjoin(self.options['pythia-pgs_path'],'src')): 1224 error_msg = 'No valid pythia-pgs path set.\n' 1225 error_msg += 'Please use the set command to define the path and retry.\n' 1226 error_msg += 'You can also define it in the configuration file.\n' 1227 raise self.InvalidCmd(error_msg) 1228 1229 tag = [a for a in arg if a.startswith('--tag=')] 1230 if tag: 1231 arg.remove(tag[0]) 1232 tag = tag[0][6:] 1233 1234 1235 if len(arg) == 0 and not self.run_name: 1236 if self.results.lastrun: 1237 arg.insert(0, self.results.lastrun) 1238 else: 1239 raise self.InvalidCmd('No run name currently define. Please add this information.') 1240 1241 if len(arg) == 1 and self.run_name == arg[0]: 1242 arg.pop(0) 1243 1244 if not len(arg) and \ 1245 not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')): 1246 if not no_default: 1247 self.help_pgs() 1248 raise self.InvalidCmd('''No file file pythia_events.hep currently available 1249 Please specify a valid run_name''') 1250 1251 lock = None 1252 if len(arg) == 1: 1253 prev_tag = self.set_run_name(arg[0], tag, 'pgs') 1254 if not os.path.exists(pjoin(self.me_dir,'Events',self.run_name,'%s_pythia_events.hep.gz' % prev_tag)): 1255 raise self.InvalidCmd('No events file corresponding to %s run with tag %s. '% (self.run_name, prev_tag)) 1256 else: 1257 input_file = pjoin(self.me_dir,'Events', self.run_name, '%s_pythia_events.hep.gz' % prev_tag) 1258 output_file = pjoin(self.me_dir, 'Events', 'pythia_events.hep') 1259 lock = cluster.asyncrone_launch('gunzip',stdout=open(output_file,'w'), 1260 argument=['-c', input_file]) 1261 1262 else: 1263 if tag: 1264 self.run_card['run_tag'] = tag 1265 self.set_run_name(self.run_name, tag, 'pgs') 1266 1267 return lock
1268
1269 - def check_display(self, args):
1270 """check the validity of line 1271 syntax is "display XXXXX" 1272 """ 1273 1274 if len(args) < 1 or args[0] not in self._display_opts: 1275 self.help_display() 1276 raise self.InvalidCmd 1277 1278 if args[0] == 'variable' and len(args) !=2: 1279 raise self.InvalidCmd('variable need a variable name')
1280 1281 1282 1283 1284
1285 - def check_import(self, args):
1286 """check the validity of line""" 1287 1288 if not args: 1289 self.help_import() 1290 raise self.InvalidCmd('wrong \"import\" format') 1291 1292 if args[0] != 'command': 1293 args.insert(0,'command') 1294 1295 1296 if not len(args) == 2 or not os.path.exists(args[1]): 1297 raise self.InvalidCmd('PATH is mandatory for import command\n')
1298
1299 1300 #=============================================================================== 1301 # CompleteForCmd 1302 #=============================================================================== 1303 -class CompleteForCmd(CheckValidForCmd):
1304 """ The Series of help routine for the MadGraphCmd""" 1305 1306
1307 - def complete_add_time_of_flight(self, text, line, begidx, endidx):
1308 "Complete command" 1309 1310 args = self.split_arg(line[0:begidx], error=False) 1311 1312 if len(args) == 1: 1313 #return valid run_name 1314 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'), pjoin(self.me_dir, 'Events')) 1315 data = [n.rsplit('/',2)[1] for n in data] 1316 return self.list_completion(text, data + ['--threshold='], line) 1317 elif args[-1].endswith(os.path.sep): 1318 return self.path_completion(text, 1319 os.path.join('.',*[a for a in args \ 1320 if a.endswith(os.path.sep)])) 1321 else: 1322 return self.list_completion(text, ['--threshold='], line)
1323
1324 - def complete_banner_run(self, text, line, begidx, endidx, formatting=True):
1325 "Complete the banner run command" 1326 try: 1327 1328 1329 args = self.split_arg(line[0:begidx], error=False) 1330 1331 if args[-1].endswith(os.path.sep): 1332 return self.path_completion(text, 1333 os.path.join('.',*[a for a in args \ 1334 if a.endswith(os.path.sep)])) 1335 1336 1337 if len(args) > 1: 1338 # only options are possible 1339 tags = misc.glob('%s_*_banner.txt' % args[1], pjoin(self.me_dir, 'Events' , args[1])) 1340 tags = ['%s' % os.path.basename(t)[len(args[1])+1:-11] for t in tags] 1341 1342 if args[-1] != '--tag=': 1343 tags = ['--tag=%s' % t for t in tags] 1344 else: 1345 return self.list_completion(text, tags) 1346 return self.list_completion(text, tags +['--name=','-f'], line) 1347 1348 # First argument 1349 possibilites = {} 1350 1351 comp = self.path_completion(text, os.path.join('.',*[a for a in args \ 1352 if a.endswith(os.path.sep)])) 1353 if os.path.sep in line: 1354 return comp 1355 else: 1356 possibilites['Path from ./'] = comp 1357 1358 run_list = misc.glob(pjoin('*','*_banner.txt'), pjoin(self.me_dir, 'Events')) 1359 run_list = [n.rsplit('/',2)[1] for n in run_list] 1360 possibilites['RUN Name'] = self.list_completion(text, run_list) 1361 1362 return self.deal_multiple_categories(possibilites, formatting) 1363 1364 1365 except Exception, error: 1366 print error
1367 1368
1369 - def complete_history(self, text, line, begidx, endidx):
1370 "Complete the history command" 1371 1372 args = self.split_arg(line[0:begidx], error=False) 1373 1374 # Directory continuation 1375 if args[-1].endswith(os.path.sep): 1376 return self.path_completion(text, 1377 os.path.join('.',*[a for a in args \ 1378 if a.endswith(os.path.sep)])) 1379 1380 if len(args) == 1: 1381 return self.path_completion(text)
1382
1383 - def complete_open(self, text, line, begidx, endidx):
1384 """ complete the open command """ 1385 1386 args = self.split_arg(line[0:begidx]) 1387 1388 # Directory continuation 1389 if os.path.sep in args[-1] + text: 1390 return self.path_completion(text, 1391 os.path.join('.',*[a for a in args if \ 1392 a.endswith(os.path.sep)])) 1393 1394 possibility = [] 1395 if self.me_dir: 1396 path = self.me_dir 1397 possibility = ['index.html'] 1398 if os.path.isfile(os.path.join(path,'README')): 1399 possibility.append('README') 1400 if os.path.isdir(os.path.join(path,'Cards')): 1401 possibility += [f for f in os.listdir(os.path.join(path,'Cards')) 1402 if f.endswith('.dat')] 1403 if os.path.isdir(os.path.join(path,'HTML')): 1404 possibility += [f for f in os.listdir(os.path.join(path,'HTML')) 1405 if f.endswith('.html') and 'default' not in f] 1406 else: 1407 possibility.extend(['./','../']) 1408 if os.path.exists('ME5_debug'): 1409 possibility.append('ME5_debug') 1410 if os.path.exists('MG5_debug'): 1411 possibility.append('MG5_debug') 1412 return self.list_completion(text, possibility)
1413
1414 - def complete_set(self, text, line, begidx, endidx):
1415 "Complete the set command" 1416 1417 args = self.split_arg(line[0:begidx]) 1418 1419 # Format 1420 if len(args) == 1: 1421 return self.list_completion(text, self._set_options + self.options.keys() ) 1422 1423 if len(args) == 2: 1424 if args[1] == 'stdout_level': 1425 return self.list_completion(text, ['DEBUG','INFO','WARNING','ERROR','CRITICAL']) 1426 else: 1427 first_set = ['None','True','False'] 1428 # directory names 1429 second_set = [name for name in self.path_completion(text, '.', only_dirs = True)] 1430 return self.list_completion(text, first_set + second_set) 1431 elif len(args) >2 and args[-1].endswith(os.path.sep): 1432 return self.path_completion(text, 1433 os.path.join('.',*[a for a in args if a.endswith(os.path.sep)]), 1434 only_dirs = True)
1435
1436 - def complete_survey(self, text, line, begidx, endidx):
1437 """ Complete the survey command """ 1438 1439 if line.endswith('nb_core=') and not text: 1440 import multiprocessing 1441 max = multiprocessing.cpu_count() 1442 return [str(i) for i in range(2,max+1)] 1443 1444 return self.list_completion(text, self._run_options, line)
1445 1446 complete_refine = complete_survey 1447 complete_combine_events = complete_survey 1448 complite_store = complete_survey 1449 complete_generate_events = complete_survey 1450 complete_create_gridpack = complete_survey 1451
1452 - def complete_generate_events(self, text, line, begidx, endidx):
1453 """ Complete the generate events""" 1454 1455 if line.endswith('nb_core=') and not text: 1456 import multiprocessing 1457 max = multiprocessing.cpu_count() 1458 return [str(i) for i in range(2,max+1)] 1459 if line.endswith('laststep=') and not text: 1460 return ['parton','pythia','pgs','delphes'] 1461 elif '--laststep=' in line.split()[-1] and line and line[-1] != ' ': 1462 return self.list_completion(text,['parton','pythia','pgs','delphes'],line) 1463 1464 opts = self._run_options + self._generate_options 1465 return self.list_completion(text, opts, line)
1466 1467
1468 - def complete_initMadLoop(self, text, line, begidx, endidx):
1469 "Complete the initMadLoop command" 1470 1471 numbers = [str(i) for i in range(10)] 1472 opts = ['-f','-r','--nPS='] 1473 1474 args = self.split_arg(line[0:begidx], error=False) 1475 if len(line) >=6 and line[begidx-6:begidx]=='--nPS=': 1476 return self.list_completion(text, numbers, line) 1477 else: 1478 return self.list_completion(text, [opt for opt in opts if not opt in 1479 line], line)
1480
1481 - def complete_launch(self, *args, **opts):
1482 1483 if self.ninitial == 1: 1484 return self.complete_calculate_decay_widths(*args, **opts) 1485 else: 1486 return self.complete_generate_events(*args, **opts)
1487
1488 - def complete_calculate_decay_widths(self, text, line, begidx, endidx):
1489 """ Complete the calculate_decay_widths command""" 1490 1491 if line.endswith('nb_core=') and not text: 1492 import multiprocessing 1493 max = multiprocessing.cpu_count() 1494 return [str(i) for i in range(2,max+1)] 1495 1496 opts = self._run_options + self._calculate_decay_options 1497 return self.list_completion(text, opts, line)
1498
1499 - def complete_display(self, text, line, begidx, endidx):
1500 """ Complete the display command""" 1501 1502 args = self.split_arg(line[0:begidx], error=False) 1503 if len(args) >= 2 and args[1] =='results': 1504 start = line.find('results') 1505 return self.complete_print_results(text, 'print_results '+line[start+7:], begidx+2+start, endidx+2+start) 1506 return super(CompleteForCmd, self).complete_display(text, line, begidx, endidx)
1507
1508 - def complete_multi_run(self, text, line, begidx, endidx):
1509 """complete multi run command""" 1510 1511 args = self.split_arg(line[0:begidx], error=False) 1512 if len(args) == 1: 1513 data = [str(i) for i in range(0,20)] 1514 return self.list_completion(text, data, line) 1515 1516 if line.endswith('run=') and not text: 1517 return ['parton','pythia','pgs','delphes'] 1518 elif '--laststep=' in line.split()[-1] and line and line[-1] != ' ': 1519 return self.list_completion(text,['parton','pythia','pgs','delphes'],line) 1520 1521 opts = self._run_options + self._generate_options 1522 return self.list_completion(text, opts, line) 1523 1524 1525 1526 if line.endswith('nb_core=') and not text: 1527 import multiprocessing 1528 max = multiprocessing.cpu_count() 1529 return [str(i) for i in range(2,max+1)] 1530 opts = self._run_options + self._generate_options 1531 return self.list_completion(text, opts, line)
1532
1533 - def complete_plot(self, text, line, begidx, endidx):
1534 """ Complete the plot command """ 1535 1536 args = self.split_arg(line[0:begidx], error=False) 1537 if len(args) > 1: 1538 return self.list_completion(text, self._plot_mode) 1539 else: 1540 return self.list_completion(text, self._plot_mode + self.results.keys())
1541
1542 - def complete_syscalc(self, text, line, begidx, endidx, formatting=True):
1543 """ Complete the syscalc command """ 1544 1545 output = {} 1546 args = self.split_arg(line[0:begidx], error=False) 1547 1548 if len(args) <=1: 1549 output['RUN_NAME'] = self.list_completion(self.results.keys()) 1550 output['MODE'] = self.list_completion(text, self._syscalc_mode) 1551 output['options'] = ['-f'] 1552 if len(args) > 1 and (text.startswith('--t')): 1553 run = args[1] 1554 if run in self.results: 1555 tags = ['--tag=%s' % tag['tag'] for tag in self.results[run]] 1556 output['options'] += tags 1557 1558 return self.deal_multiple_categories(output, formatting)
1559
1560 - def complete_remove(self, text, line, begidx, endidx):
1561 """Complete the remove command """ 1562 1563 args = self.split_arg(line[0:begidx], error=False) 1564 if len(args) > 1 and (text.startswith('--t')): 1565 run = args[1] 1566 tags = ['--tag=%s' % tag['tag'] for tag in self.results[run]] 1567 return self.list_completion(text, tags) 1568 elif len(args) > 1 and '--' == args[-1]: 1569 run = args[1] 1570 tags = ['tag=%s' % tag['tag'] for tag in self.results[run]] 1571 return self.list_completion(text, tags) 1572 elif len(args) > 1 and '--tag=' == args[-1]: 1573 run = args[1] 1574 tags = [tag['tag'] for tag in self.results[run]] 1575 return self.list_completion(text, tags) 1576 elif len(args) > 1: 1577 return self.list_completion(text, self._clean_mode + ['-f','--tag=']) 1578 else: 1579 data = misc.glob(pjoin('*','*_banner.txt'), pjoin(self.me_dir, 'Events')) 1580 data = [n.rsplit('/',2)[1] for n in data] 1581 return self.list_completion(text, ['all'] + data)
1582 1583
1584 - def complete_shower(self,text, line, begidx, endidx):
1585 "Complete the shower command" 1586 args = self.split_arg(line[0:begidx], error=False) 1587 if len(args) == 1: 1588 return self.list_completion(text, self._interfaced_showers) 1589 elif len(args)>1 and args[1] in self._interfaced_showers: 1590 return getattr(self, 'complete_%s' % text)\ 1591 (text, args[1],line.replace(args[0]+' ',''), 1592 begidx-len(args[0])-1, endidx-len(args[0])-1)
1593
1594 - def complete_pythia8(self,text, line, begidx, endidx):
1595 "Complete the pythia8 command" 1596 args = self.split_arg(line[0:begidx], error=False) 1597 if len(args) == 1: 1598 #return valid run_name 1599 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'),pjoin(self.me_dir, 'Events')) 1600 data = [n.rsplit('/',2)[1] for n in data] 1601 tmp1 = self.list_completion(text, data) 1602 if not self.run_name: 1603 return tmp1 1604 else: 1605 tmp2 = self.list_completion(text, self._run_options + ['-f', 1606 '--no_default', '--tag='], line) 1607 return tmp1 + tmp2 1608 elif line[-1] != '=': 1609 return self.list_completion(text, self._run_options + ['-f', 1610 '--no_default','--tag='], line)
1611
1612 - def complete_madanalysis5_parton(self,text, line, begidx, endidx):
1613 "Complete the madanalysis5 command" 1614 args = self.split_arg(line[0:begidx], error=False) 1615 if len(args) == 1: 1616 #return valid run_name 1617 data = [] 1618 for name in ['unweighted_events.lhe']: 1619 data += misc.glob(pjoin('*','%s'%name), pjoin(self.me_dir, 'Events')) 1620 data += misc.glob(pjoin('*','%s.gz'%name), pjoin(self.me_dir, 'Events')) 1621 data = [n.rsplit('/',2)[1] for n in data] 1622 tmp1 = self.list_completion(text, data) 1623 if not self.run_name: 1624 return tmp1 1625 else: 1626 tmp2 = self.list_completion(text, ['-f', 1627 '--MA5_stdout_lvl=','--no_default','--tag='], line) 1628 return tmp1 + tmp2 1629 elif '--MA5_stdout_lvl=' in line and not any(arg.startswith( 1630 '--MA5_stdout_lvl=') for arg in args): 1631 return self.list_completion(text, 1632 ['--MA5_stdout_lvl=%s'%opt for opt in 1633 ['logging.INFO','logging.DEBUG','logging.WARNING', 1634 'logging.CRITICAL','90']], line) 1635 else: 1636 return self.list_completion(text, ['-f', 1637 '--MA5_stdout_lvl=','--no_default','--tag='], line)
1638
1639 - def complete_pythia(self,text, line, begidx, endidx):
1640 "Complete the pythia command" 1641 args = self.split_arg(line[0:begidx], error=False) 1642 1643 if len(args) == 1: 1644 #return valid run_name 1645 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'), pjoin(self.me_dir, 'Events')) 1646 data = [n.rsplit('/',2)[1] for n in data] 1647 tmp1 = self.list_completion(text, data) 1648 if not self.run_name: 1649 return tmp1 1650 else: 1651 tmp2 = self.list_completion(text, self._run_options + ['-f', 1652 '--no_default', '--tag='], line) 1653 return tmp1 + tmp2 1654 elif line[-1] != '=': 1655 return self.list_completion(text, self._run_options + ['-f', 1656 '--no_default','--tag='], line)
1657
1658 - def complete_pgs(self,text, line, begidx, endidx):
1659 "Complete the pythia command" 1660 args = self.split_arg(line[0:begidx], error=False) 1661 if len(args) == 1: 1662 #return valid run_name 1663 data = misc.glob(pjoin('*', '*_pythia_events.hep.gz'), pjoin(self.me_dir, 'Events')) 1664 data = [n.rsplit('/',2)[1] for n in data] 1665 tmp1 = self.list_completion(text, data) 1666 if not self.run_name: 1667 return tmp1 1668 else: 1669 tmp2 = self.list_completion(text, self._run_options + ['-f', 1670 '--tag=' ,'--no_default'], line) 1671 return tmp1 + tmp2 1672 else: 1673 return self.list_completion(text, self._run_options + ['-f', 1674 '--tag=','--no_default'], line)
1675 1676 complete_delphes = complete_pgs 1677
1678 1679 1680 1681 1682 #=============================================================================== 1683 # MadEventCmd 1684 #=============================================================================== 1685 -class MadEventCmd(CompleteForCmd, CmdExtended, HelpToCmd, common_run.CommonRunCmd):
1686 1687 """The command line processor of MadGraph""" 1688 1689 # Truth values 1690 true = ['T','.true.',True,'true'] 1691 # Options and formats available 1692 _run_options = ['--cluster','--multicore','--nb_core=','--nb_core=2', '-c', '-m'] 1693 _generate_options = ['-f', '--laststep=parton', '--laststep=pythia', '--laststep=pgs', '--laststep=delphes'] 1694 _calculate_decay_options = ['-f', '--accuracy=0.'] 1695 _interfaced_showers = ['pythia','pythia8'] 1696 _set_options = ['stdout_level','fortran_compiler','timeout'] 1697 _plot_mode = ['all', 'parton','pythia','pgs','delphes','channel', 'banner'] 1698 _syscalc_mode = ['all', 'parton','pythia'] 1699 _clean_mode = _plot_mode 1700 _display_opts = ['run_name', 'options', 'variable', 'results'] 1701 _save_opts = ['options'] 1702 _initMadLoop_opts = ['-f','-r','--nPS='] 1703 # survey options, dict from name to type, default value, and help text 1704 _survey_options = {'points':('int', 1000,'Number of points for first iteration'), 1705 'iterations':('int', 5, 'Number of iterations'), 1706 'accuracy':('float', 0.1, 'Required accuracy'), 1707 'gridpack':('str', '.false.', 'Gridpack generation')} 1708 # Variables to store object information 1709 true = ['T','.true.',True,'true', 1, '1'] 1710 web = False 1711 cluster_mode = 0 1712 queue = 'madgraph' 1713 nb_core = None 1714 1715 next_possibility = { 1716 'start': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]', 1717 'calculate_decay_widths [OPTIONS]', 1718 'help generate_events'], 1719 'generate_events': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]', 'pythia', 'pgs','delphes'], 1720 'calculate_decay_widths': ['calculate_decay_widths [OPTIONS]', 1721 'generate_events [OPTIONS]'], 1722 'multi_run': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'], 1723 'survey': ['refine'], 1724 'refine': ['combine_events'], 1725 'combine_events': ['store'], 1726 'store': ['pythia'], 1727 'pythia': ['pgs', 'delphes'], 1728 'pgs': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'], 1729 'delphes' : ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'] 1730 } 1731 1732 ############################################################################
1733 - def __init__(self, me_dir = None, options={}, *completekey, **stdin):
1734 """ add information to the cmd """ 1735 1736 CmdExtended.__init__(self, me_dir, options, *completekey, **stdin) 1737 #common_run.CommonRunCmd.__init__(self, me_dir, options) 1738 1739 self.mode = 'madevent' 1740 self.nb_refine=0 1741 if self.web: 1742 os.system('touch %s' % pjoin(self.me_dir,'Online')) 1743 1744 self.load_results_db() 1745 self.results.def_web_mode(self.web) 1746 1747 self.prompt = "%s>"%os.path.basename(pjoin(self.me_dir)) 1748 self.configured = 0 # time for reading the card 1749 self._options = {} # for compatibility with extended_cmd
1750 1751
1752 - def pass_in_web_mode(self):
1753 """configure web data""" 1754 self.web = True 1755 self.results.def_web_mode(True) 1756 self.force = True 1757 if os.environ['MADGRAPH_BASE']: 1758 self.options['mg5_path'] = pjoin(os.environ['MADGRAPH_BASE'],'MG5')
1759 1760 ############################################################################
1761 - def check_output_type(self, path):
1762 """ Check that the output path is a valid madevent directory """ 1763 1764 bin_path = os.path.join(path,'bin') 1765 if os.path.isfile(os.path.join(bin_path,'generate_events')): 1766 return True 1767 else: 1768 return False
1769 1770 ############################################################################
1771 - def set_configuration(self, amcatnlo=False, final=True, **opt):
1772 """assign all configuration variable from file 1773 loop over the different config file if config_file not define """ 1774 1775 super(MadEventCmd,self).set_configuration(amcatnlo=amcatnlo, 1776 final=final, **opt) 1777 1778 if not final: 1779 return self.options # the return is usefull for unittest 1780 1781 1782 # Treat each expected input 1783 # delphes/pythia/... path 1784 # ONLY the ONE LINKED TO Madevent ONLY!!! 1785 for key in (k for k in self.options if k.endswith('path')): 1786 path = self.options[key] 1787 if path is None or key.startswith("cluster"): 1788 continue 1789 if not os.path.isdir(path): 1790 path = pjoin(self.me_dir, self.options[key]) 1791 if os.path.isdir(path): 1792 self.options[key] = None 1793 if key == "pythia-pgs_path": 1794 if not os.path.exists(pjoin(path, 'src','pythia')): 1795 logger.info("No valid pythia-pgs path found") 1796 continue 1797 elif key == "delphes_path": 1798 if not os.path.exists(pjoin(path, 'Delphes')) and not\ 1799 os.path.exists(pjoin(path, 'DelphesSTDHEP')): 1800 logger.info("No valid Delphes path found") 1801 continue 1802 elif key == "madanalysis_path": 1803 if not os.path.exists(pjoin(path, 'plot_events')): 1804 logger.info("No valid MadAnalysis path found") 1805 continue 1806 elif key == "td_path": 1807 if not os.path.exists(pjoin(path, 'td')): 1808 logger.info("No valid td path found") 1809 continue 1810 elif key == "syscalc_path": 1811 if not os.path.exists(pjoin(path, 'sys_calc')): 1812 logger.info("No valid SysCalc path found") 1813 continue 1814 # No else since the next line reinitialize the option to the 1815 #previous value anyway 1816 self.options[key] = os.path.realpath(path) 1817 continue 1818 else: 1819 self.options[key] = None 1820 1821 1822 return self.options
1823 1824 ############################################################################
1825 - def do_add_time_of_flight(self, line):
1826 1827 args = self.split_arg(line) 1828 #check the validity of the arguments and reformat args 1829 self.check_add_time_of_flight(args) 1830 1831 event_path, threshold = args 1832 #gunzip the file 1833 if event_path.endswith('.gz'): 1834 need_zip = True 1835 misc.gunzip(event_path) 1836 event_path = event_path[:-3] 1837 else: 1838 need_zip = False 1839 1840 import random 1841 try: 1842 import madgraph.various.lhe_parser as lhe_parser 1843 except: 1844 import internal.lhe_parser as lhe_parser 1845 1846 logger.info('Add time of flight information on file %s' % event_path) 1847 lhe = lhe_parser.EventFile(event_path) 1848 output = open('%s_2vertex.lhe' % event_path, 'w') 1849 #write the banner to the output file 1850 output.write(lhe.banner) 1851 1852 # get the associate param_card 1853 begin_param = lhe.banner.find('<slha>') 1854 end_param = lhe.banner.find('</slha>') 1855 param_card = lhe.banner[begin_param+6:end_param].split('\n') 1856 param_card = check_param_card.ParamCard(param_card) 1857 1858 cst = 6.58211915e-25 # hbar in GeV s 1859 c = 299792458000 # speed of light in mm/s 1860 # Loop over all events 1861 for event in lhe: 1862 for particle in event: 1863 id = particle.pid 1864 width = param_card['decay'].get((abs(id),)).value 1865 if width: 1866 vtim = c * random.expovariate(width/cst) 1867 if vtim > threshold: 1868 particle.vtim = vtim 1869 #write this modify event 1870 output.write(str(event)) 1871 output.write('</LesHouchesEvents>\n') 1872 output.close() 1873 1874 files.mv('%s_2vertex.lhe' % event_path, event_path) 1875 1876 if need_zip: 1877 misc.gzip(event_path)
1878 1879 ############################################################################
1880 - def do_banner_run(self, line):
1881 """Make a run from the banner file""" 1882 1883 args = self.split_arg(line) 1884 #check the validity of the arguments 1885 self.check_banner_run(args) 1886 1887 # Remove previous cards 1888 for name in ['delphes_trigger.dat', 'delphes_card.dat', 1889 'pgs_card.dat', 'pythia_card.dat', 'madspin_card.dat', 1890 'reweight_card.dat']: 1891 try: 1892 os.remove(pjoin(self.me_dir, 'Cards', name)) 1893 except Exception: 1894 pass 1895 1896 banner_mod.split_banner(args[0], self.me_dir, proc_card=False) 1897 1898 # Check if we want to modify the run 1899 if not self.force: 1900 ans = self.ask('Do you want to modify the Cards?', 'n', ['y','n']) 1901 if ans == 'n': 1902 self.force = True 1903 1904 # Call Generate events 1905 self.exec_cmd('generate_events %s %s' % (self.run_name, self.force and '-f' or ''))
1906 1907 1908 1909 ############################################################################
1910 - def do_display(self, line, output=sys.stdout):
1911 """Display current internal status""" 1912 1913 args = self.split_arg(line) 1914 #check the validity of the arguments 1915 self.check_display(args) 1916 1917 if args[0] == 'run_name': 1918 #return valid run_name 1919 data = misc.glob(pjoin('*','*_banner.txt'), pjoin(self.me_dir, 'Events')) 1920 data = [n.rsplit('/',2)[1:] for n in data] 1921 1922 if data: 1923 out = {} 1924 for name, tag in data: 1925 tag = tag[len(name)+1:-11] 1926 if name in out: 1927 out[name].append(tag) 1928 else: 1929 out[name] = [tag] 1930 print 'the runs available are:' 1931 for run_name, tags in out.items(): 1932 print ' run: %s' % run_name 1933 print ' tags: ', 1934 print ', '.join(tags) 1935 else: 1936 print 'No run detected.' 1937 1938 elif args[0] == 'options': 1939 outstr = " Run Options \n" 1940 outstr += " ----------- \n" 1941 for key, default in self.options_madgraph.items(): 1942 value = self.options[key] 1943 if value == default: 1944 outstr += " %25s \t:\t%s\n" % (key,value) 1945 else: 1946 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 1947 outstr += "\n" 1948 outstr += " MadEvent Options \n" 1949 outstr += " ---------------- \n" 1950 for key, default in self.options_madevent.items(): 1951 if key in self.options: 1952 value = self.options[key] 1953 else: 1954 default = '' 1955 if value == default: 1956 outstr += " %25s \t:\t%s\n" % (key,value) 1957 else: 1958 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 1959 outstr += "\n" 1960 outstr += " Configuration Options \n" 1961 outstr += " --------------------- \n" 1962 for key, default in self.options_configuration.items(): 1963 value = self.options[key] 1964 if value == default: 1965 outstr += " %25s \t:\t%s\n" % (key,value) 1966 else: 1967 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 1968 output.write(outstr) 1969 elif args[0] == 'results': 1970 self.do_print_results(' '.join(args[1:])) 1971 else: 1972 super(MadEventCmd, self).do_display(line, output)
1973
1974 - def do_save(self, line, check=True, to_keep={}):
1975 """Not in help: Save information to file""" 1976 1977 args = self.split_arg(line) 1978 # Check argument validity 1979 if check: 1980 self.check_save(args) 1981 1982 if args[0] == 'options': 1983 # First look at options which should be put in MG5DIR/input 1984 to_define = {} 1985 for key, default in self.options_configuration.items(): 1986 if self.options[key] != self.options_configuration[key]: 1987 to_define[key] = self.options[key] 1988 1989 if not '--auto' in args: 1990 for key, default in self.options_madevent.items(): 1991 if self.options[key] != self.options_madevent[key]: 1992 to_define[key] = self.options[key] 1993 1994 if '--all' in args: 1995 for key, default in self.options_madgraph.items(): 1996 if self.options[key] != self.options_madgraph[key]: 1997 to_define[key] = self.options[key] 1998 elif not '--auto' in args: 1999 for key, default in self.options_madgraph.items(): 2000 if self.options[key] != self.options_madgraph[key]: 2001 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 2002 % (key,self.options_madgraph[key]) ) 2003 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 2004 if len(args) >1 and not args[1].startswith('--'): 2005 filepath = args[1] 2006 else: 2007 filepath = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 2008 basefile = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 2009 basedir = self.me_dir 2010 2011 if to_keep: 2012 to_define = to_keep 2013 self.write_configuration(filepath, basefile, basedir, to_define)
2014 2015 2016 2017
2018 - def do_edit_cards(self, line):
2019 """Advanced commands: Basic edition of the cards""" 2020 args = self.split_arg(line) 2021 # Check argument's validity 2022 mode = self.check_generate_events(args) 2023 self.ask_run_configuration(mode) 2024 2025 return
2026 2027 ############################################################################ 2028 2029 ############################################################################
2030 - def do_generate_events(self, line):
2031 """Main Commands: launch the full chain """ 2032 2033 self.banner = None 2034 args = self.split_arg(line) 2035 # Check argument's validity 2036 mode = self.check_generate_events(args) 2037 self.ask_run_configuration(mode, args) 2038 if not args: 2039 # No run name assigned -> assigned one automaticaly 2040 self.set_run_name(self.find_available_run_name(self.me_dir), None, 'parton') 2041 else: 2042 self.set_run_name(args[0], None, 'parton', True) 2043 args.pop(0) 2044 2045 if self.proc_characteristics['loop_induced'] and self.options['run_mode']==0: 2046 # Also the single core mode is not supported for loop-induced. 2047 # We therefore emulate it with multi-core mode with one core 2048 logger.warning( 2049 """Single-core mode not supported for loop-induced processes. 2050 Beware that MG5aMC now changes your runtime options to a multi-core mode with only one active core.""") 2051 self.do_set('run_mode 2') 2052 self.do_set('nb_core 1') 2053 2054 if self.run_card['gridpack'] in self.true: 2055 # Running gridpack warmup 2056 gridpack_opts=[('accuracy', 0.01), 2057 ('points', 2000), 2058 ('iterations',8), 2059 ('gridpack','.true.')] 2060 logger.info('Generating gridpack with run name %s' % self.run_name) 2061 self.exec_cmd('survey %s %s' % \ 2062 (self.run_name, 2063 " ".join(['--' + opt + '=' + str(val) for (opt,val) \ 2064 in gridpack_opts])), 2065 postcmd=False) 2066 self.exec_cmd('combine_events', postcmd=False) 2067 self.exec_cmd('store_events', postcmd=False) 2068 self.exec_cmd('decay_events -from_cards', postcmd=False) 2069 self.exec_cmd('create_gridpack', postcmd=False) 2070 else: 2071 # Regular run mode 2072 logger.info('Generating %s events with run name %s' % 2073 (self.run_card['nevents'], self.run_name)) 2074 2075 self.exec_cmd('survey %s %s' % (self.run_name,' '.join(args)), 2076 postcmd=False) 2077 nb_event = self.run_card['nevents'] 2078 bypass_run=False 2079 self.exec_cmd('refine %s' % nb_event, postcmd=False) 2080 if not float(self.results.current['cross']): 2081 # Zero cross-section. Try to guess why 2082 text = '''Survey return zero cross section. 2083 Typical reasons are the following: 2084 1) A massive s-channel particle has a width set to zero. 2085 2) The pdf are zero for at least one of the initial state particles 2086 or you are using maxjetflavor=4 for initial state b:s. 2087 3) The cuts are too strong. 2088 Please check/correct your param_card and/or your run_card.''' 2089 logger_stderr.critical(text) 2090 if not self.param_card_iterator: 2091 raise ZeroResult('See https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/FAQ-General-14') 2092 else: 2093 bypass_run = True 2094 2095 #we can bypass the following if scan and first result is zero 2096 if not bypass_run: 2097 self.exec_cmd('refine %s' % nb_event, postcmd=False) 2098 2099 self.exec_cmd('combine_events', postcmd=False,printcmd=False) 2100 self.print_results_in_shell(self.results.current) 2101 2102 if self.run_card['use_syst']: 2103 if self.run_card['systematics_program'] == 'auto': 2104 scdir = self.options['syscalc_path'] 2105 if not scdir or not os.path.exists(scdir): 2106 to_use = 'systematics' 2107 else: 2108 to_use = 'syscalc' 2109 elif self.run_card['systematics_program'].lower() in ['systematics','syscalc', 'none']: 2110 to_use = self.run_card['systematics_program'] 2111 else: 2112 logger.critical('Unvalid options for systematics_program: bypass computation of systematics variations.') 2113 to_use = 'none' 2114 2115 if to_use == 'systematics': 2116 if self.run_card['systematics_arguments'] != ['']: 2117 self.exec_cmd('systematics %s %s ' % (self.run_name, 2118 ' '.join(self.run_card['systematics_arguments'])), 2119 postcmd=False, printcmd=False) 2120 else: 2121 self.exec_cmd('systematics %s --from_card' % self.run_name, 2122 postcmd=False,printcmd=False) 2123 elif to_use == 'syscalc': 2124 self.run_syscalc('parton') 2125 2126 2127 self.create_plot('parton') 2128 self.exec_cmd('store_events', postcmd=False) 2129 self.exec_cmd('reweight -from_cards', postcmd=False) 2130 self.exec_cmd('decay_events -from_cards', postcmd=False) 2131 if self.run_card['time_of_flight']>=0: 2132 self.exec_cmd("add_time_of_flight --threshold=%s" % self.run_card['time_of_flight'] ,postcmd=False) 2133 2134 self.exec_cmd('madanalysis5_parton --no_default', postcmd=False, printcmd=False) 2135 # shower launches pgs/delphes if needed 2136 self.exec_cmd('shower --no_default', postcmd=False, printcmd=False) 2137 self.exec_cmd('madanalysis5_hadron --no_default', postcmd=False, printcmd=False) 2138 self.store_result() 2139 2140 if self.param_card_iterator: 2141 param_card_iterator = self.param_card_iterator 2142 self.param_card_iterator = [] 2143 with misc.TMP_variable(self, 'allow_notification_center', False): 2144 param_card_iterator.store_entry(self.run_name, self.results.current['cross']) 2145 #check if the param_card defines a scan. 2146 orig_name = self.run_name 2147 for card in param_card_iterator: 2148 path = pjoin(self.me_dir,'Cards','param_card.dat') 2149 card.write(pjoin(self.me_dir,'Cards','param_card.dat')) 2150 self.check_param_card(path, dependent=True) 2151 next_name = param_card_iterator.get_next_name(self.run_name) 2152 try: 2153 self.exec_cmd("generate_events -f %s" % next_name, 2154 precmd=True, postcmd=True,errorhandling=False) 2155 except ZeroResult: 2156 param_card_iterator.store_entry(self.run_name, 0) 2157 else: 2158 param_card_iterator.store_entry(self.run_name, self.results.current['cross']) 2159 param_card_iterator.write(pjoin(self.me_dir,'Cards','param_card.dat')) 2160 name = misc.get_scan_name(orig_name, self.run_name) 2161 path = pjoin(self.me_dir, 'Events','scan_%s.txt' % name) 2162 logger.info("write all cross-section results in %s" % path ,'$MG:color:BLACK') 2163 param_card_iterator.write_summary(path) 2164 2165 2166 if self.allow_notification_center: 2167 misc.apple_notify('Run %s finished' % os.path.basename(self.me_dir), 2168 '%s: %s +- %s ' % (self.results.current['run_name'], 2169 self.results.current['cross'], 2170 self.results.current['error']))
2171
2172 - def do_initMadLoop(self,line):
2173 """Compile and run MadLoop for a certain number of PS point so as to 2174 initialize MadLoop (setup the zero helicity and loop filter.)""" 2175 2176 args = line.split() 2177 # Check argument's validity 2178 options = self.check_initMadLoop(args) 2179 2180 if not options['force']: 2181 self.ask_edit_cards(['MadLoopParams.dat'], mode='fixed', plot=False) 2182 self.exec_cmd('treatcards loop --no_MadLoopInit') 2183 2184 if options['refresh']: 2185 for filter in misc.glob('*Filter*', 2186 pjoin(self.me_dir,'SubProcesses','MadLoop5_resources')): 2187 logger.debug("Resetting filter '%s'."%os.path.basename(filter)) 2188 os.remove(filter) 2189 2190 MLCard = banner_mod.MadLoopParam(pjoin(self.me_dir, 2191 'Cards','MadLoopParams.dat')) 2192 if options['nPS'] is None: 2193 options['nPS'] = MLCard['CheckCycle']+2 2194 elif options['nPS'] < MLCard['CheckCycle']+2: 2195 new_n_PS = MLCard['CheckCycle']+2 2196 logger.debug('Hard-setting user-defined n_PS (%d) to %d, because '\ 2197 %(options['nPS'],new_n_PS)+"of the 'CheckCycle' value (%d) "%MLCard['CheckCycle']+\ 2198 "specified in the ML param card.") 2199 options['nPS'] = new_n_PS 2200 2201 MadLoopInitializer.init_MadLoop(self.me_dir,n_PS=options['nPS'], 2202 subproc_prefix='PV', MG_options=self.options, interface=self)
2203
2204 - def do_launch(self, line, *args, **opt):
2205 """Main Commands: exec generate_events for 2>N and calculate_width for 1>N""" 2206 2207 if self.ninitial == 1: 2208 logger.info("Note that since 2.3. The launch for 1>N pass in event generation\n"+ 2209 " To have the previous behavior use the calculate_decay_widths function") 2210 # self.do_calculate_decay_widths(line, *args, **opt) 2211 #else: 2212 self.do_generate_events(line, *args, **opt)
2213
2214 - def print_results_in_shell(self, data):
2215 """Have a nice results prints in the shell, 2216 data should be of type: gen_crossxhtml.OneTagResults""" 2217 2218 if not data: 2219 return 2220 2221 if data['run_statistics']: 2222 globalstat = sum_html.RunStatistics() 2223 2224 logger.info(" " ) 2225 logger.debug(" === Run statistics summary ===") 2226 for key, value in data['run_statistics'].items(): 2227 globalstat.aggregate_statistics(value) 2228 level = 5 2229 if value.has_warning(): 2230 level = 10 2231 logger.log(level, value.nice_output(str('/'.join([key[0],'G%s'%key[1]]))).\ 2232 replace(' statistics','')) 2233 logger.info(" " ) 2234 logger.debug(globalstat.nice_output('combined', no_warning=True)) 2235 if globalstat.has_warning(): 2236 logger.warning(globalstat.get_warning_text()) 2237 logger.info(" ") 2238 2239 2240 logger.info(" === Results Summary for run: %s tag: %s ===\n" % (data['run_name'],data['tag'])) 2241 2242 total_time = int(sum(_['cumulative_timing'] for _ in data['run_statistics'].values())) 2243 if total_time > 0: 2244 logger.info(" Cumulative sequential time for this run: %s"%misc.format_time(total_time)) 2245 2246 if self.ninitial == 1: 2247 logger.info(" Width : %.4g +- %.4g GeV" % (data['cross'], data['error'])) 2248 else: 2249 logger.info(" Cross-section : %.4g +- %.4g pb" % (data['cross'], data['error'])) 2250 logger.info(" Nb of events : %s" % data['nb_event'] ) 2251 2252 if data['run_mode']=='madevent': 2253 if data['cross_pythia'] and data['nb_event_pythia']: 2254 if data['cross_pythia'] == -1: 2255 path = pjoin(self.me_dir, 'Events', self.run_name, '%s_merged_xsecs.txt' % self.run_tag) 2256 cross_sections = {} 2257 if os.path.exists(path): 2258 for line in open(path): 2259 split = line.split() 2260 if len(split)!=3: 2261 continue 2262 scale, cross, error = split 2263 cross_sections[float(scale)] = (float(cross), float(error)) 2264 if len(cross_sections)>0: 2265 logger.info(' Pythia8 merged cross-sections are:') 2266 for scale in sorted(cross_sections.keys()): 2267 logger.info(' > Merging scale = %-6.4g : %-11.5g +/- %-7.2g [pb]'%\ 2268 (scale,cross_sections[scale][0],cross_sections[scale][1])) 2269 2270 else: 2271 if self.ninitial == 1: 2272 logger.info(" Matched width : %.4g +- %.4g GeV" % (data['cross_pythia'], data['error_pythia'])) 2273 else: 2274 logger.info(" Matched cross-section : %.4g +- %.4g pb" % (data['cross_pythia'], data['error_pythia'])) 2275 logger.info(" Nb of events after matching/merging : %d" % int(data['nb_event_pythia'])) 2276 if self.run_card['use_syst'] in self.true and \ 2277 (int(self.run_card['ickkw'])==1 or self.run_card['ktdurham']>0.0 2278 or self.run_card['ptlund']>0.0): 2279 logger.info(" Notice that because Systematics computation is turned on, the merging did not veto events but modified their weights instead.\n"+\ 2280 " The resulting hepmc/stdhep file should therefore be use with those weights.") 2281 else: 2282 logger.info(" Nb of events after merging : %s" % data['nb_event_pythia']) 2283 2284 logger.info(" " )
2285
2286 - def print_results_in_file(self, data, path, mode='w', format='full'):
2287 """Have a nice results prints in the shell, 2288 data should be of type: gen_crossxhtml.OneTagResults""" 2289 if not data: 2290 return 2291 2292 fsock = open(path, mode) 2293 2294 if data['run_statistics']: 2295 logger.debug(" === Run statistics summary ===") 2296 for key, value in data['run_statistics'].items(): 2297 logger.debug(value.nice_output(str('/'.join([key[0],'G%s'%key[1]]))).\ 2298 replace(' statistics','')) 2299 logger.info(" " ) 2300 2301 if format == "full": 2302 fsock.write(" === Results Summary for run: %s tag: %s process: %s ===\n" % \ 2303 (data['run_name'],data['tag'], os.path.basename(self.me_dir))) 2304 2305 if self.ninitial == 1: 2306 fsock.write(" Width : %.4g +- %.4g GeV\n" % (data['cross'], data['error'])) 2307 else: 2308 fsock.write(" Cross-section : %.4g +- %.4g pb\n" % (data['cross'], data['error'])) 2309 fsock.write(" Nb of events : %s\n" % data['nb_event'] ) 2310 if data['cross_pythia'] and data['nb_event_pythia']: 2311 if self.ninitial == 1: 2312 fsock.write(" Matched Width : %.4g +- %.4g GeV\n" % (data['cross_pythia'], data['error_pythia'])) 2313 else: 2314 fsock.write(" Matched Cross-section : %.4g +- %.4g pb\n" % (data['cross_pythia'], data['error_pythia'])) 2315 fsock.write(" Nb of events after Matching : %s\n" % data['nb_event_pythia']) 2316 fsock.write(" \n" ) 2317 elif format == "short": 2318 if mode == "w": 2319 fsock.write("# run_name tag cross error Nb_event cross_after_matching nb_event_after matching\n") 2320 2321 if data['cross_pythia'] and data['nb_event_pythia']: 2322 text = "%(run_name)s %(tag)s %(cross)s %(error)s %(nb_event)s %(cross_pythia)s %(nb_event_pythia)s\n" 2323 else: 2324 text = "%(run_name)s %(tag)s %(cross)s %(error)s %(nb_event)s\n" 2325 fsock.write(text % data)
2326 2327 ############################################################################
2328 - def do_calculate_decay_widths(self, line):
2329 """Main Commands: launch decay width calculation and automatic inclusion of 2330 calculated widths and BRs in the param_card.""" 2331 2332 args = self.split_arg(line) 2333 # Check argument's validity 2334 accuracy = self.check_calculate_decay_widths(args) 2335 self.ask_run_configuration('parton') 2336 self.banner = None 2337 if not args: 2338 # No run name assigned -> assigned one automaticaly 2339 self.set_run_name(self.find_available_run_name(self.me_dir)) 2340 else: 2341 self.set_run_name(args[0], reload_card=True) 2342 args.pop(0) 2343 2344 self.configure_directory() 2345 2346 # Running gridpack warmup 2347 opts=[('accuracy', accuracy), # default 0.01 2348 ('points', 1000), 2349 ('iterations',9)] 2350 2351 logger.info('Calculating decay widths with run name %s' % self.run_name) 2352 2353 self.exec_cmd('survey %s %s' % \ 2354 (self.run_name, 2355 " ".join(['--' + opt + '=' + str(val) for (opt,val) \ 2356 in opts])), 2357 postcmd=False) 2358 self.refine_mode = "old" # specify how to combine event 2359 self.exec_cmd('combine_events', postcmd=False) 2360 self.exec_cmd('store_events', postcmd=False) 2361 2362 self.collect_decay_widths() 2363 self.print_results_in_shell(self.results.current) 2364 self.update_status('calculate_decay_widths done', 2365 level='parton', makehtml=False)
2366 2367 2368 ############################################################################
2369 - def collect_decay_widths(self):
2370 """ Collect the decay widths and calculate BRs for all particles, and put 2371 in param_card form. 2372 """ 2373 2374 particle_dict = {} # store the results 2375 run_name = self.run_name 2376 2377 # Looping over the Subprocesses 2378 for P_path in SubProcesses.get_subP(self.me_dir): 2379 ids = SubProcesses.get_subP_ids(P_path) 2380 # due to grouping we need to compute the ratio factor for the 2381 # ungroup resutls (that we need here). Note that initial particles 2382 # grouping are not at the same stage as final particle grouping 2383 nb_output = len(ids) / (len(set([p[0] for p in ids]))) 2384 results = open(pjoin(P_path, run_name + '_results.dat')).read().split('\n')[0] 2385 result = float(results.strip().split(' ')[0]) 2386 for particles in ids: 2387 try: 2388 particle_dict[particles[0]].append([particles[1:], result/nb_output]) 2389 except KeyError: 2390 particle_dict[particles[0]] = [[particles[1:], result/nb_output]] 2391 2392 self.update_width_in_param_card(particle_dict, 2393 initial = pjoin(self.me_dir, 'Cards', 'param_card.dat'), 2394 output=pjoin(self.me_dir, 'Events', run_name, "param_card.dat"))
2395 2396 @staticmethod
2397 - def update_width_in_param_card(decay_info, initial=None, output=None):
2398 # Open the param_card.dat and insert the calculated decays and BRs 2399 2400 if not output: 2401 output = initial 2402 2403 param_card_file = open(initial) 2404 param_card = param_card_file.read().split('\n') 2405 param_card_file.close() 2406 2407 decay_lines = [] 2408 line_number = 0 2409 # Read and remove all decays from the param_card 2410 while line_number < len(param_card): 2411 line = param_card[line_number] 2412 if line.lower().startswith('decay'): 2413 # Read decay if particle in decay_info 2414 # DECAY 6 1.455100e+00 2415 line = param_card.pop(line_number) 2416 line = line.split() 2417 particle = 0 2418 if int(line[1]) not in decay_info: 2419 try: # If formatting is wrong, don't want this particle 2420 particle = int(line[1]) 2421 width = float(line[2]) 2422 except Exception: 2423 particle = 0 2424 # Read BRs for this decay 2425 line = param_card[line_number] 2426 while line.startswith('#') or line.startswith(' '): 2427 line = param_card.pop(line_number) 2428 if not particle or line.startswith('#'): 2429 line=param_card[line_number] 2430 continue 2431 # 6.668201e-01 3 5 2 -1 2432 line = line.split() 2433 try: # Remove BR if formatting is wrong 2434 partial_width = float(line[0])*width 2435 decay_products = [int(p) for p in line[2:2+int(line[1])]] 2436 except Exception: 2437 line=param_card[line_number] 2438 continue 2439 try: 2440 decay_info[particle].append([decay_products, partial_width]) 2441 except KeyError: 2442 decay_info[particle] = [[decay_products, partial_width]] 2443 if line_number == len(param_card): 2444 break 2445 line=param_card[line_number] 2446 if particle and particle not in decay_info: 2447 # No decays given, only total width 2448 decay_info[particle] = [[[], width]] 2449 else: # Not decay 2450 line_number += 1 2451 # Clean out possible remaining comments at the end of the card 2452 while not param_card[-1] or param_card[-1].startswith('#'): 2453 param_card.pop(-1) 2454 2455 # Append calculated and read decays to the param_card 2456 param_card.append("#\n#*************************") 2457 param_card.append("# Decay widths *") 2458 param_card.append("#*************************") 2459 for key in sorted(decay_info.keys()): 2460 width = sum([r for p,r in decay_info[key]]) 2461 param_card.append("#\n# PDG Width") 2462 param_card.append("DECAY %i %e" % (key, width.real)) 2463 if not width: 2464 continue 2465 if decay_info[key][0][0]: 2466 param_card.append("# BR NDA ID1 ID2 ...") 2467 brs = [[(val[1]/width).real, val[0]] for val in decay_info[key] if val[1]] 2468 for val in sorted(brs, reverse=True): 2469 param_card.append(" %e %i %s # %s" % 2470 (val[0].real, len(val[1]), 2471 " ".join([str(v) for v in val[1]]), 2472 val[0] * width 2473 )) 2474 decay_table = open(output, 'w') 2475 decay_table.write("\n".join(param_card) + "\n") 2476 decay_table.close() 2477 logger.info("Results written to %s" % output)
2478 2479 2480 ############################################################################
2481 - def do_multi_run(self, line):
2482 2483 args = self.split_arg(line) 2484 # Check argument's validity 2485 mode = self.check_multi_run(args) 2486 nb_run = args.pop(0) 2487 if nb_run == 1: 2488 logger.warn("'multi_run 1' command is not optimal. Think of using generate_events instead") 2489 self.ask_run_configuration(mode) 2490 2491 self.check_survey(args, cmd='multi_run') 2492 main_name = self.run_name 2493 # check if the param_card requires a scan over parameter. 2494 path=pjoin(self.me_dir, 'Cards', 'param_card.dat') 2495 self.check_param_card(path, run=False) 2496 #store it locally to avoid relaunch 2497 param_card_iterator, self.param_card_iterator = self.param_card_iterator, [] 2498 2499 crossoversig = 0 2500 inv_sq_err = 0 2501 nb_event = 0 2502 for i in range(nb_run): 2503 self.nb_refine = 0 2504 self.exec_cmd('generate_events %s_%s -f' % (main_name, i), postcmd=False) 2505 # Update collected value 2506 nb_event += int(self.results[self.run_name][-1]['nb_event']) 2507 self.results.add_detail('nb_event', nb_event , run=main_name) 2508 cross = self.results[self.run_name][-1]['cross'] 2509 error = self.results[self.run_name][-1]['error'] + 1e-99 2510 crossoversig+=cross/error**2 2511 inv_sq_err+=1.0/error**2 2512 self.results[main_name][-1]['cross'] = crossoversig/inv_sq_err 2513 self.results[main_name][-1]['error'] = math.sqrt(1.0/inv_sq_err) 2514 self.results.def_current(main_name) 2515 self.run_name = main_name 2516 self.update_status("Merging LHE files", level='parton') 2517 try: 2518 os.mkdir(pjoin(self.me_dir,'Events', self.run_name)) 2519 except Exception: 2520 pass 2521 os.system('%(bin)s/merge.pl %(event)s/%(name)s_*/unweighted_events.lhe.gz %(event)s/%(name)s/unweighted_events.lhe.gz %(event)s/%(name)s_banner.txt' 2522 % {'bin': self.dirbin, 'event': pjoin(self.me_dir,'Events'), 2523 'name': self.run_name}) 2524 2525 eradir = self.options['exrootanalysis_path'] 2526 if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter')): 2527 self.update_status("Create Root file", level='parton') 2528 misc.gunzip('%s/%s/unweighted_events.lhe.gz' % 2529 (pjoin(self.me_dir,'Events'), self.run_name)) 2530 2531 self.create_root_file('%s/unweighted_events.lhe' % self.run_name, 2532 '%s/unweighted_events.root' % self.run_name) 2533 2534 path = pjoin(self.me_dir, "Events", self.run_name, "unweighted_events.lhe") 2535 self.create_plot('parton', path, 2536 pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html') 2537 ) 2538 2539 2540 if not os.path.exists('%s.gz' % path): 2541 misc.gzip(path) 2542 2543 self.update_status('', level='parton') 2544 self.print_results_in_shell(self.results.current) 2545 2546 if param_card_iterator: 2547 2548 param_card_iterator.store_entry(self.run_name, self.results.current['cross']) 2549 #check if the param_card defines a scan. 2550 orig_name=self.run_name 2551 for card in param_card_iterator: 2552 card.write(pjoin(self.me_dir,'Cards','param_card.dat')) 2553 self.exec_cmd("multi_run %s -f " % nb_run ,precmd=True, postcmd=True,errorhandling=False) 2554 param_card_iterator.store_entry(self.run_name, self.results.current['cross']) 2555 param_card_iterator.write(pjoin(self.me_dir,'Cards','param_card.dat')) 2556 scan_name = misc.get_scan_name(orig_name, self.run_name) 2557 path = pjoin(self.me_dir, 'Events','scan_%s.txt' % scan_name) 2558 logger.info("write all cross-section results in %s" % path, '$MG:color:BLACK') 2559 param_card_iterator.write_summary(path)
2560 2561 2562 ############################################################################
2563 - def do_treatcards(self, line, mode=None, opt=None):
2564 """Advanced commands: create .inc files from param_card.dat/run_card.dat""" 2565 2566 if not mode and not opt: 2567 args = self.split_arg(line) 2568 mode, opt = self.check_treatcards(args) 2569 2570 # To decide whether to refresh MadLoop's helicity filters, it is necessary 2571 # to check if the model parameters where modified or not, before doing 2572 # anything else. 2573 need_MadLoopFilterUpdate = False 2574 # Just to record what triggered the reinitialization of MadLoop for a 2575 # nice debug message. 2576 type_of_change = '' 2577 if not opt['forbid_MadLoopInit'] and self.proc_characteristics['loop_induced'] \ 2578 and mode in ['loop', 'all']: 2579 paramDat = pjoin(self.me_dir, 'Cards','param_card.dat') 2580 paramInc = pjoin(opt['output_dir'], 'param_card.inc') 2581 if (not os.path.isfile(paramDat)) or (not os.path.isfile(paramInc)) or \ 2582 (os.path.getmtime(paramDat)-os.path.getmtime(paramInc)) > 0.0: 2583 need_MadLoopFilterUpdate = True 2584 type_of_change = 'model' 2585 2586 ML_in = pjoin(self.me_dir, 'Cards', 'MadLoopParams.dat') 2587 ML_out = pjoin(self.me_dir,"SubProcesses", 2588 "MadLoop5_resources", "MadLoopParams.dat") 2589 if (not os.path.isfile(ML_in)) or (not os.path.isfile(ML_out)) or \ 2590 (os.path.getmtime(ML_in)-os.path.getmtime(ML_out)) > 0.0: 2591 need_MadLoopFilterUpdate = True 2592 type_of_change = 'MadLoop' 2593 2594 #check if no 'Auto' are present in the file 2595 self.check_param_card(pjoin(self.me_dir, 'Cards','param_card.dat')) 2596 2597 if mode in ['param', 'all']: 2598 model = self.find_model_name() 2599 tmp_model = os.path.basename(model) 2600 if tmp_model == 'mssm' or tmp_model.startswith('mssm-'): 2601 if not '--param_card=' in line: 2602 param_card = pjoin(self.me_dir, 'Cards','param_card.dat') 2603 mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat') 2604 check_param_card.convert_to_mg5card(param_card, mg5_param) 2605 check_param_card.check_valid_param_card(mg5_param) 2606 opt['param_card'] = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat') 2607 else: 2608 check_param_card.check_valid_param_card(opt['param_card']) 2609 2610 logger.debug('write compile file for card: %s' % opt['param_card']) 2611 param_card = check_param_card.ParamCard(opt['param_card']) 2612 outfile = pjoin(opt['output_dir'], 'param_card.inc') 2613 ident_card = pjoin(self.me_dir,'Cards','ident_card.dat') 2614 if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')): 2615 default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat') 2616 elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')): 2617 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat') 2618 elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')): 2619 fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w') 2620 fsock.write(' ') 2621 fsock.close() 2622 if mode == 'all': 2623 self.do_treatcards('', 'run', opt) 2624 return 2625 else: 2626 devnull = open(os.devnull,'w') 2627 subprocess.call([sys.executable, 'write_param_card.py'], 2628 cwd=pjoin(self.me_dir,'bin','internal','ufomodel'), 2629 stdout=devnull) 2630 devnull.close() 2631 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat') 2632 2633 need_mp = self.proc_characteristics['loop_induced'] 2634 param_card.write_inc_file(outfile, ident_card, default, need_mp=need_mp) 2635 2636 2637 if mode in ['run', 'all']: 2638 if not hasattr(self, 'run_card'): 2639 run_card = banner_mod.RunCard(opt['run_card']) 2640 else: 2641 run_card = self.run_card 2642 if self.ninitial == 1: 2643 run_card['lpp1'] = 0 2644 run_card['lpp2'] = 0 2645 run_card['ebeam1'] = 0 2646 run_card['ebeam2'] = 0 2647 2648 # Ensure that the bias parameters has all the required input from the 2649 # run_card 2650 if run_card['bias_module'].lower() not in ['dummy','none']: 2651 # Using basename here means that the module will not be overwritten if already existing. 2652 bias_module_path = pjoin(self.me_dir,'Source','BIAS', 2653 os.path.basename(run_card['bias_module'])) 2654 if not os.path.isdir(bias_module_path): 2655 if not os.path.isdir(run_card['bias_module']): 2656 raise InvalidCmd("The bias module at '%s' cannot be found."%run_card['bias_module']) 2657 else: 2658 for mandatory_file in ['makefile','%s.f'%os.path.basename(run_card['bias_module'])]: 2659 if not os.path.isfile(pjoin(run_card['bias_module'],mandatory_file)): 2660 raise InvalidCmd("Could not find the mandatory file '%s' in bias module '%s'."%( 2661 mandatory_file,run_card['bias_module'])) 2662 shutil.copytree(run_card['bias_module'], pjoin(self.me_dir,'Source','BIAS', 2663 os.path.basename(run_card['bias_module']))) 2664 2665 #check expected parameters for the module. 2666 default_bias_parameters = {} 2667 start, last = False,False 2668 for line in open(pjoin(bias_module_path,'%s.f'%os.path.basename(bias_module_path))): 2669 if start and last: 2670 break 2671 if not start and not re.search('c\s*parameters\s*=\s*{',line, re.I): 2672 continue 2673 start = True 2674 if not line.startswith('C'): 2675 continue 2676 line = line[1:] 2677 if '{' in line: 2678 line = line.split('{')[-1] 2679 # split for } ! # 2680 split_result = re.split('(\}|!|\#)', line,1, re.M) 2681 line = split_result[0] 2682 sep = split_result[1] if len(split_result)>1 else None 2683 if sep == '}': 2684 last = True 2685 if ',' in line: 2686 for pair in line.split(','): 2687 if not pair.strip(): 2688 continue 2689 x,y =pair.split(':') 2690 x=x.strip() 2691 if x.startswith(('"',"'")) and x.endswith(x[0]): 2692 x = x[1:-1] 2693 default_bias_parameters[x] = y 2694 elif ':' in line: 2695 x,y = line.split(':') 2696 x = x.strip() 2697 if x.startswith(('"',"'")) and x.endswith(x[0]): 2698 x = x[1:-1] 2699 default_bias_parameters[x] = y 2700 for key,value in run_card['bias_parameters'].items(): 2701 if key not in default_bias_parameters: 2702 logger.warning('%s not supported by the bias module. We discard this entry.', key) 2703 else: 2704 default_bias_parameters[key] = value 2705 run_card['bias_parameters'] = default_bias_parameters 2706 2707 2708 # Finally write the include file 2709 run_card.write_include_file(opt['output_dir']) 2710 2711 2712 if self.proc_characteristics['loop_induced'] and mode in ['loop', 'all']: 2713 self.MadLoopparam = banner_mod.MadLoopParam(pjoin(self.me_dir, 2714 'Cards', 'MadLoopParams.dat')) 2715 # The writing out of MadLoop filter is potentially dangerous 2716 # when running in multi-core with a central disk. So it is turned 2717 # off here. If these filters were not initialized then they will 2718 # have to be re-computed at the beginning of each run. 2719 if 'WriteOutFilters' in self.MadLoopparam.user_set and \ 2720 self.MadLoopparam.get('WriteOutFilters'): 2721 logger.info( 2722 """You chose to have MadLoop writing out filters. 2723 Beware that this can be dangerous for local multicore runs.""") 2724 self.MadLoopparam.set('WriteOutFilters',False, changeifuserset=False) 2725 2726 # The conservative settings below for 'CTModeInit' and 'ZeroThres' 2727 # help adress issues for processes like g g > h z, and g g > h g 2728 # where there are some helicity configuration heavily suppressed 2729 # (by several orders of magnitude) so that the helicity filter 2730 # needs high numerical accuracy to correctly handle this spread in 2731 # magnitude. Also, because one cannot use the Born as a reference 2732 # scale, it is better to force quadruple precision *for the 2733 # initialization points only*. This avoids numerical accuracy issues 2734 # when setting up the helicity filters and does not significantly 2735 # slow down the run. 2736 # self.MadLoopparam.set('CTModeInit',4, changeifuserset=False) 2737 # Consequently, we can allow for a finer threshold for vanishing 2738 # helicity configuration 2739 # self.MadLoopparam.set('ZeroThres',1.0e-11, changeifuserset=False) 2740 2741 # It is a bit superficial to use the level 2 which tries to numerically 2742 # map matching helicities (because of CP symmetry typically) together. 2743 # It is useless in the context of MC over helicities and it can 2744 # potentially make the helicity double checking fail. 2745 self.MadLoopparam.set('HelicityFilterLevel',1, changeifuserset=False) 2746 2747 # To be on the safe side however, we ask for 4 consecutive matching 2748 # helicity filters. 2749 self.MadLoopparam.set('CheckCycle',4, changeifuserset=False) 2750 2751 # For now it is tricky to have each channel performing the helicity 2752 # double check. What we will end up doing is probably some kind 2753 # of new initialization round at the beginning of each launch 2754 # command, to reset the filters. 2755 self.MadLoopparam.set('DoubleCheckHelicityFilter',False, 2756 changeifuserset=False) 2757 2758 # Thanks to TIR recycling, TIR is typically much faster for Loop-induced 2759 # processes when not doing MC over helicities, so that we place OPP last. 2760 if not hasattr(self, 'run_card'): 2761 run_card = banner_mod.RunCard(opt['run_card']) 2762 else: 2763 run_card = self.run_card 2764 if run_card['nhel'] == 0: 2765 if 'MLReductionLib' in self.MadLoopparam.user_set and \ 2766 (self.MadLoopparam.get('MLReductionLib').startswith('1') or 2767 self.MadLoopparam.get('MLReductionLib').startswith('6')): 2768 logger.warning( 2769 """You chose to set the preferred reduction technique in MadLoop to be OPP (see parameter MLReductionLib). 2770 Beware that this can bring significant slowdown; the optimal choice --when not MC over helicity-- being to first start with TIR reduction.""") 2771 # We do not include GOLEM for now since it cannot recycle TIR coefs yet. 2772 self.MadLoopparam.set('MLReductionLib','7|6|1', changeifuserset=False) 2773 else: 2774 if 'MLReductionLib' in self.MadLoopparam.user_set and \ 2775 not (self.MadLoopparam.get('MLReductionLib').startswith('1') or 2776 self.MadLoopparam.get('MLReductionLib').startswith('6')): 2777 logger.warning( 2778 """You chose to set the preferred reduction technique in MadLoop to be different than OPP (see parameter MLReductionLib). 2779 Beware that this can bring significant slowdown; the optimal choice --when MC over helicity-- being to first start with OPP reduction.""") 2780 self.MadLoopparam.set('MLReductionLib','6|7|1', changeifuserset=False) 2781 2782 # Also TIR cache will only work when NRotations_DP=0 (but only matters 2783 # when not MC-ing over helicities) so it will be hard-reset by MadLoop 2784 # to zero when not MC-ing over helicities, unless the parameter 2785 # Force_ML_Helicity_Sum is set to True in the matrix<i>.f codes. 2786 if run_card['nhel'] == 0: 2787 if ('NRotations_DP' in self.MadLoopparam.user_set and \ 2788 self.MadLoopparam.get('NRotations_DP')!=0) or \ 2789 ('NRotations_QP' in self.MadLoopparam.user_set and \ 2790 self.MadLoopparam.get('NRotations_QP')!=0): 2791 logger.warning( 2792 """You chose to also use a lorentz rotation for stability tests (see parameter NRotations_[DP|QP]). 2793 Beware that, for optimization purposes, MadEvent uses manual TIR cache clearing which is not compatible 2794 with the lorentz rotation stability test. The number of these rotations to be used will be reset to 2795 zero by MadLoop. You can avoid this by changing the parameter 'FORCE_ML_HELICITY_SUM' int he matrix<i>.f 2796 files to be .TRUE. so that the sum over helicity configurations is performed within MadLoop (in which case 2797 the helicity of final state particles cannot be speicfied in the LHE file.""") 2798 self.MadLoopparam.set('NRotations_DP',0,changeifuserset=False) 2799 self.MadLoopparam.set('NRotations_QP',0,changeifuserset=False) 2800 else: 2801 # When MC-ing over helicities, the manual TIR cache clearing is 2802 # not necessary, so that one can use the lorentz check 2803 # Using NRotations_DP=1 slows down the code by close to 100% 2804 # but it is typicaly safer. 2805 # self.MadLoopparam.set('NRotations_DP',0,changeifuserset=False) 2806 # Revert to the above to be slightly less robust but twice faster. 2807 self.MadLoopparam.set('NRotations_DP',1,changeifuserset=False) 2808 self.MadLoopparam.set('NRotations_QP',0,changeifuserset=False) 2809 2810 # Finally, the stability tests are slightly less reliable for process 2811 # with less or equal than 4 final state particles because the 2812 # accessible kinematic is very limited (i.e. lorentz rotations don't 2813 # shuffle invariants numerics much). In these cases, we therefore 2814 # increase the required accuracy to 10^-7. 2815 # This is important for getting g g > z z [QCD] working with a 2816 # ptheavy cut as low as 1 GeV. 2817 if self.proc_characteristics['nexternal']<=4: 2818 if ('MLStabThres' in self.MadLoopparam.user_set and \ 2819 self.MadLoopparam.get('MLStabThres')>1.0e-7): 2820 logger.warning( 2821 """You chose to increase the default value of the MadLoop parameter 'MLStabThres' above 1.0e-7. 2822 Stability tests can be less reliable on the limited kinematic of processes with less or equal 2823 than four external legs, so this is not recommended (especially not for g g > z z).""") 2824 self.MadLoopparam.set('MLStabThres',1.0e-7,changeifuserset=False) 2825 else: 2826 self.MadLoopparam.set('MLStabThres',1.0e-4,changeifuserset=False) 2827 2828 #write the output file 2829 self.MadLoopparam.write(pjoin(self.me_dir,"SubProcesses","MadLoop5_resources", 2830 "MadLoopParams.dat")) 2831 2832 if self.proc_characteristics['loop_induced'] and mode in ['loop', 'all']: 2833 # Now Update MadLoop filters if necessary (if modifications were made to 2834 # the model parameters). 2835 if need_MadLoopFilterUpdate: 2836 logger.debug('Changes to the %s parameters'%type_of_change+\ 2837 ' have been detected. Madevent will then now reinitialize'+\ 2838 ' MadLoop filters.') 2839 self.exec_cmd('initMadLoop -r -f') 2840 # The need_MadLoopInit condition is just there so as to avoid useless 2841 # printout if there is not initialization to be performed. But even 2842 # without it, and because we call 'initMadLoop' without the '-r' option 2843 # no time would be wasted anyway, since the existing filters would not 2844 # be overwritten. 2845 elif not opt['forbid_MadLoopInit'] and \ 2846 MadLoopInitializer.need_MadLoopInit(self.me_dir): 2847 self.exec_cmd('initMadLoop -f')
2848 2849 ############################################################################
2850 - def do_survey(self, line):
2851 """Advanced commands: launch survey for the current process """ 2852 2853 2854 args = self.split_arg(line) 2855 # Check argument's validity 2856 self.check_survey(args) 2857 # initialize / remove lhapdf mode 2858 2859 if os.path.exists(pjoin(self.me_dir,'error')): 2860 os.remove(pjoin(self.me_dir,'error')) 2861 2862 self.configure_directory() 2863 # Save original random number 2864 self.random_orig = self.random 2865 logger.info("Using random number seed offset = %s" % self.random) 2866 # Update random number 2867 self.update_random() 2868 self.save_random() 2869 self.update_status('Running Survey', level=None) 2870 if self.cluster_mode: 2871 logger.info('Creating Jobs') 2872 2873 self.total_jobs = 0 2874 subproc = [l.strip() for l in open(pjoin(self.me_dir, 2875 'SubProcesses', 'subproc.mg'))] 2876 2877 P_zero_result = [] # check the number of times where they are no phase-space 2878 2879 # File for the loop (for loop induced) 2880 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 2881 'MadLoop5_resources')) and cluster.need_transfer(self.options): 2882 tf=tarfile.open(pjoin(self.me_dir, 'SubProcesses', 2883 'MadLoop5_resources.tar.gz'), 'w:gz', dereference=True) 2884 tf.add(pjoin(self.me_dir,'SubProcesses','MadLoop5_resources'), 2885 arcname='MadLoop5_resources') 2886 tf.close() 2887 2888 logger.info('Working on SubProcesses') 2889 ajobcreator = gen_ximprove.gensym(self) 2890 2891 #check difficult PS case 2892 if float(self.run_card['mmjj']) > 0.01 * (float(self.run_card['ebeam1'])+float(self.run_card['ebeam2'])): 2893 self.pass_in_difficult_integration_mode() 2894 2895 jobs, P_zero_result = ajobcreator.launch() 2896 2897 # Check if all or only some fails 2898 if P_zero_result: 2899 if len(P_zero_result) == len(subproc): 2900 Pdir = pjoin(self.me_dir, 'SubProcesses',subproc[0].strip()) 2901 raise ZeroResult, '%s' % \ 2902 open(pjoin(Pdir,'ajob.no_ps.log')).read() 2903 else: 2904 logger.warning(''' %s SubProcesses doesn\'t have available phase-space. 2905 Please check mass spectrum.''' % ','.join(P_zero_result)) 2906 2907 2908 self.monitor(run_type='All jobs submitted for survey', html=True) 2909 if not self.history or 'survey' in self.history[-1] or self.ninitial ==1 or \ 2910 self.run_card['gridpack']: 2911 #will be done during the refine (more precisely in gen_ximprove) 2912 cross, error = sum_html.make_all_html_results(self) 2913 self.results.add_detail('cross', cross) 2914 self.results.add_detail('error', error) 2915 self.exec_cmd("print_results %s" % self.run_name, 2916 errorhandling=False, printcmd=False, precmd=False, postcmd=False) 2917 2918 self.results.add_detail('run_statistics', dict(ajobcreator.run_statistics)) 2919 self.update_status('End survey', 'parton', makehtml=False)
2920 2921 ############################################################################
2922 - def pass_in_difficult_integration_mode(self):
2923 """be more secure for the integration to not miss it due to strong cut""" 2924 2925 # improve survey options if default 2926 if self.opts['points'] == self._survey_options['points'][1]: 2927 self.opts['points'] = 2 * self._survey_options['points'][1] 2928 if self.opts['iterations'] == self._survey_options['iterations'][1]: 2929 self.opts['iterations'] = 1 + self._survey_options['iterations'][1] 2930 if self.opts['accuracy'] == self._survey_options['accuracy'][1]: 2931 self.opts['accuracy'] = self._survey_options['accuracy'][1]/2 2932 2933 # Modify run_config.inc in order to improve the refine 2934 #conf_path = pjoin(self.me_dir, 'Source','run_config.inc') 2935 #files.cp(conf_path, conf_path + '.bk') 2936 # 2937 #text = open(conf_path).read() 2938 #text = re.sub('''\(min_events = \d+\)''', '''(min_events = 7500 )''', text) 2939 #text = re.sub('''\(max_events = \d+\)''', '''(max_events = 20000 )''', text) 2940 #fsock = open(conf_path, 'w') 2941 #fsock.write(text) 2942 #fsock.close() 2943 2944 # Compile 2945 for name in ['../bin/internal/gen_ximprove', 'all', 2946 '../bin/internal/combine_events']: 2947 self.compile(arg=[name], cwd=os.path.join(self.me_dir, 'Source'))
2948 2949 2950 ############################################################################
2951 - def do_refine(self, line):
2952 """Advanced commands: launch survey for the current process """ 2953 devnull = open(os.devnull, 'w') 2954 self.nb_refine += 1 2955 args = self.split_arg(line) 2956 # Check argument's validity 2957 self.check_refine(args) 2958 2959 refine_opt = {'err_goal': args[0], 'split_channels': True} 2960 precision = args[0] 2961 if len(args) == 2: 2962 refine_opt['max_process']= args[1] 2963 2964 2965 # initialize / remove lhapdf mode 2966 self.configure_directory() 2967 2968 # Update random number 2969 self.update_random() 2970 self.save_random() 2971 2972 if self.cluster_mode: 2973 logger.info('Creating Jobs') 2974 self.update_status('Refine results to %s' % precision, level=None) 2975 2976 self.total_jobs = 0 2977 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 2978 'subproc.mg'))] 2979 2980 # cleanning the previous job 2981 for nb_proc,subdir in enumerate(subproc): 2982 subdir = subdir.strip() 2983 Pdir = pjoin(self.me_dir, 'SubProcesses', subdir) 2984 for match in misc.glob('*ajob*', Pdir): 2985 if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']: 2986 os.remove(match) 2987 2988 x_improve = gen_ximprove.gen_ximprove(self, refine_opt) 2989 # Load the run statistics from the survey 2990 survey_statistics = dict(self.results.get_detail('run_statistics')) 2991 # Printout survey statistics 2992 if __debug__ and survey_statistics: 2993 globalstat = sum_html.RunStatistics() 2994 logger.debug(" === Survey statistics summary ===") 2995 for key, value in survey_statistics.items(): 2996 globalstat.aggregate_statistics(value) 2997 level = 5 2998 if value.has_warning(): 2999 level = 10 3000 logger.log(level, 3001 value.nice_output(str('/'.join([key[0],'G%s'%key[1]]))). 3002 replace(' statistics','')) 3003 logger.debug(globalstat.nice_output('combined', no_warning=True)) 3004 3005 if survey_statistics: 3006 x_improve.run_statistics = survey_statistics 3007 3008 x_improve.launch() # create the ajob for the refinment. 3009 if not self.history or 'refine' not in self.history[-1]: 3010 cross, error = x_improve.update_html() #update html results for survey 3011 if cross == 0: 3012 return 3013 logger.info("Current estimate of cross-section: %s +- %s" % (cross, error)) 3014 3015 if isinstance(x_improve, gen_ximprove.gen_ximprove_v4): 3016 # Non splitted mode is based on writting ajob so need to track them 3017 # Splitted mode handle the cluster submition internally. 3018 for nb_proc,subdir in enumerate(subproc): 3019 subdir = subdir.strip() 3020 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir) 3021 bindir = pjoin(os.path.relpath(self.dirbin, Pdir)) 3022 3023 logger.info(' %s ' % subdir) 3024 3025 if os.path.exists(pjoin(Pdir, 'ajob1')): 3026 self.compile(['madevent'], cwd=Pdir) 3027 3028 alljobs = misc.glob('ajob*', Pdir) 3029 3030 #remove associated results.dat (ensure to not mix with all data) 3031 Gre = re.compile("\s*j=(G[\d\.\w]+)") 3032 for job in alljobs: 3033 Gdirs = Gre.findall(open(job).read()) 3034 for Gdir in Gdirs: 3035 if os.path.exists(pjoin(Pdir, Gdir, 'results.dat')): 3036 os.remove(pjoin(Pdir, Gdir,'results.dat')) 3037 3038 nb_tot = len(alljobs) 3039 self.total_jobs += nb_tot 3040 for i, job in enumerate(alljobs): 3041 job = os.path.basename(job) 3042 self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1), 3043 run_type='Refine number %s on %s (%s/%s)' % 3044 (self.nb_refine, subdir, nb_proc+1, len(subproc))) 3045 3046 self.monitor(run_type='All job submitted for refine number %s' % self.nb_refine, 3047 html=True) 3048 3049 self.update_status("Combining runs", level='parton') 3050 try: 3051 os.remove(pjoin(Pdir, 'combine_runs.log')) 3052 except Exception: 3053 pass 3054 3055 if isinstance(x_improve, gen_ximprove.gen_ximprove_v4): 3056 # the merge of the events.lhe is handle in the x_improve class 3057 # for splitted runs. (and partly in store_events). 3058 combine_runs.CombineRuns(self.me_dir) 3059 self.refine_mode = "old" 3060 else: 3061 self.refine_mode = "new" 3062 3063 cross, error = sum_html.make_all_html_results(self) 3064 self.results.add_detail('cross', cross) 3065 self.results.add_detail('error', error) 3066 3067 self.results.add_detail('run_statistics', 3068 dict(self.results.get_detail('run_statistics'))) 3069 3070 self.update_status('finish refine', 'parton', makehtml=False) 3071 devnull.close()
3072 3073 ############################################################################
3074 - def do_combine_iteration(self, line):
3075 """Not in help: Combine a given iteration combine_iteration Pdir Gdir S|R step 3076 S is for survey 3077 R is for refine 3078 step is the iteration number (not very critical)""" 3079 3080 self.set_run_name("tmp") 3081 self.configure_directory(html_opening=False) 3082 Pdir, Gdir, mode, step = self.split_arg(line) 3083 if Gdir.startswith("G"): 3084 Gdir = Gdir[1:] 3085 if "SubProcesses" not in Pdir: 3086 Pdir = pjoin(self.me_dir, "SubProcesses", Pdir) 3087 if mode == "S": 3088 self.opts = dict([(key,value[1]) for (key,value) in \ 3089 self._survey_options.items()]) 3090 gensym = gen_ximprove.gensym(self) 3091 gensym.combine_iteration(Pdir, Gdir, int(step)) 3092 elif mode == "R": 3093 refine = gen_ximprove.gen_ximprove_share(self) 3094 refine.combine_iteration(Pdir, Gdir, int(step))
3095 3096 3097 3098 3099 ############################################################################
3100 - def do_combine_events(self, line):
3101 """Advanced commands: Launch combine events""" 3102 3103 args = self.split_arg(line) 3104 # Check argument's validity 3105 self.check_combine_events(args) 3106 3107 self.update_status('Combining Events', level='parton') 3108 3109 3110 3111 if self.run_card['gridpack']: #not hasattr(self, "refine_mode") or self.refine_mode == "old": 3112 try: 3113 os.remove(pjoin(self.me_dir,'SubProcesses', 'combine.log')) 3114 except Exception: 3115 pass 3116 3117 cluster.onecore.launch_and_wait('../bin/internal/run_combine', 3118 args=[self.run_name], 3119 cwd=pjoin(self.me_dir,'SubProcesses'), 3120 stdout=pjoin(self.me_dir,'SubProcesses', 'combine.log'), 3121 required_output=[pjoin(self.me_dir,'SubProcesses', 'combine.log')]) 3122 3123 #self.cluster.launch_and_wait('../bin/internal/run_combine', 3124 # cwd=pjoin(self.me_dir,'SubProcesses'), 3125 # stdout=pjoin(self.me_dir,'SubProcesses', 'combine.log'), 3126 # required_output=[pjoin(self.me_dir,'SubProcesses', 'combine.log')]) 3127 3128 output = misc.mult_try_open(pjoin(self.me_dir,'SubProcesses','combine.log')).read() 3129 # Store the number of unweighted events for the results object 3130 pat = re.compile(r'''\s*Unweighting\s*selected\s*(\d+)\s*events''') 3131 try: 3132 nb_event = pat.search(output).groups()[0] 3133 except AttributeError: 3134 time.sleep(10) 3135 output = misc.mult_try_open(pjoin(self.me_dir,'SubProcesses','combine.log')).read() 3136 try: 3137 nb_event = pat.search(output).groups()[0] 3138 except AttributeError: 3139 logger.warning('Fail to read the number of unweighted events in the combine.log file') 3140 nb_event = 0 3141 3142 self.results.add_detail('nb_event', nb_event) 3143 3144 3145 # Define The Banner 3146 tag = self.run_card['run_tag'] 3147 3148 # Update the banner with the pythia card 3149 if not self.banner: 3150 self.banner = banner_mod.recover_banner(self.results, 'parton') 3151 self.banner.load_basic(self.me_dir) 3152 # Add cross-section/event information 3153 self.banner.add_generation_info(self.results.current['cross'], nb_event) 3154 if not hasattr(self, 'random_orig'): self.random_orig = 0 3155 self.banner.change_seed(self.random_orig) 3156 if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)): 3157 os.mkdir(pjoin(self.me_dir, 'Events', self.run_name)) 3158 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, 3159 '%s_%s_banner.txt' % (self.run_name, tag))) 3160 3161 3162 self.banner.add_to_file(pjoin(self.me_dir,'Events', 'events.lhe'), 3163 out=pjoin(self.me_dir,'Events', self.run_name, 'events.lhe')) 3164 self.banner.add_to_file(pjoin(self.me_dir,'Events', 'unweighted_events.lhe'), 3165 out=pjoin(self.me_dir,'Events', self.run_name, 'unweighted_events.lhe')) 3166 3167 else: 3168 # Define The Banner 3169 tag = self.run_card['run_tag'] 3170 # Update the banner with the pythia card 3171 if not self.banner: 3172 self.banner = banner_mod.recover_banner(self.results, 'parton') 3173 self.banner.load_basic(self.me_dir) 3174 # Add cross-section/event information 3175 self.banner.add_generation_info(self.results.current['cross'], self.run_card['nevents']) 3176 if not hasattr(self, 'random_orig'): self.random_orig = 0 3177 self.banner.change_seed(self.random_orig) 3178 if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)): 3179 os.mkdir(pjoin(self.me_dir, 'Events', self.run_name)) 3180 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, 3181 '%s_%s_banner.txt' % (self.run_name, tag))) 3182 3183 3184 get_wgt = lambda event: event.wgt 3185 AllEvent = lhe_parser.MultiEventFile() 3186 AllEvent.banner = self.banner 3187 3188 partials = 0 # if too many file make some partial unweighting 3189 sum_xsec, sum_xerru, sum_axsec = 0,[],0 3190 for Gdir,mfactor in self.get_Gdir(): 3191 if os.path.exists(pjoin(Gdir, 'events.lhe')): 3192 result = sum_html.OneResult('') 3193 result.read_results(pjoin(Gdir, 'results.dat')) 3194 AllEvent.add(pjoin(Gdir, 'events.lhe'), 3195 result.get('xsec'), 3196 result.get('xerru'), 3197 result.get('axsec') 3198 ) 3199 3200 sum_xsec += result.get('xsec') 3201 sum_xerru.append(result.get('xerru')) 3202 sum_axsec += result.get('axsec') 3203 3204 if len(AllEvent) >= 80: #perform a partial unweighting 3205 AllEvent.unweight(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe.gz" % partials), 3206 get_wgt, log_level=5, trunc_error=1e-2, event_target=self.run_card['nevents']) 3207 AllEvent = lhe_parser.MultiEventFile() 3208 AllEvent.banner = self.banner 3209 AllEvent.add(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe.gz" % partials), 3210 sum_xsec, 3211 math.sqrt(sum(x**2 for x in sum_xerru)), 3212 sum_axsec) 3213 partials +=1 3214 3215 nb_event = AllEvent.unweight(pjoin(self.me_dir, "Events", self.run_name, "unweighted_events.lhe.gz"), 3216 get_wgt, trunc_error=1e-2, event_target=self.run_card['nevents'], 3217 log_level=logging.DEBUG, normalization=self.run_card['event_norm']) 3218 3219 if partials: 3220 misc.sprint("used partials") 3221 for i in range(partials): 3222 try: 3223 os.remove(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe.gz" % i)) 3224 except Exception: 3225 os.remove(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe" % i)) 3226 3227 self.results.add_detail('nb_event', nb_event) 3228 3229 if self.run_card['bias_module'].lower() not in ['dummy', 'none']: 3230 self.correct_bias() 3231 3232 3233 3234 self.to_store.append('event') 3235 eradir = self.options['exrootanalysis_path'] 3236 madir = self.options['madanalysis_path'] 3237 td = self.options['td_path'] 3238 if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter')) and\ 3239 os.path.exists(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')): 3240 if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)): 3241 os.mkdir(pjoin(self.me_dir, 'Events', self.run_name)) 3242 self.create_root_file(output='%s/unweighted_events.root' % \ 3243 self.run_name)
3244 3245 ############################################################################
3246 - def correct_bias(self):
3247 """check the first event and correct the weight by the bias 3248 and correct the cross-section. 3249 If the event do not have the bias tag it means that the bias is 3250 one modifying the cross-section/shape so we have nothing to do 3251 """ 3252 3253 lhe = lhe_parser.EventFile(pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')) 3254 init = False 3255 cross = collections.defaultdict(float) 3256 nb_event = 0 3257 for event in lhe: 3258 rwgt_info = event.parse_reweight() 3259 if not init: 3260 if 'bias' in rwgt_info: 3261 output = lhe_parser.EventFile(pjoin(self.me_dir, 'Events', self.run_name, '.unweighted_events.lhe.tmp.gz'),'w') 3262 #output.write(lhe.banner) 3263 init = True 3264 else: 3265 return 3266 #change the weight 3267 event.wgt /= rwgt_info['bias'] 3268 #remove the bias info 3269 del event.reweight_data['bias'] 3270 # compute the new cross-section 3271 cross[event.ievent] += event.wgt 3272 nb_event +=1 3273 output.write(str(event)) 3274 output.write('</LesHouchesEvents>') 3275 output.close() 3276 lhe.close() 3277 3278 # MODIFY THE BANNER i.e. INIT BLOCK 3279 # ensure information compatible with normalisation choice 3280 total_cross = sum(cross[key] for key in cross) 3281 if 'event_norm' in self.run_card: # if not this is "sum" 3282 if self.run_card['event_norm'] == 'average': 3283 total_cross = total_cross / nb_event 3284 for key in cross: 3285 cross[key] /= nb_event 3286 elif self.run_card['event_norm'] == 'unity': 3287 total_cross = self.results.current['cross'] * total_cross / nb_event 3288 for key in cross: 3289 cross[key] *= total_cross / nb_event 3290 3291 bannerfile = lhe_parser.EventFile(pjoin(self.me_dir, 'Events', self.run_name, '.banner.tmp.gz'),'w') 3292 banner = banner_mod.Banner(lhe.banner) 3293 banner.modify_init_cross(cross) 3294 banner.write(bannerfile, close_tag=False) 3295 bannerfile.close() 3296 # replace the lhe file by the new one 3297 os.system('cat %s %s > %s' %(bannerfile.name, output.name, lhe.name)) 3298 os.remove(bannerfile.name) 3299 os.remove(output.name) 3300 3301 3302 self.results.current['cross'] = total_cross 3303 self.results.current['error'] = 0
3304 3305 ############################################################################
3306 - def do_store_events(self, line):
3307 """Advanced commands: Launch store events""" 3308 3309 args = self.split_arg(line) 3310 # Check argument's validity 3311 self.check_combine_events(args) 3312 self.update_status('Storing parton level results', level='parton') 3313 3314 run = self.run_name 3315 tag = self.run_card['run_tag'] 3316 devnull = open(os.devnull, 'w') 3317 3318 if not os.path.exists(pjoin(self.me_dir, 'Events', run)): 3319 os.mkdir(pjoin(self.me_dir, 'Events', run)) 3320 if not os.path.exists(pjoin(self.me_dir, 'HTML', run)): 3321 os.mkdir(pjoin(self.me_dir, 'HTML', run)) 3322 3323 # 1) Store overall process information 3324 #input = pjoin(self.me_dir, 'SubProcesses', 'results.dat') 3325 #output = pjoin(self.me_dir, 'SubProcesses', '%s_results.dat' % run) 3326 #files.cp(input, output) 3327 3328 3329 # 2) Treat the files present in the P directory 3330 # Ensure that the number of events is different of 0 3331 if self.results.current['nb_event'] == 0: 3332 logger.warning("No event detected. No cleaning performed! This should allow to run:\n" + 3333 " cd Subprocesses; ../bin/internal/combine_events\n"+ 3334 " to have your events if those one are missing.") 3335 else: 3336 for P_path in SubProcesses.get_subP(self.me_dir): 3337 G_dir = [G for G in os.listdir(P_path) if G.startswith('G') and 3338 os.path.isdir(pjoin(P_path,G))] 3339 for G in G_dir: 3340 G_path = pjoin(P_path,G) 3341 try: 3342 # Remove events file (if present) 3343 if os.path.exists(pjoin(G_path, 'events.lhe')): 3344 os.remove(pjoin(G_path, 'events.lhe')) 3345 except Exception: 3346 continue 3347 #try: 3348 # # Store results.dat 3349 # if os.path.exists(pjoin(G_path, 'results.dat')): 3350 # input = pjoin(G_path, 'results.dat') 3351 # output = pjoin(G_path, '%s_results.dat' % run) 3352 # files.cp(input, output) 3353 #except Exception: 3354 # continue 3355 # Store log 3356 try: 3357 if os.path.exists(pjoin(G_path, 'log.txt')): 3358 input = pjoin(G_path, 'log.txt') 3359 output = pjoin(G_path, '%s_log.txt' % run) 3360 files.mv(input, output) 3361 except Exception: 3362 continue 3363 #try: 3364 # # Grid 3365 # for name in ['ftn26']: 3366 # if os.path.exists(pjoin(G_path, name)): 3367 # if os.path.exists(pjoin(G_path, '%s_%s.gz'%(run,name))): 3368 # os.remove(pjoin(G_path, '%s_%s.gz'%(run,name))) 3369 # input = pjoin(G_path, name) 3370 # output = pjoin(G_path, '%s_%s' % (run,name)) 3371 # files.mv(input, output) 3372 # misc.gzip(pjoin(G_path, output), error=None) 3373 #except Exception: 3374 # continue 3375 # Delete ftn25 to ensure reproducible runs 3376 if os.path.exists(pjoin(G_path, 'ftn25')): 3377 os.remove(pjoin(G_path, 'ftn25')) 3378 3379 # 3) Update the index.html 3380 misc.call(['%s/gen_cardhtml-pl' % self.dirbin], 3381 cwd=pjoin(self.me_dir)) 3382 3383 3384 # 4) Move the Files present in Events directory 3385 E_path = pjoin(self.me_dir, 'Events') 3386 O_path = pjoin(self.me_dir, 'Events', run) 3387 3388 # The events file 3389 for name in ['events.lhe', 'unweighted_events.lhe']: 3390 finput = pjoin(E_path, name) 3391 foutput = pjoin(O_path, name) 3392 if os.path.exists(finput): 3393 logger.debug("File %s exists BAAAAD. Not move anymore!" % pjoin(E_path, name)) 3394 if os.path.exists(foutput): 3395 misc.gzip(foutput, stdout="%s.gz" % foutput, error=False) 3396 # if os.path.exists(pjoin(O_path, '%s.gz' % name)): 3397 # os.remove(pjoin(O_path, '%s.gz' % name)) 3398 # input = pjoin(E_path, name) 3399 ## output = pjoin(O_path, name) 3400 3401 3402 self.update_status('End Parton', level='parton', makehtml=False) 3403 devnull.close()
3404 3405 3406 ############################################################################
3407 - def do_create_gridpack(self, line):
3408 """Advanced commands: Create gridpack from present run""" 3409 3410 self.update_status('Creating gridpack', level='parton') 3411 # compile gen_ximprove 3412 misc.compile(['../bin/internal/gen_ximprove'], cwd=pjoin(self.me_dir, "Source")) 3413 args = self.split_arg(line) 3414 self.check_combine_events(args) 3415 if not self.run_tag: self.run_tag = 'tag_1' 3416 os.system("sed -i.bak \"s/ *.false.*=.*GridRun/ .true. = GridRun/g\" %s/Cards/grid_card.dat" \ 3417 % self.me_dir) 3418 misc.call(['./bin/internal/restore_data', self.run_name], 3419 cwd=self.me_dir) 3420 misc.call(['./bin/internal/store4grid', 3421 self.run_name, self.run_tag], 3422 cwd=self.me_dir) 3423 misc.call(['./bin/internal/clean'], cwd=self.me_dir) 3424 misc.call(['./bin/internal/make_gridpack'], cwd=self.me_dir) 3425 files.mv(pjoin(self.me_dir, 'gridpack.tar.gz'), 3426 pjoin(self.me_dir, '%s_gridpack.tar.gz' % self.run_name)) 3427 os.system("sed -i.bak \"s/\s*.true.*=.*GridRun/ .false. = GridRun/g\" %s/Cards/grid_card.dat" \ 3428 % self.me_dir) 3429 self.update_status('gridpack created', level='gridpack')
3430 3431 ############################################################################
3432 - def do_shower(self, line):
3433 """launch the shower""" 3434 3435 args = self.split_arg(line) 3436 if len(args)>1 and args[0] in self._interfaced_showers: 3437 chosen_showers = [args.pop(0)] 3438 elif '--no_default' in line: 3439 # If '--no_default' was specified in the arguments, then only one 3440 # shower will be run, depending on which card is present. 3441 # but we each of them are called. (each of them check if the file exists) 3442 chosen_showers = list(self._interfaced_showers) 3443 else: 3444 chosen_showers = list(self._interfaced_showers) 3445 # It is preferable to run only one shower, even if several are available and no 3446 # specific one has been selected 3447 shower_priority = ['pythia8','pythia'] 3448 chosen_showers = [sorted(chosen_showers,key=lambda sh: 3449 shower_priority.index(sh) if sh in shower_priority else len(shower_priority)+1)[0]] 3450 3451 for shower in chosen_showers: 3452 self.exec_cmd('%s %s'%(shower,' '.join(args)), 3453 postcmd=False, printcmd=False)
3454
3455 - def do_madanalysis5_parton(self, line):
3456 """launch MadAnalysis5 at the parton level.""" 3457 return self.run_madanalysis5(line,mode='parton')
3458 3459 #=============================================================================== 3460 # Return a warning (if applicable) on the consistency of the current Pythia8 3461 # and MG5_aMC version specified. It is placed here because it should be accessible 3462 # from both madgraph5_interface and madevent_interface 3463 #=============================================================================== 3464 @staticmethod
3465 - def mg5amc_py8_interface_consistency_warning(options):
3466 """ Check the consistency of the mg5amc_py8_interface installed with 3467 the current MG5 and Pythia8 versions. """ 3468 3469 # All this is only relevant is Pythia8 is interfaced to MG5 3470 if not options['pythia8_path']: 3471 return None 3472 3473 if not options['mg5amc_py8_interface_path']: 3474 return \ 3475 """ 3476 A Pythia8 path is specified via the option 'pythia8_path' but no path for option 3477 'mg5amc_py8_interface_path' is specified. This means that Pythia8 cannot be used 3478 leading order simulations with MadEvent. 3479 Consider installing the MG5_aMC-PY8 interface with the following command: 3480 MG5_aMC>install mg5amc_py8_interface 3481 """ 3482 3483 mg5amc_py8_interface_path = options['mg5amc_py8_interface_path'] 3484 py8_path = options['pythia8_path'] 3485 # If the specified interface path is relative, make it absolut w.r.t MGDIR if 3486 # avaialble. 3487 if not MADEVENT: 3488 mg5amc_py8_interface_path = pjoin(MG5DIR,mg5amc_py8_interface_path) 3489 py8_path = pjoin(MG5DIR,py8_path) 3490 3491 # Retrieve all the on-install and current versions 3492 MG5_version_on_install = open(pjoin(mg5amc_py8_interface_path, 3493 'MG5AMC_VERSION_ON_INSTALL')).read().replace('\n','') 3494 if MG5_version_on_install == 'UNSPECIFIED': 3495 MG5_version_on_install = None 3496 PY8_version_on_install = open(pjoin(mg5amc_py8_interface_path, 3497 'PYTHIA8_VERSION_ON_INSTALL')).read().replace('\n','') 3498 MG5_curr_version =misc.get_pkg_info()['version'] 3499 try: 3500 p = subprocess.Popen(['./get_pythia8_version.py',py8_path], 3501 stdout=subprocess.PIPE, stderr=subprocess.PIPE, 3502 cwd=mg5amc_py8_interface_path) 3503 (out, err) = p.communicate() 3504 out = out.replace('\n','') 3505 PY8_curr_version = out 3506 # In order to test that the version is correctly formed, we try to cast 3507 # it to a float 3508 float(out) 3509 except: 3510 PY8_curr_version = None 3511 3512 if not MG5_version_on_install is None and not MG5_curr_version is None: 3513 if MG5_version_on_install != MG5_curr_version: 3514 return \ 3515 """ 3516 The current version of MG5_aMC (v%s) is different than the one active when 3517 installing the 'mg5amc_py8_interface_path' (which was MG5aMC v%s). 3518 Please consider refreshing the installation of this interface with the command: 3519 MG5_aMC>install mg5amc_py8_interface 3520 """%(MG5_curr_version, MG5_version_on_install) 3521 3522 if not PY8_version_on_install is None and not PY8_curr_version is None: 3523 if PY8_version_on_install != PY8_curr_version: 3524 return \ 3525 """ 3526 The current version of Pythia8 (v%s) is different than the one active when 3527 installing the 'mg5amc_py8_interface' tool (which was Pythia8 v%s). 3528 Please consider refreshing the installation of this interface with the command: 3529 MG5_aMC>install mg5amc_py8_interface 3530 """%(PY8_curr_version,PY8_version_on_install) 3531 3532 return None
3533
3534 - def setup_Pythia8RunAndCard(self, PY8_Card, run_type):
3535 """ Setup the Pythia8 Run environment and card. In particular all the process and run specific parameters 3536 of the card are automatically set here. This function returns the path where HEPMC events will be output, 3537 if any.""" 3538 3539 HepMC_event_output = None 3540 tag = self.run_tag 3541 3542 PY8_Card.subruns[0].systemSet('Beams:LHEF',"unweighted_events.lhe.gz") 3543 3544 if PY8_Card['HEPMCoutput:file']=='auto': 3545 HepMC_event_output = pjoin(self.me_dir,'Events', self.run_name, 3546 '%s_pythia8_events.hepmc'%tag) 3547 PY8_Card.MadGraphSet('HEPMCoutput:file','%s_pythia8_events.hepmc'%tag) 3548 elif PY8_Card['HEPMCoutput:file'].startswith('fifo'): 3549 fifo_specs = PY8_Card['HEPMCoutput:file'].split('@') 3550 fifo_path = None 3551 if len(fifo_specs)<=1: 3552 fifo_path = pjoin(self.me_dir,'Events', self.run_name,'PY8.hepmc.fifo') 3553 if os.path.exists(fifo_path): 3554 os.remove(fifo_path) 3555 misc.mkfifo(fifo_path) 3556 # Use defaultSet not to overwrite the current userSet status 3557 PY8_Card.defaultSet('HEPMCoutput:file','PY8.hepmc.fifo') 3558 else: 3559 fifo_path = fifo_specs[1] 3560 if os.path.exists(fifo_path): 3561 if stat.S_ISFIFO(os.stat(fifo_path).st_mode): 3562 logger.warning('PY8 will be reusing already existing '+ 3563 'custom fifo file at:\n %s'%fifo_path) 3564 else: 3565 raise InvalidCmd( 3566 """The fifo path speficied for the PY8 parameter 'HEPMCoutput:file': 3567 %s 3568 already exists and is not a fifo file."""%fifo_path) 3569 else: 3570 misc.mkfifo(fifo_path) 3571 # Use defaultSet not to overwrite the current userSet status 3572 PY8_Card.defaultSet('HEPMCoutput:file',fifo_path) 3573 HepMC_event_output=fifo_path 3574 elif PY8_Card['HEPMCoutput:file'] in ['','/dev/null','None']: 3575 logger.warning('User disabled the HepMC output of Pythia8.') 3576 HepMC_event_output = None 3577 else: 3578 # Normalize the relative path if given as relative by the user. 3579 HepMC_event_output = pjoin(self.me_dir,'Events', self.run_name, 3580 PY8_Card['HEPMCoutput:file']) 3581 3582 # We specify by hand all necessary parameters, so that there is no 3583 # need to read parameters from the Banner. 3584 PY8_Card.MadGraphSet('JetMatching:setMad', False) 3585 if run_type=='MLM': 3586 # MadGraphSet sets the corresponding value (in system mode) 3587 # only if it is not already user_set. 3588 if PY8_Card['JetMatching:qCut']==-1.0: 3589 PY8_Card.MadGraphSet('JetMatching:qCut',1.5*self.run_card['xqcut']) 3590 3591 if PY8_Card['JetMatching:qCut']<(1.5*self.run_card['xqcut']): 3592 logger.error( 3593 'The MLM merging qCut parameter you chose (%f) is less than'%PY8_Card['JetMatching:qCut']+ 3594 '1.5*xqcut, with xqcut your run_card parameter (=%f).\n'%self.run_card['xqcut']+ 3595 'It would be better/safer to use a larger qCut or a smaller xqcut.') 3596 3597 # Also make sure to use the shower starting scales specified in the LHE 3598 # unless the user specified it 3599 PY8_Card.systemSet('Beams:setProductionScalesFromLHEF',True) 3600 3601 # Automatically set qWeed to xqcut if not defined by the user. 3602 if PY8_Card['SysCalc:qWeed']==-1.0: 3603 PY8_Card.MadGraphSet('SysCalc:qWeed',self.run_card['xqcut']) 3604 3605 if PY8_Card['SysCalc:qCutList']=='auto': 3606 if self.run_card['use_syst']: 3607 if self.run_card['sys_matchscale']=='auto': 3608 qcut = PY8_Card['JetMatching:qCut'] 3609 value = [factor*qcut for factor in [0.5,0.75,1.0,1.5,2.0] if\ 3610 factor*qcut> 1.5*self.run_card['xqcut'] ] 3611 PY8_Card.MadGraphSet('SysCalc:qCutList', value) 3612 else: 3613 qCutList = [float(qc) for qc in self.run_card['sys_matchscale'].split()] 3614 if PY8_Card['JetMatching:qCut'] not in qCutList: 3615 qCutList.append(PY8_Card['JetMatching:qCut']) 3616 PY8_Card.MadGraphSet('SysCalc:qCutList', qCutList) 3617 3618 for scale in PY8_Card['SysCalc:qCutList']: 3619 if scale<(1.5*self.run_card['xqcut']): 3620 logger.error( 3621 'One of the MLM merging qCut parameter you chose (%f) in the variation list'%scale+\ 3622 " (either via 'SysCalc:qCutList' in the PY8 shower card or "+\ 3623 "'sys_matchscale' in the run_card) is less than 1.5*xqcut, where xqcut is"+ 3624 ' the run_card parameter (=%f)\n'%self.run_card['xqcut']+ 3625 'It would be better/safer to use a larger qCut or a smaller xqcut.') 3626 3627 # Specific MLM settings 3628 # PY8 should not implement the MLM veto since the driver should do it 3629 # if merging scale variation is turned on 3630 if self.run_card['use_syst']: 3631 PY8_Card.MadGraphSet('JetMatching:doVeto',False) 3632 3633 PY8_Card.MadGraphSet('JetMatching:merge',True) 3634 PY8_Card.MadGraphSet('JetMatching:scheme',1) 3635 # Use the parameter maxjetflavor for JetMatching:nQmatch which specifies 3636 # up to which parton must be matched.Merging:nQuarksMerge 3637 PY8_Card.MadGraphSet('JetMatching:nQmatch',self.run_card['maxjetflavor']) 3638 # For MLM, a cone radius of 1.0 is to be prefered. 3639 PY8_Card.MadGraphSet('JetMatching:coneRadius',1.0) 3640 # And the value of etaj_max is already infinity by default. 3641 # PY8_Card.MadGraphSet('JetMatching:etaJetMax',1000.0) 3642 if not hasattr(self,'proc_characteristic'): 3643 self.proc_characteristic = self.get_characteristics() 3644 nJetMax = self.proc_characteristic['max_n_matched_jets'] 3645 if PY8_Card['JetMatching:nJetMax'.lower()] == -1: 3646 logger.info("No user-defined value for Pythia8 parameter "+ 3647 "'JetMatching:nJetMax'. Setting it automatically to %d."%nJetMax) 3648 PY8_Card.MadGraphSet('JetMatching:nJetMax',nJetMax) 3649 # We use the positivity of 'ktdurham' cut as a CKKWl marker. 3650 elif run_type=='CKKW': 3651 CKKW_cut = None 3652 # Specific CKKW settings 3653 if self.run_card['ptlund']<=0.0 and self.run_card['ktdurham']>0.0: 3654 PY8_Card.subruns[0].MadGraphSet('Merging:doKTMerging',True) 3655 PY8_Card.subruns[0].MadGraphSet('Merging:Dparameter', 3656 self.run_card['dparameter']) 3657 CKKW_cut = 'ktdurham' 3658 elif self.run_card['ptlund']>0.0 and self.run_card['ktdurham']<=0.0: 3659 PY8_Card.subruns[0].MadGraphSet('Merging:doPTLundMerging',True) 3660 CKKW_cut = 'ptlund' 3661 else: 3662 raise InvalidCmd("*Either* the 'ptlund' or 'ktdurham' cut in "+\ 3663 " the run_card must be turned on to activate CKKW(L) merging"+ 3664 " with Pythia8, but *both* cuts cannot be turned on at the same time."+ 3665 "\n ptlund=%f, ktdurham=%f."%(self.run_card['ptlund'],self.run_card['ktdurham'])) 3666 3667 3668 # Automatically set qWeed to the CKKWL cut if not defined by the user. 3669 if PY8_Card['SysCalc:qWeed']==-1.0: 3670 PY8_Card.MadGraphSet('SysCalc:qWeed',self.run_card[CKKW_cut]) 3671 3672 # MadGraphSet sets the corresponding value (in system mode) 3673 # only if it is not already user_set. 3674 if PY8_Card['Merging:TMS']==-1.0: 3675 if self.run_card[CKKW_cut]>0.0: 3676 PY8_Card.MadGraphSet('Merging:TMS',self.run_card[CKKW_cut]) 3677 else: 3678 raise self.InvalidCmd('When running CKKWl merging, the user'+\ 3679 " select a '%s' cut larger than 0.0 in the run_card."%CKKW_cut) 3680 if PY8_Card['Merging:TMS']<self.run_card[CKKW_cut]: 3681 logger.error( 3682 'The CKKWl merging scale you chose (%f) is less than'%PY8_Card['Merging:TMS']+ 3683 'the %s cut specified in the run_card parameter (=%f).\n'%(CKKW_cut,self.run_card[CKKW_cut])+ 3684 'It is incorrect to use a smaller CKKWl scale than the generation-level %s cut!'%CKKW_cut) 3685 3686 if PY8_Card['Merging:Process']=='<set_by_user>': 3687 raise self.InvalidCmd('When running CKKWl merging, the user must'+ 3688 " specifiy the option 'Merging:Process' in pythia8_card.dat.\n"+ 3689 "Read section 'Defining the hard process' of "+\ 3690 "http://home.thep.lu.se/~torbjorn/pythia81html/CKKWLMerging.html for more information.") 3691 PY8_Card.MadGraphSet('TimeShower:pTmaxMatch',1) 3692 PY8_Card.MadGraphSet('SpaceShower:pTmaxMatch',1) 3693 PY8_Card.MadGraphSet('SpaceShower:rapidityOrder',False) 3694 # PY8 should not implement the CKKW veto since the driver should do it. 3695 if self.run_card['use_syst']: 3696 PY8_Card.MadGraphSet('Merging:applyVeto',False) 3697 PY8_Card.MadGraphSet('Merging:includeWeightInXsection',False) 3698 # Use the parameter maxjetflavor for Merging:nQuarksMerge which specifies 3699 # up to which parton must be matched. 3700 PY8_Card.MadGraphSet('Merging:nQuarksMerge',self.run_card['maxjetflavor']) 3701 if not hasattr(self,'proc_characteristic'): 3702 self.proc_characteristic = self.get_characteristics() 3703 nJetMax = self.proc_characteristic['max_n_matched_jets'] 3704 if PY8_Card['Merging:nJetMax'.lower()] == -1: 3705 logger.info("No user-defined value for Pythia8 parameter "+ 3706 "'Merging:nJetMax'. Setting it automatically to %d."%nJetMax) 3707 PY8_Card.MadGraphSet('Merging:nJetMax',nJetMax) 3708 if PY8_Card['SysCalc:tmsList']=='auto': 3709 if self.run_card['use_syst']: 3710 if self.run_card['sys_matchscale']=='auto': 3711 tms = PY8_Card["Merging:TMS"] 3712 value = [factor*tms for factor in [0.5,0.75,1.0,1.5,2.0] 3713 if factor*tms > self.run_card[CKKW_cut]] 3714 PY8_Card.MadGraphSet('SysCalc:tmsList', value) 3715 else: 3716 tmsList = [float(tms) for tms in self.run_card['sys_matchscale'].split()] 3717 if PY8_Card['Merging:TMS'] not in tmsList: 3718 tmsList.append(PY8_Card['Merging:TMS']) 3719 PY8_Card.MadGraphSet('SysCalc:tmsList', tmsList) 3720 3721 for scale in PY8_Card['SysCalc:tmsList']: 3722 if scale<self.run_card[CKKW_cut]: 3723 logger.error( 3724 'One of the CKKWl merging scale you chose (%f) in the variation list'%scale+\ 3725 " (either via 'SysCalc:tmsList' in the PY8 shower card or "+\ 3726 "'sys_matchscale' in the run_card) is less than %f, "%self.run_card[CKKW_cut]+ 3727 'the %s cut specified in the run_card parameter.\n'%CKKW_cut+ 3728 'It is incorrect to use a smaller CKKWl scale than the generation-level %s cut!'%CKKW_cut) 3729 else: 3730 # Here, the run is therefore not a merged-type of run. We must therefore make sure *not* 3731 # to specify the "Merging:Process' as this makes older versions of the driver crash if 3732 # there is no merging in place 3733 PY8_Card.vetoParamWriteOut('Merging:Process') 3734 3735 return HepMC_event_output
3736
3737 - def do_pythia8(self, line):
3738 """launch pythia8""" 3739 3740 # Check argument's validity 3741 args = self.split_arg(line) 3742 if '--no_default' in args: 3743 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia8_card.dat')): 3744 return 3745 no_default = True 3746 args.remove('--no_default') 3747 else: 3748 no_default = False 3749 3750 if not self.run_name: 3751 self.check_pythia8(args) 3752 self.configure_directory(html_opening =False) 3753 else: 3754 # initialize / remove lhapdf mode 3755 self.configure_directory(html_opening =False) 3756 self.check_pythia8(args) 3757 3758 # the args are modify and the last arg is always the mode 3759 if not no_default: 3760 self.ask_pythia_run_configuration(args[-1], pythia_version=8) 3761 3762 if self.options['automatic_html_opening']: 3763 misc.open_file(os.path.join(self.me_dir, 'crossx.html')) 3764 self.options['automatic_html_opening'] = False 3765 3766 if self.run_card['event_norm'] not in ['unit','average']: 3767 logger.critical("Pythia8 does not support normalization to the sum. Not running Pythia8") 3768 return 3769 #\n"+\ 3770 #"The normalisation of the hepmc output file will be wrong (i.e. non-standard).\n"+\ 3771 #"Please use 'event_norm = average' in the run_card to avoid this problem.") 3772 3773 # Update the banner with the pythia card 3774 if not self.banner or len(self.banner) <=1: 3775 # Here the level keyword 'pythia' must not be changed to 'pythia8'. 3776 self.banner = banner_mod.recover_banner(self.results, 'pythia') 3777 3778 if not self.options['mg5amc_py8_interface_path'] or not \ 3779 os.path.exists(pjoin(self.options['mg5amc_py8_interface_path'], 3780 'MG5aMC_PY8_interface')): 3781 raise self.InvalidCmd( 3782 """The MG5aMC_PY8_interface tool cannot be found, so that MadEvent cannot steer Pythia8 shower. 3783 Please install this tool with the following MG5_aMC command: 3784 MG5_aMC> install mg5amc_py8_interface_path""") 3785 else: 3786 pythia_main = pjoin(self.options['mg5amc_py8_interface_path'], 3787 'MG5aMC_PY8_interface') 3788 warnings = MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options) 3789 if warnings: 3790 logger.warning(warnings) 3791 3792 self.results.add_detail('run_mode', 'madevent') 3793 3794 # Again here 'pythia' is just a keyword for the simulation level. 3795 self.update_status('\033[92mRunning Pythia8 [arXiv:1410.3012]\033[0m', 'pythia8') 3796 3797 tag = self.run_tag 3798 # Now write Pythia8 card 3799 # Start by reading, starting from the default one so that the 'user_set' 3800 # tag are correctly set. 3801 PY8_Card = banner_mod.PY8Card(pjoin(self.me_dir, 'Cards', 3802 'pythia8_card_default.dat')) 3803 PY8_Card.read(pjoin(self.me_dir, 'Cards', 'pythia8_card.dat'), 3804 setter='user') 3805 3806 run_type = 'default' 3807 merged_run_types = ['MLM','CKKW'] 3808 if int(self.run_card['ickkw'])==1: 3809 run_type = 'MLM' 3810 elif int(self.run_card['ickkw'])==2 or \ 3811 self.run_card['ktdurham']>0.0 or self.run_card['ptlund']>0.0: 3812 run_type = 'CKKW' 3813 3814 # Edit the card and run environment according to the run specification 3815 HepMC_event_output = self.setup_Pythia8RunAndCard(PY8_Card, run_type) 3816 3817 # Now write the card. 3818 pythia_cmd_card = pjoin(self.me_dir, 'Events', self.run_name , 3819 '%s_pythia8.cmd' % tag) 3820 cmd_card = StringIO.StringIO() 3821 PY8_Card.write(cmd_card,pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 3822 direct_pythia_input=True) 3823 3824 # Now setup the preamble to make sure that everything will use the locally 3825 # installed tools (if present) even if the user did not add it to its 3826 # environment variables. 3827 if MADEVENT: 3828 preamble = misc.get_HEPTools_location_setter( 3829 pjoin(self.options['mg5amc_py8_interface_path'],os.pardir),'lib') 3830 else: 3831 preamble = misc.get_HEPTools_location_setter( 3832 pjoin(MG5DIR,'HEPTools'),'lib') 3833 3834 open(pythia_cmd_card,'w').write("""! 3835 ! It is possible to run this card manually with: 3836 ! %s %s 3837 ! 3838 """%(preamble+pythia_main,os.path.basename(pythia_cmd_card))+cmd_card.getvalue()) 3839 3840 # launch pythia8 3841 pythia_log = pjoin(self.me_dir, 'Events', self.run_name , 3842 '%s_pythia8.log' % tag) 3843 3844 # Write a bash wrapper to run the shower with custom environment variables 3845 wrapper_path = pjoin(self.me_dir,'Events',self.run_name,'run_shower.sh') 3846 wrapper = open(wrapper_path,'w') 3847 shell = 'bash' if misc.get_shell_type() in ['bash',None] else 'tcsh' 3848 shell_exe = None 3849 if os.path.exists('/usr/bin/env'): 3850 shell_exe = '/usr/bin/env %s'%shell 3851 else: 3852 shell_exe = misc.which(shell) 3853 if not shell_exe: 3854 self.InvalidCmd('No shell could be found in your environment.\n'+ 3855 "Make sure that either '%s' is in your path or that the"%shell+\ 3856 " command '/usr/bin/env %s' exists and returns a valid path."%shell) 3857 3858 exe_cmd = "#!%s\n%s"%(shell_exe,' '.join( 3859 [preamble+pythia_main, 3860 os.path.basename(pythia_cmd_card)])) 3861 3862 wrapper.write(exe_cmd) 3863 wrapper.close() 3864 3865 # Set it as executable 3866 st = os.stat(wrapper_path) 3867 os.chmod(wrapper_path, st.st_mode | stat.S_IEXEC) 3868 3869 # If the target HEPMC output file is a fifo, don't hang MG5_aMC and let 3870 # it proceed. 3871 is_HepMC_output_fifo = False if not HepMC_event_output else \ 3872 ( os.path.exists(HepMC_event_output) and \ 3873 stat.S_ISFIFO(os.stat(HepMC_event_output).st_mode)) 3874 startPY8timer = time.time() 3875 3876 # Information that will be extracted from this PY8 run 3877 PY8_extracted_information={ 'sigma_m':None, 'Nacc':None, 'Ntry':None, 3878 'cross_sections':{} } 3879 3880 if is_HepMC_output_fifo: 3881 logger.info( 3882 """Pythia8 is set to output HEPMC events to to a fifo file. 3883 You can follow PY8 run with the following command (in a separate terminal): 3884 tail -f %s"""%pythia_log) 3885 py8_log = open(pythia_log,'w') 3886 py8_bkgrd_proc = misc.Popen([wrapper_path], 3887 stdout=py8_log,stderr=py8_log, 3888 cwd=pjoin(self.me_dir,'Events',self.run_name)) 3889 # Now directly return to madevent interactive interface if we are piping PY8 3890 if not no_default: 3891 logger.info('You can now run a tool that reads the following fifo file:'+\ 3892 '\n %s\nwhere PY8 outputs HEPMC events (e.g. MadAnalysis5).' 3893 %HepMC_event_output,'$MG:color:GREEN') 3894 return 3895 else: 3896 if self.options['run_mode']!=0: 3897 # Start a parallelization instance (stored in self.cluster) 3898 self.configure_run_mode(self.options['run_mode']) 3899 if self.options['run_mode']==1: 3900 n_cores = max(self.options['cluster_size'],1) 3901 elif self.options['run_mode']==2: 3902 n_cores = max(self.cluster.nb_core,1) 3903 3904 lhe_file_name = os.path.basename(PY8_Card.subruns[0]['Beams:LHEF']) 3905 lhe_file = lhe_parser.EventFile(pjoin(self.me_dir,'Events', 3906 self.run_name,PY8_Card.subruns[0]['Beams:LHEF'])) 3907 n_available_events = len(lhe_file) 3908 if PY8_Card['Main:numberOfEvents']==-1: 3909 n_events = n_available_events 3910 else: 3911 n_events = PY8_Card['Main:numberOfEvents'] 3912 if n_events > n_available_events: 3913 raise self.InvalidCmd, 'You specified more events (%d) in the PY8 parameter'%n_events+\ 3914 "'Main:numberOfEvents' than the total number of events available (%d)"%n_available_events+\ 3915 ' in the event file:\n %s'%pjoin(self.me_dir,'Events',self.run_name,PY8_Card.subruns[0]['Beams:LHEF']) 3916 3917 # Implement a security to insure a minimum numbe of events per job 3918 if self.options['run_mode']==2: 3919 min_n_events_per_job = 100 3920 elif self.options['run_mode']==1: 3921 min_n_events_per_job = 1000 3922 min_n_core = n_events//min_n_events_per_job 3923 n_cores = max(min(min_n_core,n_cores),1) 3924 3925 if self.options['run_mode']==0 or (self.options['run_mode']==2 and self.options['nb_core']==1): 3926 # No need for parallelization anymore 3927 self.cluster = None 3928 logger.info('Follow Pythia8 shower by running the '+ 3929 'following command (in a separate terminal):\n tail -f %s'%pythia_log) 3930 3931 if self.options['run_mode']==2 and self.options['nb_core']>1: 3932 ret_code = self.cluster.launch_and_wait(wrapper_path, 3933 argument= [], stdout= pythia_log, stderr=subprocess.STDOUT, 3934 cwd=pjoin(self.me_dir,'Events',self.run_name)) 3935 else: 3936 ret_code = misc.call(wrapper_path, stdout=open(pythia_log,'w'), stderr=subprocess.STDOUT, 3937 cwd=pjoin(self.me_dir,'Events',self.run_name)) 3938 if ret_code != 0: 3939 raise self.InvalidCmd, 'Pythia8 shower interrupted with return'+\ 3940 ' code %d.\n'%ret_code+\ 3941 'You can find more information in this log file:\n%s'%pythia_log 3942 else: 3943 if self.run_card['event_norm']=='sum': 3944 logger.error("") 3945 logger.error("Either run in single core or change event_norm to 'average'.") 3946 raise InvalidCmd("Pythia8 parallelization with event_norm set to 'sum' is not supported." 3947 "Either run in single core or change event_norm to 'average'.") 3948 3949 # Create the parallelization folder 3950 parallelization_dir = pjoin(self.me_dir,'Events',self.run_name,'PY8_parallelization') 3951 if os.path.isdir(parallelization_dir): 3952 shutil.rmtree(parallelization_dir) 3953 os.mkdir(parallelization_dir) 3954 # Copy what should be the now standalone executable for PY8 3955 shutil.copy(pythia_main,parallelization_dir) 3956 # Add a safe card in parallelization 3957 ParallelPY8Card = copy.copy(PY8_Card) 3958 # Normalize the name of the HEPMCouput and lhe input 3959 if HepMC_event_output: 3960 ParallelPY8Card['HEPMCoutput:file']='events.hepmc' 3961 else: 3962 ParallelPY8Card['HEPMCoutput:file']='/dev/null' 3963 3964 ParallelPY8Card.subruns[0].systemSet('Beams:LHEF','events.lhe.gz') 3965 ParallelPY8Card.write(pjoin(parallelization_dir,'PY8Card.dat'), 3966 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 3967 direct_pythia_input=True) 3968 # Write the wrapper 3969 wrapper_path = pjoin(parallelization_dir,'run_PY8.sh') 3970 wrapper = open(wrapper_path,'w') 3971 if self.options['cluster_temp_path'] is None: 3972 exe_cmd = \ 3973 """#!%s 3974 ./%s PY8Card.dat >& PY8_log.txt 3975 """ 3976 else: 3977 exe_cmd = \ 3978 """#!%s 3979 ln -s ./events_$1.lhe.gz ./events.lhe.gz 3980 ./%s PY8Card_$1.dat >& PY8_log.txt 3981 mkdir split_$1 3982 if [ -f ./events.hepmc ]; 3983 then 3984 mv ./events.hepmc ./split_$1/ 3985 fi 3986 if [ -f ./pts.dat ]; 3987 then 3988 mv ./pts.dat ./split_$1/ 3989 fi 3990 if [ -f ./djrs.dat ]; 3991 then 3992 mv ./djrs.dat ./split_$1/ 3993 fi 3994 if [ -f ./PY8_log.txt ]; 3995 then 3996 mv ./PY8_log.txt ./split_$1/ 3997 fi 3998 tar -czf split_$1.tar.gz split_$1 3999 """ 4000 exe_cmd = exe_cmd%(shell_exe,os.path.basename(pythia_main)) 4001 wrapper.write(exe_cmd) 4002 wrapper.close() 4003 # Set it as executable 4004 st = os.stat(wrapper_path) 4005 os.chmod(wrapper_path, st.st_mode | stat.S_IEXEC) 4006 4007 # Split the .lhe event file, create event partition 4008 partition=[n_available_events//n_cores]*n_cores 4009 for i in range(n_available_events%n_cores): 4010 partition[i] += 1 4011 4012 # Splitting according to the total number of events requested by the user 4013 # Will be used to determine the number of events to indicate in the PY8 split cards. 4014 partition_for_PY8=[n_events//n_cores]*n_cores 4015 for i in range(n_events%n_cores): 4016 partition_for_PY8[i] += 1 4017 4018 logger.info('Splitting .lhe event file for PY8 parallelization...') 4019 n_splits = lhe_file.split(partition=partition, cwd=parallelization_dir, zip=True) 4020 4021 if n_splits!=len(partition): 4022 raise MadGraph5Error('Error during lhe file splitting. Expected %d files but obtained %d.' 4023 %(len(partition),n_splits)) 4024 # Distribute the split events 4025 split_files = [] 4026 split_dirs = [] 4027 for split_id in range(n_splits): 4028 split_files.append('events_%s.lhe.gz'%split_id) 4029 split_dirs.append(pjoin(parallelization_dir,'split_%d'%split_id)) 4030 # Add the necessary run content 4031 shutil.move(pjoin(parallelization_dir,lhe_file.name+'_%d.lhe.gz'%split_id), 4032 pjoin(parallelization_dir,split_files[-1])) 4033 4034 logger.info('Submitting Pythia8 jobs...') 4035 for i, split_file in enumerate(split_files): 4036 # We must write a PY8Card tailored for each split so as to correct the normalization 4037 # HEPMCoutput:scaling of each weight since the lhe showered will not longer contain the 4038 # same original number of events 4039 split_PY8_Card = banner_mod.PY8Card(pjoin(parallelization_dir,'PY8Card.dat')) 4040 # Make sure to sure the number of split_events determined during the splitting. 4041 split_PY8_Card.systemSet('Main:numberOfEvents',partition_for_PY8[i]) 4042 split_PY8_Card.systemSet('HEPMCoutput:scaling',split_PY8_Card['HEPMCoutput:scaling']* 4043 (float(partition_for_PY8[i])/float(n_events))) 4044 # Add_missing set to False so as to be sure not to add any additional parameter w.r.t 4045 # the ones in the original PY8 param_card copied. 4046 split_PY8_Card.write(pjoin(parallelization_dir,'PY8Card_%d.dat'%i), 4047 pjoin(parallelization_dir,'PY8Card.dat'), add_missing=False) 4048 in_files = [pjoin(parallelization_dir,os.path.basename(pythia_main)), 4049 pjoin(parallelization_dir,'PY8Card_%d.dat'%i), 4050 pjoin(parallelization_dir,split_file)] 4051 if self.options['cluster_temp_path'] is None: 4052 out_files = [] 4053 os.mkdir(pjoin(parallelization_dir,'split_%d'%i)) 4054 selected_cwd = pjoin(parallelization_dir,'split_%d'%i) 4055 for in_file in in_files+[pjoin(parallelization_dir,'run_PY8.sh')]: 4056 # Make sure to rename the split_file link from events_<x>.lhe.gz to events.lhe.gz 4057 # and similarly for PY8Card 4058 if os.path.basename(in_file)==split_file: 4059 ln(in_file,selected_cwd,name='events.lhe.gz') 4060 elif os.path.basename(in_file).startswith('PY8Card'): 4061 ln(in_file,selected_cwd,name='PY8Card.dat') 4062 else: 4063 ln(in_file,selected_cwd) 4064 in_files = [] 4065 else: 4066 out_files = ['split_%d.tar.gz'%i] 4067 selected_cwd = parallelization_dir 4068 self.cluster.submit2(wrapper_path, 4069 argument=[str(i)], cwd=selected_cwd, 4070 input_files=in_files, 4071 output_files=out_files, 4072 required_output=out_files) 4073 4074 def wait_monitoring(Idle, Running, Done): 4075 if Idle+Running+Done == 0: 4076 return 4077 logger.info('Pythia8 shower jobs: %d Idle, %d Running, %d Done [%s]'\ 4078 %(Idle, Running, Done, misc.format_time(time.time() - startPY8timer)))
4079 self.cluster.wait(parallelization_dir,wait_monitoring) 4080 4081 logger.info('Merging results from the split PY8 runs...') 4082 if self.options['cluster_temp_path']: 4083 # Decompressing the output 4084 for i, split_file in enumerate(split_files): 4085 misc.call(['tar','-xzf','split_%d.tar.gz'%i],cwd=parallelization_dir) 4086 os.remove(pjoin(parallelization_dir,'split_%d.tar.gz'%i)) 4087 4088 # Now merge logs 4089 pythia_log_file = open(pythia_log,'w') 4090 n_added = 0 4091 for split_dir in split_dirs: 4092 log_file = pjoin(split_dir,'PY8_log.txt') 4093 pythia_log_file.write('='*35+'\n') 4094 pythia_log_file.write(' -> Pythia8 log file for run %d <-'%i+'\n') 4095 pythia_log_file.write('='*35+'\n') 4096 pythia_log_file.write(open(log_file,'r').read()+'\n') 4097 if run_type in merged_run_types: 4098 sigma_m, Nacc, Ntry = self.parse_PY8_log_file(log_file) 4099 if any(elem is None for elem in [sigma_m, Nacc, Ntry]): 4100 continue 4101 n_added += 1 4102 if PY8_extracted_information['sigma_m'] is None: 4103 PY8_extracted_information['sigma_m'] = sigma_m 4104 else: 4105 PY8_extracted_information['sigma_m'] += sigma_m 4106 if PY8_extracted_information['Nacc'] is None: 4107 PY8_extracted_information['Nacc'] = Nacc 4108 else: 4109 PY8_extracted_information['Nacc'] += Nacc 4110 if PY8_extracted_information['Ntry'] is None: 4111 PY8_extracted_information['Ntry'] = Ntry 4112 else: 4113 PY8_extracted_information['Ntry'] += Ntry 4114 # Normalize the values added 4115 if n_added>0: 4116 PY8_extracted_information['sigma_m'] /= float(n_added) 4117 pythia_log_file.close() 4118 4119 # djr plots 4120 djr_HwU = None 4121 n_added = 0 4122 for split_dir in split_dirs: 4123 djr_file = pjoin(split_dir,'djrs.dat') 4124 if not os.path.isfile(djr_file): 4125 continue 4126 xsecs = self.extract_cross_sections_from_DJR(djr_file) 4127 if len(xsecs)>0: 4128 n_added += 1 4129 if len(PY8_extracted_information['cross_sections'])==0: 4130 PY8_extracted_information['cross_sections'] = xsecs 4131 # Square the error term 4132 for key in PY8_extracted_information['cross_sections']: 4133 PY8_extracted_information['cross_sections'][key][1] = \ 4134 PY8_extracted_information['cross_sections'][key][1]**2 4135 else: 4136 for key, value in xsecs.items(): 4137 PY8_extracted_information['cross_sections'][key][0] += value[0] 4138 # Add error in quadrature 4139 PY8_extracted_information['cross_sections'][key][1] += value[1]**2 4140 new_djr_HwU = histograms.HwUList(djr_file,run_id=0) 4141 if djr_HwU is None: 4142 djr_HwU = new_djr_HwU 4143 else: 4144 for i, hist in enumerate(djr_HwU): 4145 djr_HwU[i] = hist + new_djr_HwU[i] 4146 if not djr_HwU is None: 4147 djr_HwU.output(pjoin(self.me_dir,'Events',self.run_name,'djrs'),format='HwU') 4148 shutil.move(pjoin(self.me_dir,'Events',self.run_name,'djrs.HwU'), 4149 pjoin(self.me_dir,'Events',self.run_name,'%s_djrs.dat'%tag)) 4150 if n_added>0: 4151 for key in PY8_extracted_information['cross_sections']: 4152 PY8_extracted_information['cross_sections'][key][0] /= float(n_added) 4153 PY8_extracted_information['cross_sections'][key][1] = \ 4154 math.sqrt(PY8_extracted_information['cross_sections'][key][1])/float(n_added) 4155 4156 # pts plots 4157 pts_HwU = None 4158 for split_dir in split_dirs: 4159 pts_file = pjoin(split_dir,'pts.dat') 4160 if not os.path.isfile(pts_file): 4161 continue 4162 new_pts_HwU = histograms.HwUList(pts_file,run_id=0) 4163 if pts_HwU is None: 4164 pts_HwU = new_pts_HwU 4165 else: 4166 for i, hist in enumerate(pts_HwU): 4167 pts_HwU[i] = hist + new_pts_HwU[i] 4168 if not pts_HwU is None: 4169 pts_HwU.output(pjoin(self.me_dir,'Events',self.run_name,'pts'),format='HwU') 4170 shutil.move(pjoin(self.me_dir,'Events',self.run_name,'pts.HwU'), 4171 pjoin(self.me_dir,'Events',self.run_name,'%s_pts.dat'%tag)) 4172 4173 # HepMC events now. 4174 all_hepmc_files = [] 4175 for split_dir in split_dirs: 4176 hepmc_file = pjoin(split_dir,'events.hepmc') 4177 if not os.path.isfile(hepmc_file): 4178 continue 4179 all_hepmc_files.append(hepmc_file) 4180 4181 if len(all_hepmc_files)>0: 4182 hepmc_output = pjoin(self.me_dir,'Events',self.run_name,HepMC_event_output) 4183 with misc.TMP_directory() as tmp_dir: 4184 # Use system calls to quickly put these together 4185 header = open(pjoin(tmp_dir,'header.hepmc'),'w') 4186 n_head = 0 4187 for line in open(all_hepmc_files[0],'r'): 4188 if not line.startswith('E'): 4189 n_head += 1 4190 header.write(line) 4191 else: 4192 break 4193 header.close() 4194 tail = open(pjoin(tmp_dir,'tail.hepmc'),'w') 4195 n_tail = 0 4196 for line in misc.BackRead(all_hepmc_files[-1]): 4197 if line.startswith('HepMC::'): 4198 n_tail += 1 4199 tail.write(line) 4200 else: 4201 break 4202 tail.close() 4203 if n_tail>1: 4204 raise MadGraph5Error,'HEPMC files should only have one trailing command.' 4205 ###################################################################### 4206 # This is the most efficient way of putting together HEPMC's, *BUT* # 4207 # WARNING: NEED TO RENDER THE CODE BELOW SAFE TOWARDS INJECTION # 4208 ###################################################################### 4209 for hepmc_file in all_hepmc_files: 4210 # Remove in an efficient way the starting and trailing HEPMC tags 4211 os.system(' '.join(['sed','-i',"''","'%s;$d'"% 4212 (';'.join('%id'%(i+1) for i in range(n_head))),hepmc_file])) 4213 os.system(' '.join(['cat',pjoin(tmp_dir,'header.hepmc')]+all_hepmc_files+ 4214 [pjoin(tmp_dir,'tail.hepmc'),'>',hepmc_output])) 4215 4216 # We are done with the parallelization directory. Clean it. 4217 if os.path.isdir(parallelization_dir): 4218 shutil.rmtree(parallelization_dir) 4219 4220 # Properly rename the djr and pts output if present. 4221 djr_output = pjoin(self.me_dir,'Events', self.run_name, 'djrs.dat') 4222 if os.path.isfile(djr_output): 4223 shutil.move(djr_output, pjoin(self.me_dir,'Events', 4224 self.run_name, '%s_djrs.dat' % tag)) 4225 pt_output = pjoin(self.me_dir,'Events', self.run_name, 'pts.dat') 4226 if os.path.isfile(pt_output): 4227 shutil.move(pt_output, pjoin(self.me_dir,'Events', 4228 self.run_name, '%s_pts.dat' % tag)) 4229 4230 if not os.path.isfile(pythia_log) or \ 4231 'Inclusive cross section:' not in '\n'.join(open(pythia_log,'r').readlines()[-20:]): 4232 logger.warning('Fail to produce a pythia8 output. More info in \n %s'%pythia_log) 4233 return 4234 4235 # Plot for Pythia8 4236 successful = self.create_plot('Pythia8') 4237 if not successful: 4238 logger.warning('Failed to produce Pythia8 merging plots.') 4239 4240 self.to_store.append('pythia8') 4241 4242 # Study matched cross-sections 4243 if run_type in merged_run_types: 4244 # From the log file 4245 if all(PY8_extracted_information[_] is None for _ in ['sigma_m','Nacc','Ntry']): 4246 PY8_extracted_information['sigma_m'],PY8_extracted_information['Nacc'],\ 4247 PY8_extracted_information['Ntry'] = self.parse_PY8_log_file( 4248 pjoin(self.me_dir,'Events', self.run_name,'%s_pythia8.log' % tag)) 4249 4250 if not any(PY8_extracted_information[_] is None for _ in ['sigma_m','Nacc','Ntry']): 4251 self.results.add_detail('cross_pythia', PY8_extracted_information['sigma_m']) 4252 self.results.add_detail('nb_event_pythia', PY8_extracted_information['Nacc']) 4253 # Compute pythia error 4254 error = self.results[self.run_name].return_tag(self.run_tag)['error'] 4255 try: 4256 error_m = math.sqrt((error * Nacc/Ntry)**2 + sigma_m**2 *(1-Nacc/Ntry)/Nacc) 4257 except ZeroDivisionError: 4258 # Cannot compute error 4259 error_m = -1.0 4260 # works both for fixed number of generated events and fixed accepted events 4261 self.results.add_detail('error_pythia', error_m) 4262 4263 if self.run_card['use_syst']: 4264 self.results.add_detail('cross_pythia', -1) 4265 self.results.add_detail('error_pythia', 0) 4266 4267 # From the djr file generated 4268 djr_output = pjoin(self.me_dir,'Events',self.run_name,'%s_djrs.dat'%tag) 4269 if os.path.isfile(djr_output) and len(PY8_extracted_information['cross_sections'])==0: 4270 PY8_extracted_information['cross_sections'] = self.extract_cross_sections_from_DJR(djr_output) 4271 cross_sections = PY8_extracted_information['cross_sections'] 4272 if cross_sections: 4273 # Filter the cross_sections specified an keep only the ones 4274 # with central parameters and a different merging scale 4275 a_float_re = '[\+|-]?\d+(\.\d*)?([EeDd][\+|-]?\d+)?' 4276 central_merging_re = re.compile( 4277 '^\s*Weight_MERGING\s*=\s*(?P<merging>%s)\s*$'%a_float_re, 4278 re.IGNORECASE) 4279 cross_sections = dict( 4280 (float(central_merging_re.match(xsec).group('merging')),value) 4281 for xsec, value in cross_sections.items() if not 4282 central_merging_re.match(xsec) is None) 4283 central_scale = PY8_Card['JetMatching:qCut'] if \ 4284 int(self.run_card['ickkw'])==1 else PY8_Card['Merging:TMS'] 4285 if central_scale in cross_sections: 4286 self.results.add_detail('cross_pythia8', cross_sections[central_scale][0]) 4287 self.results.add_detail('error_pythia8', cross_sections[central_scale][1]) 4288 4289 #logger.info('Pythia8 merged cross-sections are:') 4290 #for scale in sorted(cross_sections.keys()): 4291 # logger.info(' > Merging scale = %-6.4g : %-11.5g +/- %-7.2g [pb]'%\ 4292 # (scale,cross_sections[scale][0],cross_sections[scale][1])) 4293 4294 xsecs_file = open(pjoin(self.me_dir,'Events',self.run_name, 4295 '%s_merged_xsecs.txt'%tag),'w') 4296 if cross_sections: 4297 xsecs_file.write('%-20s%-20s%-20s\n'%('Merging scale', 4298 'Cross-section [pb]','MC uncertainty [pb]')) 4299 for scale in sorted(cross_sections.keys()): 4300 xsecs_file.write('%-20.4g%-20.6e%-20.2e\n'% 4301 (scale,cross_sections[scale][0],cross_sections[scale][1])) 4302 else: 4303 xsecs_file.write('Cross-sections could not be read from the'+\ 4304 "XML node 'xsection' of the .dat file produced by Pythia8.") 4305 xsecs_file.close() 4306 4307 #Update the banner 4308 # We add directly the pythia command card because it has the full 4309 # information 4310 self.banner.add(pythia_cmd_card) 4311 4312 if int(self.run_card['ickkw']): 4313 # Add the matched cross-section 4314 if 'MGGenerationInfo' in self.banner: 4315 self.banner['MGGenerationInfo'] += '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 4316 else: 4317 self.banner['MGGenerationInfo'] = '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 4318 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)) 4319 self.banner.write(banner_path) 4320 4321 self.update_status('Pythia8 shower finished after %s.'%misc.format_time(time.time() - startPY8timer), level='pythia8') 4322 if self.options['delphes_path']: 4323 self.exec_cmd('delphes --no_default', postcmd=False, printcmd=False) 4324 self.print_results_in_shell(self.results.current) 4325
4326 - def parse_PY8_log_file(self, log_file_path):
4327 """ Parse a log file to extract number of event and cross-section. """ 4328 pythiare = re.compile("Les Houches User Process\(es\)\s*\d+\s*\|\s*(?P<tried>\d+)\s*(?P<selected>\d+)\s*(?P<generated>\d+)\s*\|\s*(?P<xsec>[\d\.e\-\+]+)\s*(?P<xsec_error>[\d\.e\-\+]+)") 4329 for line in misc.BackRead(log_file_path): 4330 info = pythiare.search(line) 4331 if not info: 4332 continue 4333 try: 4334 # Pythia cross section in mb, we want pb 4335 sigma_m = float(info.group('xsec')) *1e9 4336 Nacc = int(info.group('generated')) 4337 Ntry = int(info.group('tried')) 4338 if Nacc==0: 4339 raise self.InvalidCmd, 'Pythia8 shower failed since it'+\ 4340 ' did not accept any event from the MG5aMC event file.' 4341 return sigma_m, Nacc, Ntry 4342 except ValueError: 4343 return None,None,None 4344 raise self.InvalidCmd, "Could not find cross-section and event number information "+\ 4345 "in Pythia8 log\n '%s'."%log_file_path
4346
4347 - def extract_cross_sections_from_DJR(self,djr_output):
4348 """Extract cross-sections from a djr XML output.""" 4349 run_nodes = minidom.parse(djr_output).getElementsByTagName("run") 4350 all_nodes = dict((int(node.getAttribute('id')),node) for 4351 node in run_nodes) 4352 try: 4353 selected_run_node = all_nodes[0] 4354 except: 4355 return {} 4356 xsections = selected_run_node.getElementsByTagName("xsection") 4357 # We need to translate PY8's output in mb into pb 4358 return dict((xsec.getAttribute('name'), 4359 [float(xsec.childNodes[0].data.split()[0])*1e9, 4360 float(xsec.childNodes[0].data.split()[1])*1e9]) 4361 for xsec in xsections)
4362
4363 - def do_pythia(self, line):
4364 """launch pythia""" 4365 4366 4367 # Check argument's validity 4368 args = self.split_arg(line) 4369 if '--no_default' in args: 4370 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia_card.dat')): 4371 return 4372 no_default = True 4373 args.remove('--no_default') 4374 else: 4375 no_default = False 4376 4377 if not self.run_name: 4378 self.check_pythia(args) 4379 self.configure_directory(html_opening =False) 4380 else: 4381 # initialize / remove lhapdf mode 4382 self.configure_directory(html_opening =False) 4383 self.check_pythia(args) 4384 4385 if self.run_card['event_norm'] != 'sum': 4386 logger.error('pythia-pgs require event_norm to be on sum. Do not run pythia6') 4387 return 4388 4389 # the args are modify and the last arg is always the mode 4390 if not no_default: 4391 self.ask_pythia_run_configuration(args[-1]) 4392 if self.options['automatic_html_opening']: 4393 misc.open_file(os.path.join(self.me_dir, 'crossx.html')) 4394 self.options['automatic_html_opening'] = False 4395 4396 # Update the banner with the pythia card 4397 if not self.banner or len(self.banner) <=1: 4398 self.banner = banner_mod.recover_banner(self.results, 'pythia') 4399 4400 pythia_src = pjoin(self.options['pythia-pgs_path'],'src') 4401 4402 self.results.add_detail('run_mode', 'madevent') 4403 4404 self.update_status('Running Pythia', 'pythia') 4405 try: 4406 os.remove(pjoin(self.me_dir,'Events','pythia.done')) 4407 except Exception: 4408 pass 4409 4410 ## LAUNCHING PYTHIA 4411 # check that LHAPATH is define. 4412 if not re.search(r'^\s*LHAPATH=%s/PDFsets' % pythia_src, 4413 open(pjoin(self.me_dir,'Cards','pythia_card.dat')).read(), 4414 re.M): 4415 f = open(pjoin(self.me_dir,'Cards','pythia_card.dat'),'a') 4416 f.write('\n LHAPATH=%s/PDFsets' % pythia_src) 4417 f.close() 4418 tag = self.run_tag 4419 pythia_log = pjoin(self.me_dir, 'Events', self.run_name , '%s_pythia.log' % tag) 4420 #self.cluster.launch_and_wait('../bin/internal/run_pythia', 4421 # argument= [pythia_src], stdout= pythia_log, 4422 # stderr=subprocess.STDOUT, 4423 # cwd=pjoin(self.me_dir,'Events')) 4424 output_files = ['pythia_events.hep'] 4425 if self.run_card['use_syst']: 4426 output_files.append('syst.dat') 4427 if self.run_card['ickkw'] == 1: 4428 output_files.append(['beforeveto.tree', 'xsecs.tree', 'events.tree']) 4429 4430 os.environ['PDG_MASS_TBL'] = pjoin(pythia_src,'mass_width_2004.mc') 4431 self.cluster.launch_and_wait(pjoin(pythia_src, 'pythia'), 4432 input_files=[pjoin(self.me_dir, "Events", "unweighted_events.lhe"), 4433 pjoin(self.me_dir,'Cards','pythia_card.dat'), 4434 pjoin(pythia_src,'mass_width_2004.mc')], 4435 output_files=output_files, 4436 stdout= pythia_log, 4437 stderr=subprocess.STDOUT, 4438 cwd=pjoin(self.me_dir,'Events')) 4439 4440 4441 os.remove(pjoin(self.me_dir, "Events", "unweighted_events.lhe")) 4442 4443 if not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')): 4444 logger.warning('Fail to produce pythia output. More info in \n %s' % pythia_log) 4445 return 4446 4447 self.to_store.append('pythia') 4448 4449 # Find the matched cross-section 4450 if int(self.run_card['ickkw']): 4451 # read the line from the bottom of the file 4452 pythia_log = misc.BackRead(pjoin(self.me_dir,'Events', self.run_name, 4453 '%s_pythia.log' % tag)) 4454 pythiare = re.compile("\s*I\s+0 All included subprocesses\s+I\s+(?P<generated>\d+)\s+(?P<tried>\d+)\s+I\s+(?P<xsec>[\d\.D\-+]+)\s+I") 4455 for line in pythia_log: 4456 info = pythiare.search(line) 4457 if not info: 4458 continue 4459 try: 4460 # Pythia cross section in mb, we want pb 4461 sigma_m = float(info.group('xsec').replace('D','E')) *1e9 4462 Nacc = int(info.group('generated')) 4463 Ntry = int(info.group('tried')) 4464 except ValueError: 4465 # xsec is not float - this should not happen 4466 self.results.add_detail('cross_pythia', 0) 4467 self.results.add_detail('nb_event_pythia', 0) 4468 self.results.add_detail('error_pythia', 0) 4469 else: 4470 self.results.add_detail('cross_pythia', sigma_m) 4471 self.results.add_detail('nb_event_pythia', Nacc) 4472 #compute pythia error 4473 error = self.results[self.run_name].return_tag(self.run_tag)['error'] 4474 if Nacc: 4475 error_m = math.sqrt((error * Nacc/Ntry)**2 + sigma_m**2 *(1-Nacc/Ntry)/Nacc) 4476 else: 4477 error_m = 10000 * sigma_m 4478 # works both for fixed number of generated events and fixed accepted events 4479 self.results.add_detail('error_pythia', error_m) 4480 break 4481 4482 pythia_log.close() 4483 4484 pydir = pjoin(self.options['pythia-pgs_path'], 'src') 4485 eradir = self.options['exrootanalysis_path'] 4486 madir = self.options['madanalysis_path'] 4487 td = self.options['td_path'] 4488 4489 #Update the banner 4490 self.banner.add(pjoin(self.me_dir, 'Cards','pythia_card.dat')) 4491 if int(self.run_card['ickkw']): 4492 # Add the matched cross-section 4493 if 'MGGenerationInfo' in self.banner: 4494 self.banner['MGGenerationInfo'] += '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 4495 else: 4496 self.banner['MGGenerationInfo'] = '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 4497 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)) 4498 self.banner.write(banner_path) 4499 4500 # Creating LHE file 4501 self.run_hep2lhe(banner_path) 4502 4503 if int(self.run_card['ickkw']): 4504 misc.gzip(pjoin(self.me_dir,'Events','beforeveto.tree'), 4505 stdout=pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_beforeveto.tree.gz')) 4506 4507 4508 if self.run_card['use_syst'] in self.true: 4509 # Calculate syscalc info based on syst.dat 4510 try: 4511 self.run_syscalc('Pythia') 4512 except SysCalcError, error: 4513 logger.error(str(error)) 4514 else: 4515 if os.path.exists(pjoin(self.me_dir,'Events', 'syst.dat')): 4516 # Store syst.dat 4517 misc.gzip(pjoin(self.me_dir,'Events', 'syst.dat'), 4518 stdout=pjoin(self.me_dir,'Events',self.run_name, tag + '_pythia_syst.dat.gz')) 4519 4520 # Store syscalc.dat 4521 if os.path.exists(pjoin(self.me_dir, 'Events', 'syscalc.dat')): 4522 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 4523 '%s_syscalc.dat' % self.run_tag) 4524 misc.gzip(pjoin(self.me_dir, 'Events','syscalc.dat'), 4525 stdout = "%s.gz" % filename) 4526 4527 # Plot for pythia 4528 self.create_plot('Pythia') 4529 4530 if os.path.exists(pjoin(self.me_dir,'Events','pythia_events.lhe')): 4531 misc.gzip(pjoin(self.me_dir,'Events','pythia_events.lhe'), 4532 stdout=pjoin(self.me_dir,'Events', self.run_name,'%s_pythia_events.lhe.gz' % tag)) 4533 4534 self.update_status('finish', level='pythia', makehtml=False) 4535 self.exec_cmd('pgs --no_default', postcmd=False, printcmd=False) 4536 if self.options['delphes_path']: 4537 self.exec_cmd('delphes --no_default', postcmd=False, printcmd=False) 4538 self.print_results_in_shell(self.results.current)
4539 4540 4541 ################################################################################
4542 - def do_remove(self, line):
4543 """Remove one/all run or only part of it""" 4544 4545 args = self.split_arg(line) 4546 run, tag, mode = self.check_remove(args) 4547 if 'banner' in mode: 4548 mode.append('all') 4549 4550 4551 if run == 'all': 4552 # Check first if they are not a run with a name run. 4553 if os.path.exists(pjoin(self.me_dir, 'Events', 'all')): 4554 logger.warning('A run with name all exists. So we will not supress all processes.') 4555 else: 4556 for match in misc.glob(pjoin('*','*_banner.txt'), pjoin(self.me_dir, 'Events')): 4557 run = match.rsplit(os.path.sep,2)[1] 4558 if self.force: 4559 args.append('-f') 4560 try: 4561 self.exec_cmd('remove %s %s' % (run, ' '.join(args[1:]) ) ) 4562 except self.InvalidCmd, error: 4563 logger.info(error) 4564 pass # run already clear 4565 return 4566 4567 # Check that run exists 4568 if not os.path.exists(pjoin(self.me_dir, 'Events', run)): 4569 raise self.InvalidCmd('No run \'%s\' detected' % run) 4570 4571 try: 4572 self.resuls.def_current(run) 4573 self.update_status(' Cleaning %s' % run, level=None) 4574 except Exception: 4575 misc.sprint('fail to update results or html status') 4576 pass # Just ensure that html never makes crash this function 4577 4578 4579 # Found the file to delete 4580 4581 to_delete = misc.glob('*', pjoin(self.me_dir, 'Events', run)) 4582 to_delete += misc.glob('*', pjoin(self.me_dir, 'HTML', run)) 4583 # forbid the banner to be removed 4584 to_delete = [os.path.basename(f) for f in to_delete if 'banner' not in f] 4585 if tag: 4586 to_delete = [f for f in to_delete if tag in f] 4587 if 'parton' in mode or 'all' in mode: 4588 try: 4589 if self.results[run][0]['tag'] != tag: 4590 raise Exception, 'dummy' 4591 except Exception: 4592 pass 4593 else: 4594 nb_rm = len(to_delete) 4595 if os.path.exists(pjoin(self.me_dir, 'Events', run, 'events.lhe.gz')): 4596 to_delete.append('events.lhe.gz') 4597 if os.path.exists(pjoin(self.me_dir, 'Events', run, 'unweighted_events.lhe.gz')): 4598 to_delete.append('unweighted_events.lhe.gz') 4599 if os.path.exists(pjoin(self.me_dir, 'HTML', run,'plots_parton.html')): 4600 to_delete.append(pjoin(self.me_dir, 'HTML', run,'plots_parton.html')) 4601 if nb_rm != len(to_delete): 4602 logger.warning('Be carefull that partonic information are on the point to be removed.') 4603 if 'all' in mode: 4604 pass # delete everything 4605 else: 4606 if 'pythia' not in mode: 4607 to_delete = [f for f in to_delete if 'pythia' not in f] 4608 if 'pgs' not in mode: 4609 to_delete = [f for f in to_delete if 'pgs' not in f] 4610 if 'delphes' not in mode: 4611 to_delete = [f for f in to_delete if 'delphes' not in f] 4612 if 'parton' not in mode: 4613 to_delete = [f for f in to_delete if 'delphes' in f 4614 or 'pgs' in f 4615 or 'pythia' in f] 4616 if not self.force and len(to_delete): 4617 question = 'Do you want to delete the following files?\n %s' % \ 4618 '\n '.join(to_delete) 4619 ans = self.ask(question, 'y', choices=['y','n']) 4620 else: 4621 ans = 'y' 4622 4623 if ans == 'y': 4624 for file2rm in to_delete: 4625 if os.path.exists(pjoin(self.me_dir, 'Events', run, file2rm)): 4626 try: 4627 os.remove(pjoin(self.me_dir, 'Events', run, file2rm)) 4628 except Exception: 4629 shutil.rmtree(pjoin(self.me_dir, 'Events', run, file2rm)) 4630 else: 4631 try: 4632 os.remove(pjoin(self.me_dir, 'HTML', run, file2rm)) 4633 except Exception: 4634 shutil.rmtree(pjoin(self.me_dir, 'HTML', run, file2rm)) 4635 4636 4637 4638 # Remove file in SubProcess directory 4639 if 'all' in mode or 'channel' in mode: 4640 try: 4641 if tag and self.results[run][0]['tag'] != tag: 4642 raise Exception, 'dummy' 4643 except Exception: 4644 pass 4645 else: 4646 to_delete = misc.glob('%s*' % run, pjoin(self.me_dir, 'SubProcesses')) 4647 to_delete += misc.glob(pjoin('*','%s*' % run), pjoin(self.me_dir, 'SubProcesses')) 4648 to_delete += misc.glob(pjoin('*','*','%s*' % run), pjoin(self.me_dir, 'SubProcesses')) 4649 4650 if self.force or len(to_delete) == 0: 4651 ans = 'y' 4652 else: 4653 question = 'Do you want to delete the following files?\n %s' % \ 4654 '\n '.join(to_delete) 4655 ans = self.ask(question, 'y', choices=['y','n']) 4656 4657 if ans == 'y': 4658 for file2rm in to_delete: 4659 os.remove(file2rm) 4660 4661 if 'banner' in mode: 4662 to_delete = misc.glob('*', pjoin(self.me_dir, 'Events', run)) 4663 if tag: 4664 # remove banner 4665 try: 4666 os.remove(pjoin(self.me_dir, 'Events',run,'%s_%s_banner.txt' % (run,tag))) 4667 except Exception: 4668 logger.warning('fail to remove the banner') 4669 # remove the run from the html output 4670 if run in self.results: 4671 self.results.delete_run(run, tag) 4672 return 4673 elif any(['banner' not in os.path.basename(p) for p in to_delete]): 4674 if to_delete: 4675 raise MadGraph5Error, '''Some output still exists for this run. 4676 Please remove those output first. Do for example: 4677 remove %s all banner 4678 ''' % run 4679 else: 4680 shutil.rmtree(pjoin(self.me_dir, 'Events',run)) 4681 if run in self.results: 4682 self.results.delete_run(run) 4683 return 4684 else: 4685 logger.info('''The banner is not removed. In order to remove it run: 4686 remove %s all banner %s''' % (run, tag and '--tag=%s ' % tag or '')) 4687 4688 # update database. 4689 self.results.clean(mode, run, tag) 4690 self.update_status('', level='all')
4691 4692 4693 4694 ############################################################################
4695 - def do_plot(self, line):
4696 """Create the plot for a given run""" 4697 4698 # Since in principle, all plot are already done automaticaly 4699 self.store_result() 4700 args = self.split_arg(line) 4701 # Check argument's validity 4702 self.check_plot(args) 4703 logger.info('plot for run %s' % self.run_name) 4704 if not self.force: 4705 self.ask_edit_cards([], args, plot=True) 4706 4707 if any([arg in ['all','parton'] for arg in args]): 4708 filename = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe') 4709 if os.path.exists(filename+'.gz'): 4710 misc.gunzip('%s.gz' % filename, keep=True) 4711 if os.path.exists(filename): 4712 files.ln(filename, pjoin(self.me_dir, 'Events')) 4713 self.create_plot('parton') 4714 if not os.path.exists(filename+'.gz'): 4715 misc.gzip(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), 4716 stdout= "%s.gz" % filename) 4717 else: 4718 try: 4719 os.remove(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')) 4720 os.remove(filename) 4721 except Exception: 4722 pass 4723 else: 4724 logger.info('No valid files for partonic plot') 4725 4726 if any([arg in ['all','pythia'] for arg in args]): 4727 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 4728 '%s_pythia_events.lhe' % self.run_tag) 4729 if os.path.exists(filename+'.gz'): 4730 misc.gunzip("%s.gz" % filename) 4731 if os.path.exists(filename): 4732 shutil.move(filename, pjoin(self.me_dir, 'Events','pythia_events.lhe')) 4733 self.create_plot('Pythia') 4734 misc.gzip(pjoin(self.me_dir, 'Events','pythia_events.lhe'), 4735 stdout= "%s.gz" % filename) 4736 else: 4737 logger.info('No valid files for pythia plot') 4738 4739 4740 if any([arg in ['all','pgs'] for arg in args]): 4741 filename = pjoin(self.me_dir, 'Events', self.run_name, 4742 '%s_pgs_events.lhco' % self.run_tag) 4743 if os.path.exists(filename+'.gz'): 4744 misc.gunzip("%s.gz" % filename) 4745 if os.path.exists(filename): 4746 self.create_plot('PGS') 4747 misc.gzip(filename) 4748 else: 4749 logger.info('No valid files for pgs plot') 4750 4751 if any([arg in ['all','delphes'] for arg in args]): 4752 filename = pjoin(self.me_dir, 'Events', self.run_name, 4753 '%s_delphes_events.lhco' % self.run_tag) 4754 if os.path.exists(filename+'.gz'): 4755 misc.gunzip("%s.gz" % filename) 4756 if os.path.exists(filename): 4757 self.create_plot('Delphes') 4758 misc.gzip(filename) 4759 else: 4760 logger.info('No valid files for delphes plot')
4761 4762 ############################################################################
4763 - def do_syscalc(self, line):
4764 """Evaluate systematics variation weights for a given run""" 4765 4766 # Since in principle, all systematics run are already done automaticaly 4767 self.store_result() 4768 args = self.split_arg(line) 4769 # Check argument's validity 4770 self.check_syscalc(args) 4771 if self.ninitial == 1: 4772 logger.error('SysCalc can\'t be run for decay processes') 4773 return 4774 4775 logger.info('Calculating systematics for run %s' % self.run_name) 4776 4777 self.ask_edit_cards(['run_card'], args) 4778 self.run_card = banner_mod.RunCard(pjoin(self.me_dir, 'Cards', 'run_card.dat')) 4779 if any([arg in ['all','parton'] for arg in args]): 4780 filename = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe') 4781 if os.path.exists(filename+'.gz'): 4782 misc.gunzip("%s.gz" % filename) 4783 if os.path.exists(filename): 4784 shutil.move(filename, pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')) 4785 self.run_syscalc('parton') 4786 misc.gzip(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), 4787 stdout="%s.gz" % filename) 4788 else: 4789 logger.info('No valid files for parton level systematics run.') 4790 4791 if any([arg in ['all','pythia'] for arg in args]): 4792 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 4793 '%s_pythia_syst.dat' % self.run_tag) 4794 if os.path.exists(filename+'.gz'): 4795 misc.gunzip("%s.gz" % filename) 4796 if os.path.exists(filename): 4797 shutil.move(filename, pjoin(self.me_dir, 'Events','syst.dat')) 4798 try: 4799 self.run_syscalc('Pythia') 4800 except SysCalcError, error: 4801 logger.warning(str(error)) 4802 return 4803 misc.gzip(pjoin(self.me_dir, 'Events','syst.dat'), "%s.gz" % filename) 4804 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 4805 '%s_syscalc.dat' % self.run_tag) 4806 misc.gzip(pjoin(self.me_dir, 'Events','syscalc.dat'), 4807 stdout=filename) 4808 else: 4809 logger.info('No valid files for pythia level')
4810 4811
4812 - def store_result(self):
4813 """ tar the pythia results. This is done when we are quite sure that 4814 the pythia output will not be use anymore """ 4815 4816 if not self.run_name: 4817 return 4818 4819 self.results.save() 4820 4821 4822 if not self.to_store: 4823 return 4824 4825 tag = self.run_card['run_tag'] 4826 self.update_status('storing files of previous run', level=None,\ 4827 error=True) 4828 if 'event' in self.to_store: 4829 if not os.path.exists(pjoin(self.me_dir, 'Events',self.run_name, 'unweighted_events.lhe.gz')) and\ 4830 os.path.exists(pjoin(self.me_dir, 'Events',self.run_name, 'unweighted_events.lhe')): 4831 logger.info("gzipping output file: unweighted_events.lhe") 4832 misc.gzip(pjoin(self.me_dir,'Events',self.run_name,"unweighted_events.lhe")) 4833 if os.path.exists(pjoin(self.me_dir,'Events','reweight.lhe')): 4834 os.remove(pjoin(self.me_dir,'Events', 'reweight.lhe')) 4835 4836 if 'pythia' in self.to_store: 4837 self.update_status('Storing Pythia files of previous run', level='pythia', error=True) 4838 4839 p = pjoin(self.me_dir,'Events') 4840 n = self.run_name 4841 t = tag 4842 self.to_store.remove('pythia') 4843 misc.gzip(pjoin(p,'pythia_events.hep'), 4844 stdout=pjoin(p, str(n),'%s_pythia_events.hep' % t)) 4845 4846 if 'pythia8' in self.to_store: 4847 p = pjoin(self.me_dir,'Events') 4848 n = self.run_name 4849 t = tag 4850 file_path = pjoin(p, n ,'%s_pythia8_events.hepmc'%t) 4851 self.to_store.remove('pythia8') 4852 if os.path.isfile(file_path): 4853 self.update_status('Storing Pythia8 files of previous run', 4854 level='pythia', error=True) 4855 misc.gzip(file_path,stdout=file_path) 4856 4857 self.update_status('Done', level='pythia',makehtml=False,error=True) 4858 4859 self.to_store = []
4860
4861 - def launch_job(self,exe, cwd=None, stdout=None, argument = [], remaining=0, 4862 run_type='', mode=None, **opt):
4863 """ """ 4864 argument = [str(arg) for arg in argument] 4865 if mode is None: 4866 mode = self.cluster_mode 4867 4868 # ensure that exe is executable 4869 if os.path.exists(exe) and not os.access(exe, os.X_OK): 4870 os.system('chmod +x %s ' % exe) 4871 elif (cwd and os.path.exists(pjoin(cwd, exe))) and not \ 4872 os.access(pjoin(cwd, exe), os.X_OK): 4873 os.system('chmod +x %s ' % pjoin(cwd, exe)) 4874 4875 if mode == 0: 4876 self.update_status((remaining, 1, 4877 self.total_jobs - remaining -1, run_type), level=None, force=False) 4878 start = time.time() 4879 #os.system('cd %s; ./%s' % (cwd,exe)) 4880 status = misc.call([exe] + argument, cwd=cwd, stdout=stdout, **opt) 4881 logger.info('%s run in %f s' % (exe, time.time() -start)) 4882 if status: 4883 raise MadGraph5Error, '%s didn\'t stop properly. Stop all computation' % exe 4884 4885 4886 elif mode in [1,2]: 4887 exename = os.path.basename(exe) 4888 # For condor cluster, create the input/output files 4889 if 'ajob' in exename: 4890 input_files = ['madevent','input_app.txt','symfact.dat','iproc.dat', 4891 pjoin(self.me_dir, 'SubProcesses','randinit')] 4892 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 4893 'MadLoop5_resources.tar.gz')) and cluster.need_transfer(self.options): 4894 input_files.append(pjoin(self.me_dir,'SubProcesses', 'MadLoop5_resources.tar.gz')) 4895 4896 output_files = [] 4897 required_output = [] 4898 4899 4900 #Find the correct PDF input file 4901 input_files.append(self.get_pdf_input_filename()) 4902 4903 #Find the correct ajob 4904 Gre = re.compile("\s*j=(G[\d\.\w]+)") 4905 origre = re.compile("grid_directory=(G[\d\.\w]+)") 4906 try : 4907 fsock = open(exe) 4908 except Exception: 4909 fsock = open(pjoin(cwd,exe)) 4910 text = fsock.read() 4911 output_files = Gre.findall(text) 4912 if not output_files: 4913 Ire = re.compile("for i in ([\d\.\s]*) ; do") 4914 data = Ire.findall(text) 4915 data = ' '.join(data).split() 4916 for nb in data: 4917 output_files.append('G%s' % nb) 4918 required_output.append('G%s/results.dat' % nb) 4919 else: 4920 for G in output_files: 4921 if os.path.isdir(pjoin(cwd,G)): 4922 input_files.append(G) 4923 required_output.append('%s/results.dat' % G) 4924 4925 if origre.search(text): 4926 G_grid = origre.search(text).groups()[0] 4927 input_files.append(pjoin(G_grid, 'ftn26')) 4928 4929 #submitting 4930 self.cluster.submit2(exe, stdout=stdout, cwd=cwd, 4931 input_files=input_files, output_files=output_files, 4932 required_output=required_output) 4933 elif 'survey' in exename: 4934 input_files = ['madevent','input_app.txt','symfact.dat','iproc.dat', 4935 pjoin(self.me_dir, 'SubProcesses','randinit')] 4936 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 4937 'MadLoop5_resources.tar.gz')) and cluster.need_transfer(self.options): 4938 input_files.append(pjoin(self.me_dir,'SubProcesses', 4939 'MadLoop5_resources.tar.gz')) 4940 4941 #Find the correct PDF input file 4942 input_files.append(self.get_pdf_input_filename()) 4943 4944 4945 output_files = [] 4946 required_output = [] 4947 4948 #Find the correct ajob 4949 suffix = "_%s" % int(float(argument[0])) 4950 if suffix == '_0': 4951 suffix = '' 4952 output_files = ['G%s%s' % (i, suffix) for i in argument[1:]] 4953 for G in output_files: 4954 required_output.append('%s/results.dat' % G) 4955 4956 # add the grid information if needed 4957 for G in output_files: 4958 if '.' in argument[0]: 4959 offset = int(str(argument[0]).split('.')[1]) 4960 else: 4961 offset = 0 4962 4963 if offset ==0 or offset == int(float(argument[0])): 4964 if os.path.exists(pjoin(cwd, G, 'input_app.txt')): 4965 os.remove(pjoin(cwd, G, 'input_app.txt')) 4966 4967 if os.path.exists(os.path.realpath(pjoin(cwd, G, 'ftn25'))): 4968 if offset == 0 or offset == int(float(argument[0])): 4969 os.remove(pjoin(cwd, G, 'ftn25')) 4970 continue 4971 else: 4972 input_files.append(pjoin(cwd, G, 'ftn25')) 4973 input_files.remove('input_app.txt') 4974 input_files.append(pjoin(cwd, G, 'input_app.txt')) 4975 elif os.path.lexists(pjoin(cwd, G, 'ftn25')): 4976 try: 4977 os.remove(pjoin(cwd,G,'ftn25')) 4978 except: 4979 pass 4980 4981 #submitting 4982 self.cluster.cluster_submit(exe, stdout=stdout, cwd=cwd, argument=argument, 4983 input_files=input_files, output_files=output_files, 4984 required_output=required_output, **opt) 4985 elif "refine_splitted.sh" in exename: 4986 input_files = ['madevent','symfact.dat','iproc.dat', 4987 pjoin(self.me_dir, 'SubProcesses','randinit')] 4988 4989 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 4990 'MadLoop5_resources.tar.gz')) and cluster.need_transfer(self.options): 4991 input_files.append(pjoin(self.me_dir,'SubProcesses', 4992 'MadLoop5_resources.tar.gz')) 4993 4994 #Find the correct PDF input file 4995 input_files.append(self.get_pdf_input_filename()) 4996 4997 4998 output_files = [argument[0]] 4999 required_output = [] 5000 for G in output_files: 5001 required_output.append('%s/results.dat' % G) 5002 input_files.append(pjoin(argument[1], "input_app.txt")) 5003 input_files.append(pjoin(argument[1], "ftn26")) 5004 5005 #submitting 5006 self.cluster.cluster_submit(exe, stdout=stdout, cwd=cwd, argument=argument, 5007 input_files=input_files, output_files=output_files, 5008 required_output=required_output, **opt) 5009 5010 5011 5012 else: 5013 self.cluster.submit(exe, argument=argument, stdout=stdout, cwd=cwd, **opt)
5014 5015 5016 ############################################################################
5017 - def find_madevent_mode(self):
5018 """Find if Madevent is in Group mode or not""" 5019 5020 # The strategy is too look in the files Source/run_configs.inc 5021 # if we found: ChanPerJob=3 then it's a group mode. 5022 file_path = pjoin(self.me_dir, 'Source', 'run_config.inc') 5023 text = open(file_path).read() 5024 if re.search(r'''s*parameter\s+\(ChanPerJob=2\)''', text, re.I+re.M): 5025 return 'group' 5026 else: 5027 return 'v4'
5028 5029 ############################################################################
5030 - def monitor(self, run_type='monitor', mode=None, html=False):
5031 """ monitor the progress of running job """ 5032 5033 5034 starttime = time.time() 5035 if mode is None: 5036 mode = self.cluster_mode 5037 if mode > 0: 5038 if html: 5039 update_status = lambda idle, run, finish: \ 5040 self.update_status((idle, run, finish, run_type), level=None, 5041 force=False, starttime=starttime) 5042 update_first = lambda idle, run, finish: \ 5043 self.update_status((idle, run, finish, run_type), level=None, 5044 force=True, starttime=starttime) 5045 else: 5046 update_status = lambda idle, run, finish: None 5047 update_first = None 5048 try: 5049 self.cluster.wait(self.me_dir, update_status, update_first=update_first) 5050 except Exception, error: 5051 logger.info(error) 5052 if not self.force: 5053 ans = self.ask('Cluster Error detected. Do you want to clean the queue? ("c"=continue the run anyway)', 5054 default = 'y', choices=['y','n', 'c']) 5055 else: 5056 ans = 'y' 5057 if ans == 'y': 5058 self.cluster.remove() 5059 elif ans == 'c': 5060 return self.monitor(run_type=run_type, mode=mode, html=html) 5061 raise 5062 except KeyboardInterrupt, error: 5063 self.cluster.remove() 5064 raise
5065 5066 5067 5068 ############################################################################
5069 - def configure_directory(self, html_opening=True):
5070 """ All action require before any type of run """ 5071 5072 # Basic check 5073 assert os.path.exists(pjoin(self.me_dir,'SubProcesses')) 5074 5075 # environmental variables to be included in make_opts 5076 self.make_opts_var = {} 5077 5078 #see when the last file was modified 5079 time_mod = max([os.path.getctime(pjoin(self.me_dir,'Cards','run_card.dat')), 5080 os.path.getctime(pjoin(self.me_dir,'Cards','param_card.dat'))]) 5081 if self.configured > time_mod and hasattr(self, 'random'): 5082 return 5083 else: 5084 self.configured = time.time() 5085 self.update_status('compile directory', level=None, update_results=True) 5086 if self.options['automatic_html_opening'] and html_opening: 5087 misc.open_file(os.path.join(self.me_dir, 'crossx.html')) 5088 self.options['automatic_html_opening'] = False 5089 #open only once the web page 5090 # Change current working directory 5091 self.launching_dir = os.getcwd() 5092 5093 # Check if we need the MSSM special treatment 5094 model = self.find_model_name() 5095 if model == 'mssm' or model.startswith('mssm-'): 5096 param_card = pjoin(self.me_dir, 'Cards','param_card.dat') 5097 mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat') 5098 check_param_card.convert_to_mg5card(param_card, mg5_param) 5099 check_param_card.check_valid_param_card(mg5_param) 5100 5101 # limit the number of event to 100k 5102 self.check_nb_events() 5103 5104 # this is in order to avoid conflicts between runs with and without 5105 # lhapdf 5106 misc.compile(['clean4pdf'], cwd = pjoin(self.me_dir, 'Source')) 5107 5108 # set lhapdf. 5109 if self.run_card['pdlabel'] == "lhapdf": 5110 self.make_opts_var['lhapdf'] = 'True' 5111 self.link_lhapdf(pjoin(self.me_dir,'lib')) 5112 pdfsetsdir = self.get_lhapdf_pdfsetsdir() 5113 lhaid_list = [int(self.run_card['lhaid'])] 5114 self.copy_lhapdf_set(lhaid_list, pdfsetsdir) 5115 if self.run_card['pdlabel'] != "lhapdf": 5116 self.pdffile = None 5117 self.make_opts_var['lhapdf'] = "" 5118 5119 # set random number 5120 if self.run_card['iseed'] != 0: 5121 self.random = int(self.run_card['iseed']) 5122 self.run_card['iseed'] = 0 5123 # Reset seed in run_card to 0, to ensure that following runs 5124 # will be statistically independent 5125 self.run_card.write(pjoin(self.me_dir, 'Cards','run_card.dat')) 5126 elif os.path.exists(pjoin(self.me_dir,'SubProcesses','randinit')): 5127 for line in open(pjoin(self.me_dir,'SubProcesses','randinit')): 5128 data = line.split('=') 5129 assert len(data) ==2 5130 self.random = int(data[1]) 5131 break 5132 else: 5133 self.random = random.randint(1, 30107) 5134 5135 if self.run_card['ickkw'] == 2: 5136 logger.info('Running with CKKW matching') 5137 self.treat_ckkw_matching() 5138 5139 # add the make_opts_var to make_opts 5140 self.update_make_opts() 5141 5142 # create param_card.inc and run_card.inc 5143 self.do_treatcards('') 5144 5145 logger.info("compile Source Directory") 5146 5147 # Compile 5148 for name in [ 'all', '../bin/internal/combine_events']: 5149 self.compile(arg=[name], cwd=os.path.join(self.me_dir, 'Source')) 5150 5151 bias_name = os.path.basename(self.run_card['bias_module']) 5152 if bias_name.lower()=='none': 5153 bias_name = 'dummy' 5154 5155 # Always refresh the bias dependencies file 5156 if os.path.exists(pjoin(self.me_dir, 'SubProcesses','bias_dependencies')): 5157 os.remove(pjoin(self.me_dir, 'SubProcesses','bias_dependencies')) 5158 if os.path.exists(pjoin(self.me_dir, 'Source','BIAS',bias_name,'bias_dependencies')): 5159 files.ln(pjoin(self.me_dir, 'Source','BIAS',bias_name,'bias_dependencies'), 5160 pjoin(self.me_dir, 'SubProcesses')) 5161 5162 if self.proc_characteristics['bias_module']!=bias_name and \ 5163 os.path.isfile(pjoin(self.me_dir, 'lib','libbias.a')): 5164 os.remove(pjoin(self.me_dir, 'lib','libbias.a')) 5165 5166 # Finally compile the bias module as well 5167 if self.run_card['bias_module']!='dummy': 5168 logger.debug("Compiling the bias module '%s'"%bias_name) 5169 # Verify the compatibility of the specified module 5170 bias_module_valid = misc.Popen(['make','requirements'], 5171 cwd=os.path.join(self.me_dir, 'Source','BIAS',bias_name), 5172 stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] 5173 if 'VALID' not in bias_module_valid.upper() or \ 5174 'INVALID' in bias_module_valid.upper(): 5175 raise InvalidCmd("The bias module '%s' cannot be used because of:\n%s"% 5176 (bias_name,bias_module_valid)) 5177 5178 self.compile(arg=[], cwd=os.path.join(self.me_dir, 'Source','BIAS',bias_name)) 5179 self.proc_characteristics['bias_module']=bias_name 5180 # Update the proc_characterstics file 5181 self.proc_characteristics.write( 5182 pjoin(self.me_dir,'SubProcesses','proc_characteristics')) 5183 # Make sure that madevent will be recompiled 5184 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 5185 'subproc.mg'))] 5186 for nb_proc,subdir in enumerate(subproc): 5187 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir.strip()) 5188 self.compile(['clean'], cwd=Pdir)
5189 5190 ############################################################################ 5191 ## HELPING ROUTINE 5192 ############################################################################ 5193 @staticmethod
5194 - def check_dir(path, default=''):
5195 """check if the directory exists. if so return the path otherwise the 5196 default""" 5197 5198 if os.path.isdir(path): 5199 return path 5200 else: 5201 return default
5202 5203 ############################################################################
5204 - def get_Pdir(self):
5205 """get the list of Pdirectory if not yet saved.""" 5206 5207 if hasattr(self, "Pdirs"): 5208 if self.me_dir in self.Pdirs[0]: 5209 return self.Pdirs 5210 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip()) 5211 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))] 5212 return self.Pdirs
5213 5214 ############################################################################
5215 - def get_Gdir(self):
5216 """get the list of Gdirectory if not yet saved.""" 5217 5218 if hasattr(self, "Gdirs"): 5219 if self.me_dir in self.Gdirs[0]: 5220 return self.Gdirs 5221 5222 Pdirs = self.get_Pdir() 5223 Gdirs = [] 5224 for P in Pdirs: 5225 for line in open(pjoin(P, "symfact.dat")): 5226 tag, mfactor = line.split() 5227 Gdirs.append( (pjoin(P, "G%s" % tag), int(mfactor)) ) 5228 5229 5230 self.Gdirs = Gdirs 5231 return self.Gdirs
5232 5233 ############################################################################
5234 - def set_run_name(self, name, tag=None, level='parton', reload_card=False, 5235 allow_new_tag=True):
5236 """define the run name, the run_tag, the banner and the results.""" 5237 5238 def get_last_tag(self, level): 5239 # Return the tag of the previous run having the required data for this 5240 # tag/run to working wel. 5241 if level == 'parton': 5242 return 5243 elif level in ['pythia','pythia8','madanalysis5_parton','madanalysis5_hadron']: 5244 return self.results[self.run_name][0]['tag'] 5245 else: 5246 for i in range(-1,-len(self.results[self.run_name])-1,-1): 5247 tagRun = self.results[self.run_name][i] 5248 if tagRun.pythia or tagRun.shower or tagRun.pythia8 : 5249 return tagRun['tag']
5250 5251 5252 # when are we force to change the tag new_run:previous run requiring changes 5253 upgrade_tag = {'parton': ['parton','pythia','pgs','delphes','madanalysis5_hadron','madanalysis5_parton'], 5254 'pythia': ['pythia','pgs','delphes','madanalysis5_hadron'], 5255 'pythia8': ['pythia8','pgs','delphes','madanalysis5_hadron'], 5256 'pgs': ['pgs'], 5257 'delphes':['delphes'], 5258 'madanalysis5_hadron':['madanalysis5_hadron'], 5259 'madanalysis5_parton':['madanalysis5_parton'], 5260 'plot':[], 5261 'syscalc':[]} 5262 5263 if name == self.run_name: 5264 if reload_card: 5265 run_card = pjoin(self.me_dir, 'Cards','run_card.dat') 5266 self.run_card = banner_mod.RunCard(run_card) 5267 5268 #check if we need to change the tag 5269 if tag: 5270 self.run_card['run_tag'] = tag 5271 self.run_tag = tag 5272 self.results.add_run(self.run_name, self.run_card) 5273 else: 5274 for tag in upgrade_tag[level]: 5275 if getattr(self.results[self.run_name][-1], tag): 5276 tag = self.get_available_tag() 5277 self.run_card['run_tag'] = tag 5278 self.run_tag = tag 5279 self.results.add_run(self.run_name, self.run_card) 5280 break 5281 return get_last_tag(self, level) 5282 5283 5284 # save/clean previous run 5285 if self.run_name: 5286 self.store_result() 5287 # store new name 5288 self.run_name = name 5289 5290 new_tag = False 5291 # First call for this run -> set the banner 5292 self.banner = banner_mod.recover_banner(self.results, level, name) 5293 if 'mgruncard' in self.banner: 5294 self.run_card = self.banner.charge_card('run_card') 5295 else: 5296 # Read run_card 5297 run_card = pjoin(self.me_dir, 'Cards','run_card.dat') 5298 self.run_card = banner_mod.RunCard(run_card) 5299 5300 if tag: 5301 self.run_card['run_tag'] = tag 5302 new_tag = True 5303 elif not self.run_name in self.results and level =='parton': 5304 pass # No results yet, so current tag is fine 5305 elif not self.run_name in self.results: 5306 #This is only for case when you want to trick the interface 5307 logger.warning('Trying to run data on unknown run.') 5308 self.results.add_run(name, self.run_card) 5309 self.results.update('add run %s' % name, 'all', makehtml=False) 5310 else: 5311 for tag in upgrade_tag[level]: 5312 5313 if getattr(self.results[self.run_name][-1], tag): 5314 # LEVEL is already define in the last tag -> need to switch tag 5315 tag = self.get_available_tag() 5316 self.run_card['run_tag'] = tag 5317 new_tag = True 5318 break 5319 if not new_tag: 5320 # We can add the results to the current run 5321 tag = self.results[self.run_name][-1]['tag'] 5322 self.run_card['run_tag'] = tag # ensure that run_tag is correct 5323 5324 if allow_new_tag and (name in self.results and not new_tag): 5325 self.results.def_current(self.run_name) 5326 else: 5327 self.results.add_run(self.run_name, self.run_card) 5328 5329 self.run_tag = self.run_card['run_tag'] 5330 5331 return get_last_tag(self, level) 5332 5333 5334 ############################################################################
5335 - def find_model_name(self):
5336 """ return the model name """ 5337 if hasattr(self, 'model_name'): 5338 return self.model_name 5339 5340 model = 'sm' 5341 proc = [] 5342 for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')): 5343 line = line.split('#')[0] 5344 #line = line.split('=')[0] 5345 if line.startswith('import') and 'model' in line: 5346 model = line.split()[2] 5347 proc = [] 5348 elif line.startswith('generate'): 5349 proc.append(line.split(None,1)[1]) 5350 elif line.startswith('add process'): 5351 proc.append(line.split(None,2)[2]) 5352 5353 self.model = model 5354 self.process = proc 5355 return model
5356 5357 5358 ############################################################################
5359 - def check_nb_events(self):
5360 """Find the number of event in the run_card, and check that this is not 5361 too large""" 5362 5363 5364 nb_event = int(self.run_card['nevents']) 5365 if nb_event > 1000000: 5366 logger.warning("Attempting to generate more than 1M events") 5367 logger.warning("Limiting number to 1M. Use multi_run for larger statistics.") 5368 path = pjoin(self.me_dir, 'Cards', 'run_card.dat') 5369 os.system(r"""perl -p -i.bak -e "s/\d+\s*=\s*nevents/1000000 = nevents/" %s""" \ 5370 % path) 5371 self.run_card['nevents'] = 1000000 5372 5373 return
5374 5375 5376 ############################################################################
5377 - def update_random(self):
5378 """ change random number""" 5379 5380 self.random += 3 5381 if self.random > 30081*30081: # can't use too big random number 5382 raise MadGraph5Error,\ 5383 'Random seed too large ' + str(self.random) + ' > 30081*30081'
5384 5385 ############################################################################
5386 - def save_random(self):
5387 """save random number in appropirate file""" 5388 5389 fsock = open(pjoin(self.me_dir, 'SubProcesses','randinit'),'w') 5390 fsock.writelines('r=%s\n' % self.random)
5391
5392 - def do_quit(self, *args, **opts):
5393 5394 common_run.CommonRunCmd.do_quit(self, *args, **opts) 5395 return CmdExtended.do_quit(self, *args, **opts)
5396 5397 ############################################################################
5398 - def treat_CKKW_matching(self):
5399 """check for ckkw""" 5400 5401 lpp1 = self.run_card['lpp1'] 5402 lpp2 = self.run_card['lpp2'] 5403 e1 = self.run_card['ebeam1'] 5404 e2 = self.run_card['ebeam2'] 5405 pd = self.run_card['pdlabel'] 5406 lha = self.run_card['lhaid'] 5407 xq = self.run_card['xqcut'] 5408 translation = {'e1': e1, 'e2':e2, 'pd':pd, 5409 'lha':lha, 'xq':xq} 5410 5411 if lpp1 or lpp2: 5412 # Remove ':s from pd 5413 if pd.startswith("'"): 5414 pd = pd[1:] 5415 if pd.endswith("'"): 5416 pd = pd[:-1] 5417 5418 if xq >2 or xq ==2: 5419 xq = 2 5420 5421 # find data file 5422 if pd == "lhapdf": 5423 issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(lha)s-%(xq)s.dat.gz' 5424 else: 5425 issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(xq)s.dat.gz' 5426 if self.web: 5427 issudfile = pjoin(self.webbin, issudfile % translation) 5428 else: 5429 issudfile = pjoin(self.me_dir, issudfile % translation) 5430 5431 logger.info('Sudakov grid file: %s' % issudfile) 5432 5433 # check that filepath exists 5434 if os.path.exists(issudfile): 5435 path = pjoin(self.me_dir, 'lib', 'issudgrid.dat') 5436 misc.gunzip(issudfile, keep=True, stdout=path) 5437 else: 5438 msg = 'No sudakov grid file for parameter choice. Start to generate it. This might take a while' 5439 logger.info(msg) 5440 self.update_status('GENERATE SUDAKOV GRID', level='parton') 5441 5442 for i in range(-2,6): 5443 self.cluster.submit('%s/gensudgrid ' % self.dirbin, 5444 argument = ['%d'%i], 5445 cwd=self.me_dir, 5446 stdout=open(pjoin(self.me_dir, 'gensudgrid%s.log' % i),'w')) 5447 self.monitor() 5448 for i in range(-2,6): 5449 path = pjoin(self.me_dir, 'lib', 'issudgrid.dat') 5450 os.system('cat %s/gensudgrid%s.log >> %s' % (self.me_dir, path)) 5451 misc.gzip(path, stdout=issudfile)
5452 5453 ############################################################################
5454 - def create_root_file(self, input='unweighted_events.lhe', 5455 output='unweighted_events.root' ):
5456 """create the LHE root file """ 5457 self.update_status('Creating root files', level='parton') 5458 5459 eradir = self.options['exrootanalysis_path'] 5460 try: 5461 misc.call(['%s/ExRootLHEFConverter' % eradir, 5462 input, output], 5463 cwd=pjoin(self.me_dir, 'Events')) 5464 except Exception: 5465 logger.warning('fail to produce Root output [problem with ExRootAnalysis]')
5466
5467 - def run_syscalc(self, mode='parton', event_path=None, output=None):
5468 """create the syscalc output""" 5469 5470 if self.run_card['use_syst'] not in self.true: 5471 return 5472 5473 scdir = self.options['syscalc_path'] 5474 if not scdir or not os.path.exists(scdir): 5475 return 5476 5477 if self.run_card['event_norm'] != 'sum': 5478 logger.critical('SysCalc works only when event_norm is on \'sum\'.') 5479 return 5480 logger.info('running SysCalc on mode %s' % mode) 5481 5482 # Restore the old default for SysCalc+PY6 5483 if self.run_card['sys_matchscale']=='auto': 5484 self.run_card['sys_matchscale'] = "30 50" 5485 5486 # Check that all pdfset are correctly installed 5487 lhaid = [self.run_card.get_lhapdf_id()] 5488 sys_pdf = self.run_card['sys_pdf'].split('&&') 5489 lhaid += [l.split()[0] for l in sys_pdf] 5490 try: 5491 pdfsets_dir = self.get_lhapdf_pdfsetsdir() 5492 except Exception, error: 5493 logger.debug(str(error)) 5494 logger.warning('Systematic computation requires lhapdf to run. Bypass SysCalc') 5495 return 5496 5497 # Copy all the relevant PDF sets 5498 [self.copy_lhapdf_set([onelha], pdfsets_dir) for onelha in lhaid] 5499 5500 5501 5502 tag = self.run_card['run_tag'] 5503 card = pjoin(self.me_dir, 'bin','internal', 'syscalc_card.dat') 5504 template = open(pjoin(self.me_dir, 'bin','internal', 'syscalc_template.dat')).read() 5505 self.run_card['sys_pdf'] = self.run_card['sys_pdf'].split('#',1)[0].replace('&&',' \n ') 5506 5507 if self.run_card['sys_pdf'].lower() in ['', 'f', 'false', 'none', '.false.']: 5508 self.run_card['sys_pdf'] = '' 5509 if self.run_card['sys_alpsfact'].lower() in ['', 'f', 'false', 'none','.false.']: 5510 self.run_card['sys_alpsfact'] = '' 5511 5512 5513 5514 5515 # check if the scalecorrelation parameter is define: 5516 if not 'sys_scalecorrelation' in self.run_card: 5517 self.run_card['sys_scalecorrelation'] = -1 5518 open(card,'w').write(template % self.run_card) 5519 5520 if not os.path.exists(card): 5521 return False 5522 5523 5524 5525 event_dir = pjoin(self.me_dir, 'Events') 5526 5527 if not event_path: 5528 if mode == 'parton': 5529 event_path = pjoin(event_dir,self.run_name, 'unweighted_events.lhe') 5530 if not (os.path.exists(event_path) or os.path.exists(event_path+".gz")): 5531 event_path = pjoin(event_dir, 'unweighted_events.lhe') 5532 output = pjoin(event_dir, 'syscalc.lhe') 5533 stdout = open(pjoin(event_dir, self.run_name, '%s_systematics.log' % (mode)),'w') 5534 elif mode == 'Pythia': 5535 stdout = open(pjoin(event_dir, self.run_name, '%s_%s_syscalc.log' % (tag,mode)),'w') 5536 if 'mgpythiacard' in self.banner: 5537 pat = re.compile('''^\s*qcut\s*=\s*([\+\-\d.e]*)''', re.M+re.I) 5538 data = pat.search(self.banner['mgpythiacard']) 5539 if data: 5540 qcut = float(data.group(1)) 5541 xqcut = abs(self.run_card['xqcut']) 5542 for value in self.run_card['sys_matchscale'].split(): 5543 if float(value) < qcut: 5544 raise SysCalcError, 'qcut value for sys_matchscale lower than qcut in pythia_card. Bypass syscalc' 5545 if float(value) < xqcut: 5546 raise SysCalcError, 'qcut value for sys_matchscale lower than xqcut in run_card. Bypass syscalc' 5547 5548 5549 event_path = pjoin(event_dir,'syst.dat') 5550 output = pjoin(event_dir, 'syscalc.dat') 5551 else: 5552 raise self.InvalidCmd, 'Invalid mode %s' % mode 5553 5554 if not os.path.exists(event_path): 5555 if os.path.exists(event_path+'.gz'): 5556 misc.gunzip(event_path+'.gz') 5557 else: 5558 raise SysCalcError, 'Events file %s does not exits' % event_path 5559 5560 self.update_status('Calculating systematics for %s level' % mode, level = mode.lower()) 5561 try: 5562 proc = misc.call([os.path.join(scdir, 'sys_calc'), 5563 event_path, card, output], 5564 stdout = stdout, 5565 stderr = subprocess.STDOUT, 5566 cwd=event_dir) 5567 # Wait 5 s to make sure file is finished writing 5568 time.sleep(5) 5569 except OSError, error: 5570 logger.error('fail to run syscalc: %s. Please check that SysCalc is correctly installed.' % error) 5571 else: 5572 if not os.path.exists(output): 5573 logger.warning('SysCalc Failed. Please read the associate log to see the reason. Did you install the associate PDF set?') 5574 elif mode == 'parton': 5575 files.mv(output, event_path) 5576 5577 self.update_status('End syscalc for %s level' % mode, level = mode.lower(), 5578 makehtml=False) 5579 5580 return True
5581 5582 5583 5584 ############################################################################
5585 - def ask_run_configuration(self, mode=None, args=[]):
5586 """Ask the question when launching generate_events/multi_run""" 5587 5588 available_mode = ['0'] 5589 void = 'Not installed' 5590 switch_order = ['shower', 'detector', 'analysis', 'madspin', 'reweight'] 5591 5592 switch = dict((k, void) for k in switch_order) 5593 5594 description = {'shower': 'Choose the shower/hadronization program:', 5595 'detector': 'Choose the detector simulation program:', 5596 'madspin': 'Decay particles with the MadSpin module:', 5597 'reweight':'Add weights to events for different model hypothesis:', 5598 'analysis':'Run an analysis package on the events generated:' 5599 } 5600 5601 force_switch = {('shower', 'OFF'): {'detector': 'OFF'}, 5602 ('detector', 'PGS'): {'shower':'PYTHIA6'}, 5603 ('detector', 'DELPHES'): {'shower': ['PYTHIA8', 'PYTHIA6']}} 5604 5605 switch_assign = lambda key, value: switch.__setitem__(key, value if value \ 5606 in valid_options[key] else switch[key]) 5607 5608 valid_options = dict((k, ['OFF']) for k in switch_order) # track of all possible input for an entry 5609 options = ['auto', 'done'] 5610 options_legacy = [] 5611 5612 # Init the switch value according to the current status 5613 if self.options['pythia-pgs_path']: 5614 available_mode.append('1') 5615 available_mode.append('2') 5616 valid_options['shower'].append('PYTHIA6') 5617 valid_options['detector'].append('PGS') 5618 options_legacy += ['pythia', 'pgs', 'pythia=ON', 'pythia=OFF', 'pgs=ON', 'pgs=OFF'] 5619 if os.path.exists(pjoin(self.me_dir,'Cards','pythia_card.dat')): 5620 switch['shower'] = 'PYTHIA6' 5621 else: 5622 switch['shower'] = 'OFF' 5623 if os.path.exists(pjoin(self.me_dir,'Cards','pgs_card.dat')): 5624 switch['detector'] = 'PGS' 5625 else: 5626 switch['detector'] = 'OFF' 5627 5628 if self.options['pythia8_path']: 5629 available_mode.append('1') 5630 valid_options['shower'].append('PYTHIA8') 5631 if os.path.exists(pjoin(self.me_dir,'Cards','pythia8_card.dat')): 5632 switch['shower'] = 'PYTHIA8' 5633 elif switch['shower'] == void: 5634 switch['shower'] = 'OFF' 5635 5636 # MadAnalysis4 options 5637 if self.options['madanalysis_path']: 5638 if os.path.exists(pjoin(self.me_dir,'Cards','plot_card_default.dat')): 5639 valid_options['analysis'].insert(0,'MADANALYSIS_4') 5640 5641 if os.path.exists(pjoin(self.me_dir,'Cards','plot_card.dat')): 5642 switch['analysis'] = 'MADANALYSIS_4' 5643 5644 # MadAnalysis5 options 5645 if self.options['madanalysis5_path']: 5646 if os.path.exists(pjoin(self.me_dir,'Cards','madanalysis5_parton_card_default.dat')) or \ 5647 os.path.exists(pjoin(self.me_dir,'Cards','madanalysis5_hadron_card_default.dat')): 5648 valid_options['analysis'].append('MADANALYSIS_5') 5649 5650 parton_card_present = os.path.exists(pjoin(self.me_dir,'Cards', 5651 'madanalysis5_parton_card.dat')) 5652 hadron_card_present = os.path.exists(pjoin(self.me_dir,'Cards', 5653 'madanalysis5_hadron_card.dat')) 5654 if hadron_card_present or parton_card_present: 5655 switch['analysis'] = 'MADANALYSIS_5' 5656 5657 if len(valid_options['analysis'])>1: 5658 available_mode.append('5') 5659 if switch['analysis'] == void: 5660 switch['analysis'] = 'OFF' 5661 else: 5662 switch['analysis'] = 'No analysis tool interfaced to MG5aMC.' 5663 5664 # Need to allow Delphes only if a shower exists 5665 if self.options['delphes_path']: 5666 if valid_options['shower'] != ['OFF']: 5667 available_mode.append('2') 5668 valid_options['detector'].append('DELPHES') 5669 options += ['delphes', 'delphes=ON', 'delphes=OFF'] 5670 if os.path.exists(pjoin(self.me_dir,'Cards','delphes_card.dat')): 5671 switch['detector'] = 'DELPHES' 5672 else: 5673 switch['detector'] = 'OFF' 5674 elif valid_options['detector'] == ['OFF']: 5675 switch['detector'] = "Requires a shower" 5676 5677 # Check switch status for MS/reweight 5678 if not MADEVENT or ('mg5_path' in self.options and self.options['mg5_path']): 5679 available_mode.append('3') 5680 valid_options['madspin'] = ['ON', 'OFF'] 5681 if os.path.exists(pjoin(self.me_dir,'Cards','madspin_card.dat')): 5682 switch['madspin'] = 'ON' 5683 else: 5684 switch['madspin'] = 'OFF' 5685 if misc.has_f2py() or self.options['f2py_compiler']: 5686 available_mode.append('4') 5687 valid_options['reweight'] = ['ON', 'OFF'] 5688 if os.path.exists(pjoin(self.me_dir,'Cards','reweight_card.dat')): 5689 switch['reweight'] = 'ON' 5690 else: 5691 switch['reweight'] = 'OFF' 5692 else: 5693 switch['reweight'] = 'Not available (requires NumPy)' 5694 5695 if '-R' in args or '--reweight' in args: 5696 if switch['reweight'] == 'OFF': 5697 switch['reweight'] = 'ON' 5698 elif switch['reweight'] != 'ON': 5699 logger.critical("Cannot run reweight: %s", switch['reweight']) 5700 if '-M' in args or '--madspin' in args: 5701 if switch['madspin'] == 'OFF': 5702 switch['madspin'] = 'ON' 5703 elif switch['madspin'] != 'ON': 5704 logger.critical("Cannot run madspin: %s", switch['reweight']) 5705 5706 for id, key in enumerate(switch_order): 5707 if len(valid_options[key]) >1: 5708 options += ['%s=%s' % (key, s) for s in valid_options[key]] 5709 options.append(key) 5710 5711 options += ['parton'] + sorted(list(set(available_mode))) 5712 options += options_legacy 5713 #options += ['pythia=ON', 'pythia=OFF', 'delphes=ON', 'delphes=OFF', 'pgs=ON', 'pgs=OFF'] 5714 #ask the question 5715 5716 def color(switch_value): 5717 green = '\x1b[32m%s\x1b[0m' 5718 bold = '\x1b[33m%s\x1b[0m' 5719 red = '\x1b[31m%s\x1b[0m' 5720 if switch_value in ['OFF',void,'Requires a shower', 5721 'Not available (requires NumPy)', 5722 'Not available yet for this output/process']: 5723 return red%switch_value 5724 elif switch_value in ['ON','MADANALYSIS_4','MADANALYSIS_5', 5725 'PYTHIA8','PYTHIA6','PGS','DELPHES-ATLAS', 5726 'DELPHES-CMS','DELPHES']: 5727 return green%switch_value 5728 else: 5729 return bold%switch_value
5730 5731 if mode or not self.force: 5732 answer = '' 5733 while answer not in ['0', 'done', 'auto']: 5734 if mode: 5735 answer = mode 5736 else: 5737 switch_format = " \x1b[31m%i\x1b[0m. %-60s %12s = %s" 5738 question = "The following switches determine which programs are run:\n" 5739 question += '/'+'-'*98+'\\\n' 5740 for id, key in enumerate(switch_order): 5741 question += '| %-115s|\n'%(switch_format%(id+1, description[key], key, color(switch[key]))) 5742 question += '\\'+'-'*98+'/\n' 5743 question += ' Either type the switch number (1 to %s) to change its setting,\n' % (id+1) 5744 question += ' Set any switch explicitly (e.g. type \'madspin=ON\' at the prompt)\n' 5745 question += ' Type \'help\' for the list of all valid option\n' 5746 question += ' Type \'0\', \'auto\', \'done\' or just press enter when you are done.\n' 5747 answer = self.ask(question, '0', options, casesensitive=False) 5748 if (answer.isdigit() and answer != '0') or answer in ['shower', 'detector']: 5749 if answer.isdigit(): 5750 key = switch_order[int(answer) - 1] 5751 else: 5752 key = answer 5753 for i, opt in enumerate(valid_options[key]): 5754 if opt == switch[key]: 5755 break 5756 i +=1 5757 if i == len(valid_options[key]): 5758 i=0 5759 answer = '%s=%s' % (key, valid_options[key][i]) 5760 5761 if '=' in answer: 5762 key, status = answer.split('=') 5763 key, status = key.lower().strip(), status.upper().strip() 5764 5765 if key not in switch: 5766 # this means use use outdated switch. Use converter to new syntax 5767 logger.warning("Using old syntax. Please check that we run what you expect.") 5768 if key == "pythia" and status == "ON": 5769 key, status = "shower", "PYTHIA6" 5770 elif key == "pythia" and status == "OFF": 5771 key, status = "shower", "OFF" 5772 elif key == "pgs" and status == "ON": 5773 if switch["detector"] in ["OFF", "PGS"] : 5774 key, status = "detector", "PGS" 5775 else: 5776 key, status = "detector", "DELPHES+PGS" 5777 elif key == "delphes" and status == "ON": 5778 if switch["detector"] in ["OFF", "DELPHES"] : 5779 key, status = "detector", "DELPHES" 5780 else: 5781 key, status = "detector", "DELPHES+PGS" 5782 elif key == "pgs" and status == "OFF": 5783 if switch["detector"] in ["OFF", "PGS"] : 5784 key, status = "detector", "OFF" 5785 elif switch["detector"] == "DELPHES+PGS": 5786 key, status = "detector", "DELPHES" 5787 else: 5788 key, status = "detector", switch['detector'] 5789 elif key == "delphes" and status == "OFF": 5790 if switch["detector"] in ["OFF", "DELPHES"] : 5791 key, status = "detector", "OFF" 5792 elif switch["detector"] == "DELPHES+PGS": 5793 key, status = "detector", "PGS" 5794 else: 5795 key, status = "detector", switch['detector'] 5796 5797 5798 switch[key] = status 5799 if (key, status) in force_switch: 5800 for key2, status2 in force_switch[(key, status)].items(): 5801 if isinstance(status2, str): 5802 if switch[key2] not in [status2, void]: 5803 logger.info('For coherence \'%s\' is set to \'%s\'' 5804 % (key2, status2), '$MG:color:BLACK') 5805 switch[key2] = status2 5806 else: 5807 if switch[key2] not in status2 + [void]: 5808 logger.info('For coherence \'%s\' is set to \'%s\'' 5809 % (key2, status2[0]), '$MG:color:BLACK') 5810 switch[key2] = status2[0] 5811 elif answer in ['0', 'auto', 'done']: 5812 continue 5813 elif answer in ['parton', 'pythia','pgs','madspin','reweight', 'delphes']: 5814 logger.info('pass in %s only mode' % answer, '$MG:color:BLACK') 5815 switch_assign('madspin', 'OFF') 5816 switch_assign('reweight', 'OFF') 5817 if answer == 'parton': 5818 switch_assign('shower', 'OFF') 5819 switch_assign('detector', 'OFF') 5820 elif answer == 'pythia': 5821 switch_assign('shower', 'PYTHIA6') 5822 switch_assign('detector', 'OFF') 5823 elif answer == 'pgs': 5824 switch_assign('shower', 'PYTHIA6') 5825 switch_assign('detector', 'PGS') 5826 elif answer == 'delphes': 5827 switch_assign('shower', 'PYTHIA6') 5828 if switch['shower'] == 'OFF': 5829 switch_assign('shower', 'PYTHIA8') 5830 switch_assign('detector', 'DELPHES') 5831 elif answer == 'madspin': 5832 switch_assign('madspin', 'ON') 5833 switch_assign('shower', 'OFF') 5834 switch_assign('detector', 'OFF') 5835 elif answer == 'reweight': 5836 switch_assign('reweight', 'ON') 5837 switch_assign('shower', 'OFF') 5838 switch_assign('detector', 'OFF') 5839 5840 if mode: 5841 answer = '0' #mode auto didn't pass here (due to the continue) 5842 else: 5843 answer = 'auto' 5844 5845 # Now that we know in which mode we are check that all the card 5846 #exists (copy default if needed) 5847 5848 cards = ['param_card.dat', 'run_card.dat'] 5849 if switch['shower'] in ['PY6', 'PYTHIA6']: 5850 cards.append('pythia_card.dat') 5851 if switch['shower'] in ['PY8', 'PYTHIA8']: 5852 cards.append('pythia8_card.dat') 5853 if switch['detector'] in ['PGS','DELPHES+PGS']: 5854 cards.append('pgs_card.dat') 5855 if switch['detector'] in ['DELPHES', 'DELPHES+PGS']: 5856 cards.append('delphes_card.dat') 5857 delphes3 = True 5858 if os.path.exists(pjoin(self.options['delphes_path'], 'data')): 5859 delphes3 = False 5860 cards.append('delphes_trigger.dat') 5861 if switch['madspin'] == 'ON': 5862 cards.append('madspin_card.dat') 5863 if switch['reweight'] == 'ON': 5864 cards.append('reweight_card.dat') 5865 if switch['analysis'] in ['MADANALYSIS_5']: 5866 cards.append('madanalysis5_parton_card.dat') 5867 if switch['analysis'] in ['MADANALYSIS_5'] and not switch['shower']=='OFF': 5868 cards.append('madanalysis5_hadron_card.dat') 5869 if switch['analysis'] in ['MADANALYSIS_4']: 5870 cards.append('plot_card.dat') 5871 5872 self.keep_cards(cards) 5873 5874 if os.path.isfile(pjoin(self.me_dir,'Cards','MadLoopParams.dat')): 5875 cards.append('MadLoopParams.dat') 5876 5877 if self.force: 5878 self.check_param_card(pjoin(self.me_dir,'Cards','param_card.dat' )) 5879 return 5880 5881 if answer == 'auto': 5882 self.ask_edit_cards(cards, plot=False, mode='auto') 5883 else: 5884 self.ask_edit_cards(cards, plot=False) 5885 return 5886 5887 ############################################################################
5888 - def ask_pythia_run_configuration(self, mode=None, pythia_version=6):
5889 """Ask the question when launching pythia""" 5890 5891 pythia_suffix = '' if pythia_version==6 else '%d'%pythia_version 5892 5893 available_mode = ['0', '1'] 5894 if pythia_version==6: 5895 available_mode.append('2') 5896 if self.options['delphes_path']: 5897 available_mode.append('3') 5898 name = {'0': 'auto', '2':'pgs', '3':'delphes'} 5899 name['1'] = 'pythia%s'%pythia_suffix 5900 options = available_mode + [name[val] for val in available_mode] 5901 question = """Which programs do you want to run? 5902 0 / auto : running existing cards\n""" 5903 if pythia_version==6: 5904 question += """ 1. pythia : Pythia\n""" 5905 question += """ 2. pgs : Pythia + PGS\n""" 5906 else: 5907 question += """ 1. pythia8 : Pythia8\n""" 5908 5909 if '3' in available_mode: 5910 question += """ 3. delphes : Pythia%s + Delphes.\n"""%pythia_suffix 5911 5912 if not self.force: 5913 if not mode: 5914 mode = self.ask(question, '0', options) 5915 elif not mode: 5916 mode = 'auto' 5917 5918 if mode.isdigit(): 5919 mode = name[mode] 5920 5921 auto = False 5922 if mode == 'auto': 5923 auto = True 5924 if pythia_version==6 and os.path.exists(pjoin(self.me_dir, 5925 'Cards', 'pgs_card.dat')): 5926 mode = 'pgs' 5927 elif os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')): 5928 mode = 'delphes' 5929 else: 5930 mode = 'pythia%s'%pythia_suffix 5931 logger.info('Will run in mode %s' % mode) 5932 # Now that we know in which mode we are check that all the card 5933 #exists (copy default if needed) remove pointless one 5934 cards = ['pythia%s_card.dat'%pythia_suffix] 5935 if mode == 'pgs' and pythia_version==6: 5936 cards.append('pgs_card.dat') 5937 if mode == 'delphes': 5938 cards.append('delphes_card.dat') 5939 delphes3 = True 5940 if os.path.exists(pjoin(self.options['delphes_path'], 'data')): 5941 delphes3 = False 5942 cards.append('delphes_trigger.dat') 5943 self.keep_cards(cards, ignore=['madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat', 5944 'plot_card.dat']) 5945 5946 if self.force: 5947 return mode 5948 5949 if auto: 5950 self.ask_edit_cards(cards, mode='auto', plot=(pythia_version==6)) 5951 else: 5952 self.ask_edit_cards(cards, plot=(pythia_version==6)) 5953 5954 return mode
5955
5956 #=============================================================================== 5957 # MadEventCmd 5958 #=============================================================================== 5959 -class MadEventCmdShell(MadEventCmd, cmd.CmdShell):
5960 """The command line processor of MadGraph"""
5961
5962 5963 5964 #=============================================================================== 5965 # HELPING FUNCTION For Subprocesses 5966 #=============================================================================== 5967 -class SubProcesses(object):
5968 5969 name_to_pdg = {} 5970 5971 @classmethod
5972 - def clean(cls):
5973 cls.name_to_pdg = {}
5974 5975 @staticmethod
5976 - def get_subP(me_dir):
5977 """return the list of Subprocesses""" 5978 5979 out = [] 5980 for line in open(pjoin(me_dir,'SubProcesses', 'subproc.mg')): 5981 if not line: 5982 continue 5983 name = line.strip() 5984 if os.path.exists(pjoin(me_dir, 'SubProcesses', name)): 5985 out.append(pjoin(me_dir, 'SubProcesses', name)) 5986 5987 return out
5988 5989 5990 5991 @staticmethod
5992 - def get_subP_info(path):
5993 """ return the list of processes with their name""" 5994 5995 nb_sub = 0 5996 names = {} 5997 old_main = '' 5998 5999 if not os.path.exists(os.path.join(path,'processes.dat')): 6000 return SubProcesses.get_subP_info_v4(path) 6001 6002 for line in open(os.path.join(path,'processes.dat')): 6003 main = line[:8].strip() 6004 if main == 'mirror': 6005 main = old_main 6006 if line[8:].strip() == 'none': 6007 continue 6008 else: 6009 main = int(main) 6010 old_main = main 6011 6012 sub_proccess = line[8:] 6013 nb_sub += sub_proccess.count(',') + 1 6014 if main in names: 6015 names[main] += [sub_proccess.split(',')] 6016 else: 6017 names[main]= [sub_proccess.split(',')] 6018 6019 return names
6020 6021 @staticmethod
6022 - def get_subP_info_v4(path):
6023 """ return the list of processes with their name in case without grouping """ 6024 6025 nb_sub = 0 6026 names = {'':[[]]} 6027 path = os.path.join(path, 'auto_dsig.f') 6028 found = 0 6029 for line in open(path): 6030 if line.startswith('C Process:'): 6031 found += 1 6032 names[''][0].append(line[15:]) 6033 elif found >1: 6034 break 6035 return names
6036 6037 6038 @staticmethod
6039 - def get_subP_ids(path):
6040 """return the pdg codes of the particles present in the Subprocesses""" 6041 6042 all_ids = [] 6043 for line in open(pjoin(path, 'leshouche.inc')): 6044 if not 'IDUP' in line: 6045 continue 6046 particles = re.search("/([\d,-]+)/", line) 6047 all_ids.append([int(p) for p in particles.group(1).split(',')]) 6048 return all_ids
6049
6050 6051 #=============================================================================== 6052 -class GridPackCmd(MadEventCmd):
6053 """The command for the gridpack --Those are not suppose to be use interactively--""" 6054
6055 - def __init__(self, me_dir = None, nb_event=0, seed=0, *completekey, **stdin):
6056 """Initialize the command and directly run""" 6057 6058 # Initialize properly 6059 6060 MadEventCmd.__init__(self, me_dir, *completekey, **stdin) 6061 self.run_mode = 0 6062 self.random = seed 6063 self.random_orig = self.random 6064 self.options['automatic_html_opening'] = False 6065 # Now it's time to run! 6066 if me_dir and nb_event and seed: 6067 self.launch(nb_event, seed) 6068 else: 6069 raise MadGraph5Error,\ 6070 'Gridpack run failed: ' + str(me_dir) + str(nb_event) + \ 6071 str(seed)
6072
6073 - def launch(self, nb_event, seed):
6074 """ launch the generation for the grid """ 6075 6076 # 1) Restore the default data 6077 logger.info('generate %s events' % nb_event) 6078 self.set_run_name('GridRun_%s' % seed) 6079 self.update_status('restoring default data', level=None) 6080 misc.call([pjoin(self.me_dir,'bin','internal','restore_data'), 6081 'default'], 6082 cwd=self.me_dir) 6083 6084 # 2) Run the refine for the grid 6085 self.update_status('Generating Events', level=None) 6086 #misc.call([pjoin(self.me_dir,'bin','refine4grid'), 6087 # str(nb_event), '0', 'Madevent','1','GridRun_%s' % seed], 6088 # cwd=self.me_dir) 6089 self.refine4grid(nb_event) 6090 6091 # 3) Combine the events/pythia/... 6092 self.exec_cmd('combine_events') 6093 self.exec_cmd('store_events') 6094 self.print_results_in_shell(self.results.current) 6095 self.exec_cmd('decay_events -from_cards', postcmd=False)
6096
6097 - def refine4grid(self, nb_event):
6098 """Special refine for gridpack run.""" 6099 self.nb_refine += 1 6100 6101 precision = nb_event 6102 6103 # initialize / remove lhapdf mode 6104 # self.configure_directory() # All this has been done before 6105 self.cluster_mode = 0 # force single machine 6106 6107 # Store seed in randinit file, to be read by ranmar.f 6108 self.save_random() 6109 6110 self.update_status('Refine results to %s' % precision, level=None) 6111 logger.info("Using random number seed offset = %s" % self.random) 6112 6113 self.total_jobs = 0 6114 subproc = [P for P in os.listdir(pjoin(self.me_dir,'SubProcesses')) if 6115 P.startswith('P') and os.path.isdir(pjoin(self.me_dir,'SubProcesses', P))] 6116 devnull = open(os.devnull, 'w') 6117 for nb_proc,subdir in enumerate(subproc): 6118 subdir = subdir.strip() 6119 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir) 6120 bindir = pjoin(os.path.relpath(self.dirbin, Pdir)) 6121 6122 logger.info(' %s ' % subdir) 6123 # clean previous run 6124 for match in misc.glob('*ajob*', Pdir): 6125 if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']: 6126 os.remove(pjoin(Pdir, match)) 6127 6128 6129 logfile = pjoin(Pdir, 'gen_ximprove.log') 6130 misc.call([pjoin(bindir, 'gen_ximprove')], 6131 stdin=subprocess.PIPE, 6132 stdout=open(logfile,'w'), 6133 cwd=Pdir) 6134 6135 if os.path.exists(pjoin(Pdir, 'ajob1')): 6136 alljobs = misc.glob('ajob*', Pdir) 6137 nb_tot = len(alljobs) 6138 self.total_jobs += nb_tot 6139 for i, job in enumerate(alljobs): 6140 job = os.path.basename(job) 6141 self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1), 6142 run_type='Refine number %s on %s (%s/%s)' % 6143 (self.nb_refine, subdir, nb_proc+1, len(subproc))) 6144 if os.path.exists(pjoin(self.me_dir,'error')): 6145 self.monitor(html=True) 6146 raise MadEventError, \ 6147 'Error detected in dir %s: %s' % \ 6148 (Pdir, open(pjoin(self.me_dir,'error')).read()) 6149 self.monitor(run_type='All job submitted for refine number %s' % 6150 self.nb_refine) 6151 6152 self.update_status("Combining runs", level='parton') 6153 try: 6154 os.remove(pjoin(Pdir, 'combine_runs.log')) 6155 except Exception: 6156 pass 6157 6158 bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses'))) 6159 combine_runs.CombineRuns(self.me_dir) 6160 6161 #update html output 6162 cross, error = sum_html.make_all_html_results(self) 6163 self.results.add_detail('cross', cross) 6164 self.results.add_detail('error', error) 6165 6166 6167 self.update_status('finish refine', 'parton', makehtml=False) 6168 devnull.close()
6169
6170 6171 -class MadLoopInitializer(object):
6172 """ A container class for the various methods for initializing MadLoop. It is 6173 placed in MadEventInterface because it is used by Madevent for loop-induced 6174 simulations. """ 6175 6176 @staticmethod
6177 - def make_and_run(dir_name,checkRam=False):
6178 """ Compile the check program in the directory dir_name. 6179 Return the compilation and running time. """ 6180 6181 # Make sure to recreate the executable and modified source 6182 # (The time stamps are sometimes not actualized if it is too fast) 6183 if os.path.isfile(pjoin(dir_name,'check')): 6184 os.remove(pjoin(dir_name,'check')) 6185 os.remove(pjoin(dir_name,'check_sa.o')) 6186 os.remove(pjoin(dir_name,'loop_matrix.o')) 6187 # Now run make 6188 devnull = open(os.devnull, 'w') 6189 start=time.time() 6190 retcode = subprocess.call(['make','check'], 6191 cwd=dir_name, stdout=devnull, stderr=devnull) 6192 compilation_time = time.time()-start 6193 if retcode != 0: 6194 logging.info("Error while executing make in %s" % dir_name) 6195 return None, None, None 6196 6197 if not checkRam: 6198 start=time.time() 6199 retcode = subprocess.call('./check', 6200 cwd=dir_name, stdout=devnull, stderr=devnull) 6201 6202 run_time = time.time()-start 6203 ram_usage = None 6204 else: 6205 ptimer = misc.ProcessTimer(['./check'], cwd=dir_name, shell=False, \ 6206 stdout=devnull, stderr=devnull, close_fds=True) 6207 try: 6208 ptimer.execute() 6209 #poll as often as possible; otherwise the subprocess might 6210 # "sneak" in some extra memory usage while you aren't looking 6211 # Accuracy of .2 seconds is enough for the timing. 6212 while ptimer.poll(): 6213 time.sleep(.2) 6214 finally: 6215 #make sure that we don't leave the process dangling. 6216 ptimer.close() 6217 # Notice that ptimer.max_vms_memory is also available if needed. 6218 ram_usage = ptimer.max_rss_memory 6219 # Unfortunately the running time is less precise than with the 6220 # above version 6221 run_time = (ptimer.t1 - ptimer.t0) 6222 retcode = ptimer.p.returncode 6223 6224 devnull.close() 6225 6226 if retcode != 0: 6227 logging.warning("Error while executing ./check in %s" % dir_name) 6228 return None, None, None 6229 6230 return compilation_time, run_time, ram_usage
6231 6232 @staticmethod
6233 - def fix_PSPoint_in_check(dir_path, read_ps = True, npoints = 1, 6234 hel_config = -1, mu_r=0.0, split_orders=-1):
6235 """Set check_sa.f to be reading PS.input assuming a working dir dir_name. 6236 if hel_config is different than -1 then check_sa.f is configured so to 6237 evaluate only the specified helicity. 6238 If mu_r > 0.0, then the renormalization constant value will be hardcoded 6239 directly in check_sa.f, if is is 0 it will be set to Sqrt(s) and if it 6240 is < 0.0 the value in the param_card.dat is used. 6241 If the split_orders target (i.e. the target squared coupling orders for 6242 the computation) is != -1, it will be changed in check_sa.f via the 6243 subroutine CALL SET_COUPLINGORDERS_TARGET(split_orders).""" 6244 6245 file_path = dir_path 6246 if not os.path.isfile(dir_path) or \ 6247 not os.path.basename(dir_path)=='check_sa.f': 6248 file_path = pjoin(dir_path,'check_sa.f') 6249 if not os.path.isfile(file_path): 6250 directories = [d for d in misc.glob('P*_*', dir_path) \ 6251 if (re.search(r'.*P\d+_\w*$', d) and os.path.isdir(d))] 6252 if len(directories)>0: 6253 file_path = pjoin(directories[0],'check_sa.f') 6254 if not os.path.isfile(file_path): 6255 raise MadGraph5Error('Could not find the location of check_sa.f'+\ 6256 ' from the specified path %s.'%str(file_path)) 6257 6258 file = open(file_path, 'r') 6259 check_sa = file.read() 6260 file.close() 6261 6262 file = open(file_path, 'w') 6263 check_sa = re.sub(r"READPS = \S+\)","READPS = %s)"%('.TRUE.' if read_ps \ 6264 else '.FALSE.'), check_sa) 6265 check_sa = re.sub(r"NPSPOINTS = \d+","NPSPOINTS = %d"%npoints, check_sa) 6266 if hel_config != -1: 6267 check_sa = re.sub(r"SLOOPMATRIX\S+\(\S+,MATELEM,", 6268 "SLOOPMATRIXHEL_THRES(P,%d,MATELEM,"%hel_config, check_sa) 6269 else: 6270 check_sa = re.sub(r"SLOOPMATRIX\S+\(\S+,MATELEM,", 6271 "SLOOPMATRIX_THRES(P,MATELEM,",check_sa) 6272 if mu_r > 0.0: 6273 check_sa = re.sub(r"MU_R=SQRTS","MU_R=%s"%\ 6274 (("%.17e"%mu_r).replace('e','d')),check_sa) 6275 elif mu_r < 0.0: 6276 check_sa = re.sub(r"MU_R=SQRTS","",check_sa) 6277 6278 if split_orders > 0: 6279 check_sa = re.sub(r"SET_COUPLINGORDERS_TARGET\(-?\d+\)", 6280 "SET_COUPLINGORDERS_TARGET(%d)"%split_orders,check_sa) 6281 6282 file.write(check_sa) 6283 file.close()
6284 6285 @staticmethod
6286 - def run_initialization(run_dir=None, SubProc_dir=None, infos=None,\ 6287 req_files = ['HelFilter.dat','LoopFilter.dat'], 6288 attempts = [4,15]):
6289 """ Run the initialization of the process in 'run_dir' with success 6290 characterized by the creation of the files req_files in this directory. 6291 The directory containing the driving source code 'check_sa.f'. 6292 The list attempt gives the successive number of PS points the 6293 initialization should be tried with before calling it failed. 6294 Returns the number of PS points which were necessary for the init. 6295 Notice at least run_dir or SubProc_dir must be provided. 6296 A negative attempt number given in input means that quadprec will be 6297 forced for initialization.""" 6298 6299 # If the user does not want detailed info, then set the dictionary 6300 # to a dummy one. 6301 if infos is None: 6302 infos={} 6303 6304 if SubProc_dir is None and run_dir is None: 6305 raise MadGraph5Error, 'At least one of [SubProc_dir,run_dir] must'+\ 6306 ' be provided in run_initialization.' 6307 6308 # If the user does not specify where is check_sa.f, then it is assumed 6309 # to be one levels above run_dir 6310 if SubProc_dir is None: 6311 SubProc_dir = os.path.abspath(pjoin(run_dir,os.pardir)) 6312 6313 if run_dir is None: 6314 directories =[ dir for dir in misc.glob('P[0-9]*', SubProc_dir) 6315 if os.path.isdir(dir) ] 6316 if directories: 6317 run_dir = directories[0] 6318 else: 6319 raise MadGraph5Error, 'Could not find a valid running directory'+\ 6320 ' in %s.'%str(SubProc_dir) 6321 6322 # Use the presence of the file born_matrix.f to decide if it is a 6323 # loop-induced process or not. It's not crucial, but just that because 6324 # of the dynamic adjustment of the ref scale used for deciding what are 6325 # the zero contributions, more points are neeeded for loop-induced. 6326 if not os.path.isfile(pjoin(run_dir,'born_matrix.f')): 6327 if len(attempts)>=1 and attempts[0]<8: 6328 attempts[0]=8 6329 if len(attempts)>=2 and attempts[1]<25: 6330 attempts[1]=25 6331 6332 to_attempt = list(attempts) 6333 to_attempt.reverse() 6334 my_req_files = list(req_files) 6335 6336 MLCardPath = pjoin(SubProc_dir,'MadLoopParams.dat') 6337 if not os.path.isfile(MLCardPath): 6338 raise MadGraph5Error, 'Could not find MadLoopParams.dat at %s.'\ 6339 %MLCardPath 6340 else: 6341 MLCard = banner_mod.MadLoopParam(MLCardPath) 6342 MLCard_orig = banner_mod.MadLoopParam(MLCard) 6343 6344 # Make sure that LoopFilter really is needed. 6345 if not MLCard['UseLoopFilter']: 6346 try: 6347 my_req_files.remove('LoopFilter.dat') 6348 except ValueError: 6349 pass 6350 6351 if MLCard['HelicityFilterLevel']==0: 6352 try: 6353 my_req_files.remove('HelFilter.dat') 6354 except ValueError: 6355 pass 6356 6357 def need_init(): 6358 """ True if init not done yet.""" 6359 proc_prefix_file = open(pjoin(run_dir,'proc_prefix.txt'),'r') 6360 proc_prefix = proc_prefix_file.read() 6361 proc_prefix_file.close() 6362 return any([not os.path.exists(pjoin(run_dir,'MadLoop5_resources', 6363 proc_prefix+fname)) for fname in my_req_files]) or \ 6364 not os.path.isfile(pjoin(run_dir,'check')) or \ 6365 not os.access(pjoin(run_dir,'check'), os.X_OK)
6366 6367 # Check if this is a process without born by checking the presence of the 6368 # file born_matrix.f 6369 is_loop_induced = os.path.exists(pjoin(run_dir,'born_matrix.f')) 6370 6371 # For loop induced processes, always attempt quadruple precision if 6372 # double precision attempts fail and the user didn't specify himself 6373 # quadruple precision initializations attempts 6374 if not any(attempt<0 for attempt in to_attempt): 6375 to_attempt = [-attempt for attempt in to_attempt] + to_attempt 6376 use_quad_prec = 1 6377 curr_attempt = 1 6378 6379 MLCard.set('WriteOutFilters',True) 6380 6381 while to_attempt!=[] and need_init(): 6382 curr_attempt = to_attempt.pop() 6383 # if the attempt is a negative number it means we must force 6384 # quadruple precision at initialization time 6385 if curr_attempt < 0: 6386 use_quad_prec = -1 6387 # In quadruple precision we can lower the ZeroThres threshold 6388 MLCard.set('CTModeInit',4) 6389 MLCard.set('ZeroThres',1e-11) 6390 else: 6391 # Restore the default double precision intialization params 6392 MLCard.set('CTModeInit',1) 6393 MLCard.set('ZeroThres',1e-9) 6394 # Plus one because the filter are written on the next PS point after 6395 curr_attempt = abs(curr_attempt+1) 6396 MLCard.set('MaxAttempts',curr_attempt) 6397 MLCard.write(pjoin(SubProc_dir,'MadLoopParams.dat')) 6398 6399 # initialization is performed. 6400 MadLoopInitializer.fix_PSPoint_in_check(run_dir, read_ps = False, 6401 npoints = curr_attempt) 6402 compile_time, run_time, ram_usage = \ 6403 MadLoopInitializer.make_and_run(run_dir) 6404 if compile_time==None: 6405 logging.error("Failed at running the process in %s."%run_dir) 6406 attempts = None 6407 return None 6408 # Only set process_compilation time for the first compilation. 6409 if 'Process_compilation' not in infos.keys() or \ 6410 infos['Process_compilation']==None: 6411 infos['Process_compilation'] = compile_time 6412 infos['Initialization'] = run_time 6413 6414 MLCard_orig.write(pjoin(SubProc_dir,'MadLoopParams.dat')) 6415 if need_init(): 6416 return None 6417 else: 6418 return use_quad_prec*(curr_attempt-1)
6419 6420 @staticmethod
6421 - def need_MadLoopInit(proc_dir, subproc_prefix='PV'):
6422 """Checks whether the necessary filters are present or not.""" 6423 6424 def need_init(ML_resources_path, proc_prefix, r_files): 6425 """ Returns true if not all required files are present. """ 6426 return any([not os.path.exists(pjoin(ML_resources_path, 6427 proc_prefix+fname)) for fname in r_files])
6428 6429 MLCardPath = pjoin(proc_dir,'SubProcesses','MadLoopParams.dat') 6430 if not os.path.isfile(MLCardPath): 6431 raise MadGraph5Error, 'Could not find MadLoopParams.dat at %s.'\ 6432 %MLCardPath 6433 MLCard = banner_mod.MadLoopParam(MLCardPath) 6434 6435 req_files = ['HelFilter.dat','LoopFilter.dat'] 6436 # Make sure that LoopFilter really is needed. 6437 if not MLCard['UseLoopFilter']: 6438 try: 6439 req_files.remove('LoopFilter.dat') 6440 except ValueError: 6441 pass 6442 if MLCard['HelicityFilterLevel']==0: 6443 try: 6444 req_files.remove('HelFilter.dat') 6445 except ValueError: 6446 pass 6447 6448 for v_folder in glob.iglob(pjoin(proc_dir,'SubProcesses', 6449 '%s*'%subproc_prefix)): 6450 # Make sure it is a valid MadLoop directory 6451 if not os.path.isdir(v_folder) or not os.path.isfile(\ 6452 pjoin(v_folder,'loop_matrix.f')): 6453 continue 6454 proc_prefix_file = open(pjoin(v_folder,'proc_prefix.txt'),'r') 6455 proc_prefix = proc_prefix_file.read() 6456 proc_prefix_file.close() 6457 if need_init(pjoin(proc_dir,'SubProcesses','MadLoop5_resources'), 6458 proc_prefix, req_files): 6459 return True 6460 6461 return False 6462 6463 @staticmethod
6464 - def init_MadLoop(proc_dir, n_PS=None, subproc_prefix='PV', MG_options=None, 6465 interface = None):
6466 """Advanced commands: Compiles and run MadLoop on RAMBO random PS points to initilize the 6467 filters.""" 6468 6469 logger.debug('Compiling Source materials necessary for MadLoop '+ 6470 'initialization.') 6471 # Initialize all the virtuals directory, so as to generate the necessary 6472 # filters (essentially Helcity filter). 6473 # Make sure that the MadLoopCard has the loop induced settings 6474 if interface is None: 6475 misc.compile(arg=['treatCardsLoopNoInit'], cwd=pjoin(proc_dir,'Source')) 6476 else: 6477 interface.do_treatcards('all --no_MadLoopInit') 6478 6479 # First make sure that IREGI and CUTTOOLS are compiled if needed 6480 if os.path.exists(pjoin(proc_dir,'Source','CUTTOOLS')): 6481 misc.compile(arg=['libcuttools'],cwd=pjoin(proc_dir,'Source')) 6482 if os.path.exists(pjoin(proc_dir,'Source','IREGI')): 6483 misc.compile(arg=['libiregi'],cwd=pjoin(proc_dir,'Source')) 6484 # Then make sure DHELAS and MODEL are compiled 6485 misc.compile(arg=['libmodel'],cwd=pjoin(proc_dir,'Source')) 6486 misc.compile(arg=['libdhelas'],cwd=pjoin(proc_dir,'Source')) 6487 6488 # Now initialize the MadLoop outputs 6489 logger.info('Initializing MadLoop loop-induced matrix elements '+\ 6490 '(this can take some time)...') 6491 6492 # Setup parallelization 6493 if MG_options: 6494 mcore = cluster.MultiCore(**MG_options) 6495 else: 6496 mcore = cluster.onecore 6497 def run_initialization_wrapper(run_dir, infos, attempts): 6498 if attempts is None: 6499 n_PS = MadLoopInitializer.run_initialization( 6500 run_dir=run_dir, infos=infos) 6501 else: 6502 n_PS = MadLoopInitializer.run_initialization( 6503 run_dir=run_dir, infos=infos, attempts=attempts) 6504 infos['nPS'] = n_PS 6505 return 0
6506 6507 def wait_monitoring(Idle, Running, Done): 6508 if Idle+Running+Done == 0: 6509 return 6510 logger.debug('MadLoop initialization jobs: %d Idle, %d Running, %d Done'\ 6511 %(Idle, Running, Done)) 6512 6513 init_info = {} 6514 # List all virtual folders while making sure they are valid MadLoop folders 6515 VirtualFolders = [f for f in glob.iglob(pjoin(proc_dir,'SubProcesses', 6516 '%s*'%subproc_prefix)) if (os.path.isdir(f) or 6517 os.path.isfile(pjoin(f,'loop_matrix.f')))] 6518 logger.debug("Now Initializing MadLoop matrix element in %d folder%s:"%\ 6519 (len(VirtualFolders),'s' if len(VirtualFolders)>1 else '')) 6520 logger.debug(', '.join("'%s'"%os.path.basename(v_folder) for v_folder in 6521 VirtualFolders)) 6522 for v_folder in VirtualFolders: 6523 init_info[v_folder] = {} 6524 6525 # We try all multiples of n_PS from 1 to max_mult, first in DP and then 6526 # in QP before giving up, or use default values if n_PS is None. 6527 max_mult = 3 6528 if n_PS is None: 6529 # Then use the default list of number of PS points to try 6530 mcore.submit(run_initialization_wrapper, 6531 [pjoin(v_folder), init_info[v_folder], None]) 6532 else: 6533 # Use specific set of PS points 6534 mcore.submit(run_initialization_wrapper, [pjoin(v_folder), 6535 init_info[v_folder], 6536 [n_PS*multiplier for multiplier in range(1,max_mult+1)]]) 6537 6538 # Wait for all jobs to finish. 6539 mcore.wait('',wait_monitoring,update_first=wait_monitoring) 6540 for v_folder in VirtualFolders: 6541 init = init_info[v_folder] 6542 if init['nPS'] is None: 6543 raise MadGraph5Error, 'Failed the initialization of'+\ 6544 " loop-induced matrix element '%s'%s."%\ 6545 (os.path.basename(v_folder),' (using default n_PS points)' if\ 6546 n_PS is None else ' (trying with a maximum of %d PS points)'\ 6547 %(max_mult*n_PS)) 6548 if init['nPS']==0: 6549 logger.debug("Nothing to be done in '%s', all filters already "%\ 6550 os.path.basename(v_folder)+\ 6551 "present (use the '-r' option to force their recomputation)") 6552 else: 6553 logger.debug("'%s' finished using "%os.path.basename(v_folder)+ 6554 '%d PS points (%s), in %.3g(compil.) + %.3g(init.) secs.'%( 6555 abs(init['nPS']),'DP' if init['nPS']>0 else 'QP', 6556 init['Process_compilation'],init['Initialization'])) 6557 6558 logger.info('MadLoop initialization finished.') 6559 6560 AskforEditCard = common_run.AskforEditCard 6561 6562 6563 if '__main__' == __name__: 6564 # Launch the interface without any check if one code is already running. 6565 # This can ONLY run a single command !! 6566 import sys 6567 if not sys.version_info[0] == 2 or sys.version_info[1] < 6: 6568 sys.exit('MadGraph/MadEvent 5 works only with python 2.6 or later (but not python 3.X).\n'+\ 6569 'Please upgrate your version of python.') 6570 6571 import os 6572 import optparse 6573 # Get the directory of the script real path (bin) 6574 # and add it to the current PYTHONPATH 6575 root_path = os.path.dirname(os.path.dirname(os.path.realpath( __file__ ))) 6576 sys.path.insert(0, root_path)
6577 6578 - class MyOptParser(optparse.OptionParser):
6579 - class InvalidOption(Exception): pass
6580 - def error(self, msg=''):
6581 raise MyOptParser.InvalidOption(msg)
6582 # Write out nice usage message if called with -h or --help 6583 usage = "usage: %prog [options] [FILE] " 6584 parser = MyOptParser(usage=usage) 6585 parser.add_option("-l", "--logging", default='INFO', 6586 help="logging level (DEBUG|INFO|WARNING|ERROR|CRITICAL) [%default]") 6587 parser.add_option("","--web", action="store_true", default=False, dest='web', \ 6588 help='force toce to be in secure mode') 6589 parser.add_option("","--debug", action="store_true", default=False, dest='debug', \ 6590 help='force to launch debug mode') 6591 parser_error = '' 6592 done = False 6593 6594 for i in range(len(sys.argv)-1): 6595 try: 6596 (options, args) = parser.parse_args(sys.argv[1:len(sys.argv)-i]) 6597 done = True 6598 except MyOptParser.InvalidOption, error: 6599 pass 6600 else: 6601 args += sys.argv[len(sys.argv)-i:] 6602 if not done: 6603 # raise correct error: 6604 try: 6605 (options, args) = parser.parse_args() 6606 except MyOptParser.InvalidOption, error: 6607 print error 6608 sys.exit(2) 6609 6610 if len(args) == 0: 6611 args = '' 6612 6613 import subprocess 6614 import logging 6615 import logging.config 6616 # Set logging level according to the logging level given by options 6617 #logging.basicConfig(level=vars(logging)[options.logging]) 6618 import internal.coloring_logging 6619 try: 6620 if __debug__ and options.logging == 'INFO': 6621 options.logging = 'DEBUG' 6622 if options.logging.isdigit(): 6623 level = int(options.logging) 6624 else: 6625 level = eval('logging.' + options.logging) 6626 print os.path.join(root_path, 'internal', 'me5_logging.conf') 6627 logging.config.fileConfig(os.path.join(root_path, 'internal', 'me5_logging.conf')) 6628 logging.root.setLevel(level) 6629 logging.getLogger('madgraph').setLevel(level) 6630 except: 6631 raise 6632 pass 6633 6634 # Call the cmd interface main loop 6635 try: 6636 if args: 6637 # a single command is provided 6638 if '--web' in args: 6639 i = args.index('--web') 6640 args.pop(i) 6641 cmd_line = MadEventCmd(force_run=True) 6642 else: 6643 cmd_line = MadEventCmdShell(force_run=True) 6644 if not hasattr(cmd_line, 'do_%s' % args[0]): 6645 if parser_error: 6646 print parser_error 6647 print 'and %s can not be interpreted as a valid command.' % args[0] 6648 else: 6649 print 'ERROR: %s not a valid command. Please retry' % args[0] 6650 else: 6651 cmd_line.use_rawinput = False 6652 cmd_line.run_cmd(' '.join(args)) 6653 cmd_line.run_cmd('quit') 6654 6655 except KeyboardInterrupt: 6656 print 'quit on KeyboardInterrupt' 6657 pass 6658