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