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