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.Gdirs = None 2122 2123 self.prompt = "%s>"%os.path.basename(pjoin(self.me_dir)) 2124 self.configured = 0 # time for reading the card 2125 self._options = {} # for compatibility with extended_cmd
2126 2127
2128 - def pass_in_web_mode(self):
2129 """configure web data""" 2130 self.web = True 2131 self.results.def_web_mode(True) 2132 self.force = True 2133 if os.environ['MADGRAPH_BASE']: 2134 self.options['mg5_path'] = pjoin(os.environ['MADGRAPH_BASE'],'MG5')
2135 2136 ############################################################################
2137 - def check_output_type(self, path):
2138 """ Check that the output path is a valid madevent directory """ 2139 2140 bin_path = os.path.join(path,'bin') 2141 if os.path.isfile(os.path.join(bin_path,'generate_events')): 2142 return True 2143 else: 2144 return False
2145 2146 ############################################################################
2147 - def set_configuration(self, amcatnlo=False, final=True, **opt):
2148 """assign all configuration variable from file 2149 loop over the different config file if config_file not define """ 2150 2151 super(MadEventCmd,self).set_configuration(amcatnlo=amcatnlo, 2152 final=final, **opt) 2153 2154 if not final: 2155 return self.options # the return is usefull for unittest 2156 2157 2158 # Treat each expected input 2159 # delphes/pythia/... path 2160 # ONLY the ONE LINKED TO Madevent ONLY!!! 2161 for key in (k for k in self.options if k.endswith('path')): 2162 path = self.options[key] 2163 if path is None or key.startswith("cluster"): 2164 continue 2165 if not os.path.isdir(path): 2166 path = pjoin(self.me_dir, self.options[key]) 2167 if os.path.isdir(path): 2168 self.options[key] = None 2169 if key == "pythia-pgs_path": 2170 if not os.path.exists(pjoin(path, 'src','pythia')): 2171 logger.info("No valid pythia-pgs path found") 2172 continue 2173 elif key == "delphes_path": 2174 if not os.path.exists(pjoin(path, 'Delphes')) and not\ 2175 os.path.exists(pjoin(path, 'DelphesSTDHEP')): 2176 logger.info("No valid Delphes path found") 2177 continue 2178 elif key == "madanalysis_path": 2179 if not os.path.exists(pjoin(path, 'plot_events')): 2180 logger.info("No valid MadAnalysis path found") 2181 continue 2182 elif key == "td_path": 2183 if not os.path.exists(pjoin(path, 'td')): 2184 logger.info("No valid td path found") 2185 continue 2186 elif key == "syscalc_path": 2187 if not os.path.exists(pjoin(path, 'sys_calc')): 2188 logger.info("No valid SysCalc path found") 2189 continue 2190 # No else since the next line reinitialize the option to the 2191 #previous value anyway 2192 self.options[key] = os.path.realpath(path) 2193 continue 2194 else: 2195 self.options[key] = None 2196 2197 2198 return self.options
2199 2200 ############################################################################
2201 - def do_add_time_of_flight(self, line):
2202 2203 args = self.split_arg(line) 2204 #check the validity of the arguments and reformat args 2205 self.check_add_time_of_flight(args) 2206 2207 event_path, threshold = args 2208 #gunzip the file 2209 if event_path.endswith('.gz'): 2210 need_zip = True 2211 misc.gunzip(event_path) 2212 event_path = event_path[:-3] 2213 else: 2214 need_zip = False 2215 2216 import random 2217 try: 2218 import madgraph.various.lhe_parser as lhe_parser 2219 except: 2220 import internal.lhe_parser as lhe_parser 2221 2222 logger.info('Add time of flight information on file %s' % event_path) 2223 lhe = lhe_parser.EventFile(event_path) 2224 output = open('%s_2vertex.lhe' % event_path, 'w') 2225 #write the banner to the output file 2226 output.write(lhe.banner) 2227 2228 # get the associate param_card 2229 begin_param = lhe.banner.find('<slha>') 2230 end_param = lhe.banner.find('</slha>') 2231 param_card = lhe.banner[begin_param+6:end_param].split('\n') 2232 param_card = check_param_card.ParamCard(param_card) 2233 2234 cst = 6.58211915e-25 # hbar in GeV s 2235 c = 299792458000 # speed of light in mm/s 2236 # Loop over all events 2237 for event in lhe: 2238 for particle in event: 2239 id = particle.pid 2240 width = param_card['decay'].get((abs(id),)).value 2241 if width: 2242 vtim = c * random.expovariate(width/cst) 2243 if vtim > threshold: 2244 particle.vtim = vtim 2245 #write this modify event 2246 output.write(str(event)) 2247 output.write('</LesHouchesEvents>\n') 2248 output.close() 2249 2250 files.mv('%s_2vertex.lhe' % event_path, event_path) 2251 2252 if need_zip: 2253 misc.gzip(event_path)
2254 2255 ############################################################################
2256 - def do_banner_run(self, line):
2257 """Make a run from the banner file""" 2258 2259 args = self.split_arg(line) 2260 #check the validity of the arguments 2261 self.check_banner_run(args) 2262 2263 # Remove previous cards 2264 for name in ['delphes_trigger.dat', 'delphes_card.dat', 2265 'pgs_card.dat', 'pythia_card.dat', 'madspin_card.dat', 2266 'reweight_card.dat']: 2267 try: 2268 os.remove(pjoin(self.me_dir, 'Cards', name)) 2269 except Exception: 2270 pass 2271 2272 banner_mod.split_banner(args[0], self.me_dir, proc_card=False) 2273 2274 # Check if we want to modify the run 2275 if not self.force: 2276 ans = self.ask('Do you want to modify the Cards?', 'n', ['y','n']) 2277 if ans == 'n': 2278 self.force = True 2279 2280 # Call Generate events 2281 self.exec_cmd('generate_events %s %s' % (self.run_name, self.force and '-f' or ''))
2282 2283 2284 2285 ############################################################################
2286 - def do_display(self, line, output=sys.stdout):
2287 """Display current internal status""" 2288 2289 args = self.split_arg(line) 2290 #check the validity of the arguments 2291 self.check_display(args) 2292 2293 if args[0] == 'run_name': 2294 #return valid run_name 2295 data = misc.glob(pjoin('*','*_banner.txt'), pjoin(self.me_dir, 'Events')) 2296 data = [n.rsplit('/',2)[1:] for n in data] 2297 2298 if data: 2299 out = {} 2300 for name, tag in data: 2301 tag = tag[len(name)+1:-11] 2302 if name in out: 2303 out[name].append(tag) 2304 else: 2305 out[name] = [tag] 2306 print('the runs available are:') 2307 for run_name, tags in out.items(): 2308 print(' run: %s' % run_name) 2309 print(' tags: ', end=' ') 2310 print(', '.join(tags)) 2311 else: 2312 print('No run detected.') 2313 2314 elif args[0] == 'options': 2315 outstr = " Run Options \n" 2316 outstr += " ----------- \n" 2317 for key, default in self.options_madgraph.items(): 2318 value = self.options[key] 2319 if value == default: 2320 outstr += " %25s \t:\t%s\n" % (key,value) 2321 else: 2322 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 2323 outstr += "\n" 2324 outstr += " MadEvent Options \n" 2325 outstr += " ---------------- \n" 2326 for key, default in self.options_madevent.items(): 2327 if key in self.options: 2328 value = self.options[key] 2329 else: 2330 default = '' 2331 if value == default: 2332 outstr += " %25s \t:\t%s\n" % (key,value) 2333 else: 2334 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 2335 outstr += "\n" 2336 outstr += " Configuration Options \n" 2337 outstr += " --------------------- \n" 2338 for key, default in self.options_configuration.items(): 2339 value = self.options[key] 2340 if value == default: 2341 outstr += " %25s \t:\t%s\n" % (key,value) 2342 else: 2343 outstr += " %25s \t:\t%s (user set)\n" % (key,value) 2344 output.write(outstr) 2345 elif args[0] == 'results': 2346 self.do_print_results(' '.join(args[1:])) 2347 else: 2348 super(MadEventCmd, self).do_display(line, output)
2349
2350 - def do_save(self, line, check=True, to_keep={}):
2351 """Not in help: Save information to file""" 2352 2353 args = self.split_arg(line) 2354 # Check argument validity 2355 if check: 2356 self.check_save(args) 2357 2358 if args[0] == 'options': 2359 # First look at options which should be put in MG5DIR/input 2360 to_define = {} 2361 for key, default in self.options_configuration.items(): 2362 if self.options[key] != self.options_configuration[key]: 2363 to_define[key] = self.options[key] 2364 2365 if not '--auto' in args: 2366 for key, default in self.options_madevent.items(): 2367 if self.options[key] != self.options_madevent[key]: 2368 to_define[key] = self.options[key] 2369 2370 if '--all' in args: 2371 for key, default in self.options_madgraph.items(): 2372 if self.options[key] != self.options_madgraph[key]: 2373 to_define[key] = self.options[key] 2374 elif not '--auto' in args: 2375 for key, default in self.options_madgraph.items(): 2376 if self.options[key] != self.options_madgraph[key]: 2377 logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \ 2378 % (key,self.options_madgraph[key]) ) 2379 logger.info('If you want to make this value the default for future session, you can run \'save options --all\'') 2380 if len(args) >1 and not args[1].startswith('--'): 2381 filepath = args[1] 2382 else: 2383 filepath = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 2384 basefile = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 2385 basedir = self.me_dir 2386 2387 if to_keep: 2388 to_define = to_keep 2389 self.write_configuration(filepath, basefile, basedir, to_define)
2390 2391 2392 2393
2394 - def do_edit_cards(self, line):
2395 """Advanced commands: Basic edition of the cards""" 2396 args = self.split_arg(line) 2397 # Check argument's validity 2398 mode = self.check_generate_events(args) 2399 self.ask_run_configuration(mode) 2400 2401 return
2402 2403 ############################################################################ 2404 2405 ############################################################################
2406 - def do_restart_gridpack(self, line):
2407 """ syntax restart_gridpack --precision=1.0 --restart_zero 2408 collect the result of the current run and relaunch each channel 2409 not completed or optionally a completed one with a precision worse than 2410 a threshold (and/or the zero result channel)""" 2411 2412 2413 args = self.split_arg(line) 2414 # Check argument's validity 2415 self.check_survey(args) 2416 2417 # initialize / remove lhapdf mode 2418 #self.run_card = banner_mod.RunCard(pjoin(self.me_dir, 'Cards', 'run_card.dat')) 2419 #self.configure_directory() 2420 2421 gensym = gen_ximprove.gensym(self) 2422 2423 min_precision = 1.0 2424 resubmit_zero=False 2425 if '--precision=' in line: 2426 s = line.index('--precision=') + len('--precision=') 2427 arg=line[s:].split(1)[0] 2428 min_precision = float(arg) 2429 2430 if '--restart_zero' in line: 2431 resubmit_zero = True 2432 2433 2434 gensym.resubmit(min_precision, resubmit_zero) 2435 self.monitor(run_type='All jobs submitted for gridpack', html=True) 2436 2437 #will be done during the refine (more precisely in gen_ximprove) 2438 cross, error = sum_html.make_all_html_results(self) 2439 self.results.add_detail('cross', cross) 2440 self.results.add_detail('error', error) 2441 self.exec_cmd("print_results %s" % self.run_name, 2442 errorhandling=False, printcmd=False, precmd=False, postcmd=False) 2443 2444 self.results.add_detail('run_statistics', dict(gensym.run_statistics)) 2445 2446 2447 #self.exec_cmd('combine_events', postcmd=False) 2448 #self.exec_cmd('store_events', postcmd=False) 2449 self.exec_cmd('decay_events -from_cards', postcmd=False) 2450 self.exec_cmd('create_gridpack', postcmd=False)
2451 2452 2453 2454 ############################################################################ 2455 2456 ############################################################################
2457 - def do_generate_events(self, line):
2458 """Main Commands: launch the full chain """ 2459 2460 self.banner = None 2461 self.Gdirs = None 2462 2463 args = self.split_arg(line) 2464 # Check argument's validity 2465 mode = self.check_generate_events(args) 2466 switch_mode = self.ask_run_configuration(mode, args) 2467 if not args: 2468 # No run name assigned -> assigned one automaticaly 2469 self.set_run_name(self.find_available_run_name(self.me_dir), None, 'parton') 2470 else: 2471 self.set_run_name(args[0], None, 'parton', True) 2472 args.pop(0) 2473 2474 self.run_generate_events(switch_mode, args)
2475 2476 2477 2478 # this decorator handle the loop related to scan. 2479 @common_run.scanparamcardhandling()
2480 - def run_generate_events(self, switch_mode, args):
2481 2482 if self.proc_characteristics['loop_induced'] and self.options['run_mode']==0: 2483 # Also the single core mode is not supported for loop-induced. 2484 # We therefore emulate it with multi-core mode with one core 2485 logger.warning( 2486 """Single-core mode not supported for loop-induced processes. 2487 Beware that MG5aMC now changes your runtime options to a multi-core mode with only one active core.""") 2488 self.do_set('run_mode 2') 2489 self.do_set('nb_core 1') 2490 2491 if self.run_card['gridpack'] in self.true: 2492 # Running gridpack warmup 2493 gridpack_opts=[('accuracy', 0.01), 2494 ('points', 2000), 2495 ('iterations',8), 2496 ('gridpack','.true.')] 2497 logger.info('Generating gridpack with run name %s' % self.run_name) 2498 self.exec_cmd('survey %s %s' % \ 2499 (self.run_name, 2500 " ".join(['--' + opt + '=' + str(val) for (opt,val) \ 2501 in gridpack_opts])), 2502 postcmd=False) 2503 self.exec_cmd('combine_events', postcmd=False) 2504 self.exec_cmd('store_events', postcmd=False) 2505 with misc.TMP_variable(self, 'run_name', self.run_name): 2506 self.exec_cmd('decay_events -from_cards', postcmd=False) 2507 self.exec_cmd('create_gridpack', postcmd=False) 2508 else: 2509 # Regular run mode 2510 logger.info('Generating %s events with run name %s' % 2511 (self.run_card['nevents'], self.run_name)) 2512 2513 self.exec_cmd('survey %s %s' % (self.run_name,' '.join(args)), 2514 postcmd=False) 2515 nb_event = self.run_card['nevents'] 2516 bypass_run=False 2517 self.exec_cmd('refine %s' % nb_event, postcmd=False) 2518 if not float(self.results.current['cross']): 2519 # Zero cross-section. Try to guess why 2520 text = '''Survey return zero cross section. 2521 Typical reasons are the following: 2522 1) A massive s-channel particle has a width set to zero. 2523 2) The pdf are zero for at least one of the initial state particles 2524 or you are using maxjetflavor=4 for initial state b:s. 2525 3) The cuts are too strong. 2526 Please check/correct your param_card and/or your run_card.''' 2527 logger_stderr.critical(text) 2528 if not self.param_card_iterator: 2529 raise ZeroResult('See https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/FAQ-General-14') 2530 else: 2531 bypass_run = True 2532 2533 #we can bypass the following if scan and first result is zero 2534 if not bypass_run: 2535 self.exec_cmd('refine %s --treshold=%s' % (nb_event,self.run_card['second_refine_treshold']) 2536 , postcmd=False) 2537 2538 self.exec_cmd('combine_events', postcmd=False,printcmd=False) 2539 self.print_results_in_shell(self.results.current) 2540 2541 if self.run_card['use_syst']: 2542 if self.run_card['systematics_program'] == 'auto': 2543 scdir = self.options['syscalc_path'] 2544 if not scdir or not os.path.exists(scdir): 2545 to_use = 'systematics' 2546 else: 2547 to_use = 'syscalc' 2548 elif self.run_card['systematics_program'].lower() in ['systematics','syscalc', 'none']: 2549 to_use = self.run_card['systematics_program'] 2550 else: 2551 logger.critical('Unvalid options for systematics_program: bypass computation of systematics variations.') 2552 to_use = 'none' 2553 2554 if to_use == 'systematics': 2555 if self.run_card['systematics_arguments'] != ['']: 2556 self.exec_cmd('systematics %s %s ' % (self.run_name, 2557 ' '.join(self.run_card['systematics_arguments'])), 2558 postcmd=False, printcmd=False) 2559 else: 2560 self.exec_cmd('systematics %s --from_card' % self.run_name, 2561 postcmd=False,printcmd=False) 2562 elif to_use == 'syscalc': 2563 self.run_syscalc('parton') 2564 2565 2566 self.create_plot('parton') 2567 self.exec_cmd('store_events', postcmd=False) 2568 if self.run_card['boost_event'].strip() and self.run_card['boost_event'] != 'False': 2569 self.boost_events() 2570 2571 2572 self.exec_cmd('reweight -from_cards', postcmd=False) 2573 self.exec_cmd('decay_events -from_cards', postcmd=False) 2574 if self.run_card['time_of_flight']>=0: 2575 self.exec_cmd("add_time_of_flight --threshold=%s" % self.run_card['time_of_flight'] ,postcmd=False) 2576 2577 if switch_mode['analysis'] == 'ExRoot': 2578 input = pjoin(self.me_dir, 'Events', self.run_name,'unweighted_events.lhe.gz') 2579 output = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.root') 2580 self.create_root_file(input , output) 2581 2582 self.exec_cmd('madanalysis5_parton --no_default', postcmd=False, printcmd=False) 2583 # shower launches pgs/delphes if needed 2584 self.exec_cmd('shower --no_default', postcmd=False, printcmd=False) 2585 self.exec_cmd('madanalysis5_hadron --no_default', postcmd=False, printcmd=False) 2586 self.store_result() 2587 2588 if self.allow_notification_center: 2589 misc.apple_notify('Run %s finished' % os.path.basename(self.me_dir), 2590 '%s: %s +- %s ' % (self.results.current['run_name'], 2591 self.results.current['cross'], 2592 self.results.current['error']))
2593
2594 - def boost_events(self):
2595 2596 if not self.run_card['boost_event']: 2597 return 2598 2599 if self.run_card['boost_event'].startswith('lambda'): 2600 if not isinstance(self, cmd.CmdShell): 2601 raise Exception("boost not allowed online") 2602 filter = eval(self.run_card['boost_event']) 2603 else: 2604 raise Exception 2605 2606 path = [pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz'), 2607 pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe'), 2608 pjoin(self.me_dir, 'Events', self.run_name, 'events.lhe.gz'), 2609 pjoin(self.me_dir, 'Events', self.run_name, 'events.lhe')] 2610 2611 for p in path: 2612 if os.path.exists(p): 2613 event_path = p 2614 break 2615 else: 2616 raise Exception("fail to find event file for the boost") 2617 2618 2619 lhe = lhe_parser.EventFile(event_path) 2620 with misc.TMP_directory() as tmp_dir: 2621 output = lhe_parser.EventFile(pjoin(tmp_dir, os.path.basename(event_path)), 'w') 2622 #write the banner to the output file 2623 output.write(lhe.banner) 2624 # Loop over all events 2625 for event in lhe: 2626 event.boost(filter) 2627 #write this modify event 2628 output.write(str(event)) 2629 output.write('</LesHouchesEvent>\n') 2630 lhe.close() 2631 files.mv(pjoin(tmp_dir, os.path.basename(event_path)), event_path)
2632 2633 2634 2635 2636
2637 - def do_initMadLoop(self,line):
2638 """Compile and run MadLoop for a certain number of PS point so as to 2639 initialize MadLoop (setup the zero helicity and loop filter.)""" 2640 2641 args = line.split() 2642 # Check argument's validity 2643 options = self.check_initMadLoop(args) 2644 2645 if not options['force']: 2646 self.ask_edit_cards(['MadLoopParams.dat'], mode='fixed', plot=False) 2647 self.exec_cmd('treatcards loop --no_MadLoopInit') 2648 2649 if options['refresh']: 2650 for filter in misc.glob('*Filter*', 2651 pjoin(self.me_dir,'SubProcesses','MadLoop5_resources')): 2652 logger.debug("Resetting filter '%s'."%os.path.basename(filter)) 2653 os.remove(filter) 2654 2655 MLCard = banner_mod.MadLoopParam(pjoin(self.me_dir, 2656 'Cards','MadLoopParams.dat')) 2657 if options['nPS'] is None: 2658 options['nPS'] = MLCard['CheckCycle']+2 2659 elif options['nPS'] < MLCard['CheckCycle']+2: 2660 new_n_PS = MLCard['CheckCycle']+2 2661 logger.debug('Hard-setting user-defined n_PS (%d) to %d, because '\ 2662 %(options['nPS'],new_n_PS)+"of the 'CheckCycle' value (%d) "%MLCard['CheckCycle']+\ 2663 "specified in the ML param card.") 2664 options['nPS'] = new_n_PS 2665 2666 MadLoopInitializer.init_MadLoop(self.me_dir,n_PS=options['nPS'], 2667 subproc_prefix='PV', MG_options=self.options, interface=self)
2668
2669 - def do_launch(self, line, *args, **opt):
2670 """Main Commands: exec generate_events for 2>N and calculate_width for 1>N""" 2671 2672 if self.ninitial == 1: 2673 logger.info("Note that since 2.3. The launch for 1>N pass in event generation\n"+ 2674 " To have the previous behavior use the calculate_decay_widths function") 2675 # self.do_calculate_decay_widths(line, *args, **opt) 2676 #else: 2677 self.do_generate_events(line, *args, **opt)
2678
2679 - def print_results_in_shell(self, data):
2680 """Have a nice results prints in the shell, 2681 data should be of type: gen_crossxhtml.OneTagResults""" 2682 2683 if not data: 2684 return 2685 2686 if data['run_statistics']: 2687 globalstat = sum_html.RunStatistics() 2688 2689 logger.info(" " ) 2690 logger.debug(" === Run statistics summary ===") 2691 for key, value in data['run_statistics'].items(): 2692 globalstat.aggregate_statistics(value) 2693 level = 5 2694 if value.has_warning(): 2695 level = 10 2696 logger.log(level, value.nice_output(str('/'.join([key[0],'G%s'%key[1]]))).\ 2697 replace(' statistics','')) 2698 logger.info(" " ) 2699 logger.debug(globalstat.nice_output('combined', no_warning=True)) 2700 if globalstat.has_warning(): 2701 logger.warning(globalstat.get_warning_text()) 2702 logger.info(" ") 2703 2704 2705 logger.info(" === Results Summary for run: %s tag: %s ===\n" % (data['run_name'],data['tag'])) 2706 2707 total_time = int(sum(_['cumulative_timing'] for _ in data['run_statistics'].values())) 2708 if total_time > 0: 2709 logger.info(" Cumulative sequential time for this run: %s"%misc.format_time(total_time)) 2710 2711 if self.ninitial == 1: 2712 logger.info(" Width : %.4g +- %.4g GeV" % (data['cross'], data['error'])) 2713 else: 2714 logger.info(" Cross-section : %.4g +- %.4g pb" % (data['cross'], data['error'])) 2715 logger.info(" Nb of events : %s" % data['nb_event'] ) 2716 2717 if data['run_mode']=='madevent': 2718 if data['cross_pythia'] and data['nb_event_pythia']: 2719 if data['cross_pythia'] == -1: 2720 path = pjoin(self.me_dir, 'Events', self.run_name, '%s_merged_xsecs.txt' % self.run_tag) 2721 cross_sections = {} 2722 if os.path.exists(path): 2723 for line in open(path): 2724 split = line.split() 2725 if len(split)!=3: 2726 continue 2727 scale, cross, error = split 2728 cross_sections[float(scale)] = (float(cross), float(error)) 2729 if len(cross_sections)>0: 2730 logger.info(' Pythia8 merged cross-sections are:') 2731 for scale in sorted(cross_sections.keys()): 2732 logger.info(' > Merging scale = %-6.4g : %-11.5g +/- %-7.2g [pb]'%\ 2733 (scale,cross_sections[scale][0],cross_sections[scale][1])) 2734 2735 else: 2736 if self.ninitial == 1: 2737 logger.info(" Matched width : %.4g +- %.4g GeV" % (data['cross_pythia'], data['error_pythia'])) 2738 else: 2739 logger.info(" Matched cross-section : %.4g +- %.4g pb" % (data['cross_pythia'], data['error_pythia'])) 2740 logger.info(" Nb of events after matching/merging : %d" % int(data['nb_event_pythia'])) 2741 if self.run_card['use_syst'] in self.true and \ 2742 (int(self.run_card['ickkw'])==1 or self.run_card['ktdurham']>0.0 2743 or self.run_card['ptlund']>0.0): 2744 logger.info(" Notice that because Systematics computation is turned on, the merging did not veto events but modified their weights instead.\n"+\ 2745 " The resulting hepmc/stdhep file should therefore be use with those weights.") 2746 else: 2747 logger.info(" Nb of events after merging : %s" % data['nb_event_pythia']) 2748 2749 logger.info(" " )
2750
2751 - def print_results_in_file(self, data, path, mode='w', format='full'):
2752 """Have a nice results prints in the shell, 2753 data should be of type: gen_crossxhtml.OneTagResults""" 2754 if not data: 2755 return 2756 2757 fsock = open(path, mode) 2758 2759 if data['run_statistics']: 2760 logger.debug(" === Run statistics summary ===") 2761 for key, value in data['run_statistics'].items(): 2762 logger.debug(value.nice_output(str('/'.join([key[0],'G%s'%key[1]]))).\ 2763 replace(' statistics','')) 2764 logger.info(" " ) 2765 2766 if format == "full": 2767 fsock.write(" === Results Summary for run: %s tag: %s process: %s ===\n" % \ 2768 (data['run_name'],data['tag'], os.path.basename(self.me_dir))) 2769 2770 if self.ninitial == 1: 2771 fsock.write(" Width : %.4g +- %.4g GeV\n" % (data['cross'], data['error'])) 2772 else: 2773 fsock.write(" Cross-section : %.4g +- %.4g pb\n" % (data['cross'], data['error'])) 2774 fsock.write(" Nb of events : %s\n" % data['nb_event'] ) 2775 if data['cross_pythia'] and data['nb_event_pythia']: 2776 if self.ninitial == 1: 2777 fsock.write(" Matched Width : %.4g +- %.4g GeV\n" % (data['cross_pythia'], data['error_pythia'])) 2778 else: 2779 fsock.write(" Matched Cross-section : %.4g +- %.4g pb\n" % (data['cross_pythia'], data['error_pythia'])) 2780 fsock.write(" Nb of events after Matching : %s\n" % data['nb_event_pythia']) 2781 fsock.write(" \n" ) 2782 elif format == "short": 2783 if mode == "w": 2784 fsock.write("# run_name tag cross error Nb_event cross_after_matching nb_event_after matching\n") 2785 2786 if data['cross_pythia'] and data['nb_event_pythia']: 2787 text = "%(run_name)s %(tag)s %(cross)s %(error)s %(nb_event)s %(cross_pythia)s %(nb_event_pythia)s\n" 2788 else: 2789 text = "%(run_name)s %(tag)s %(cross)s %(error)s %(nb_event)s\n" 2790 fsock.write(text % data)
2791 2792 ############################################################################
2793 - def do_calculate_decay_widths(self, line):
2794 """Main Commands: launch decay width calculation and automatic inclusion of 2795 calculated widths and BRs in the param_card.""" 2796 2797 args = self.split_arg(line) 2798 # Check argument's validity 2799 accuracy = self.check_calculate_decay_widths(args) 2800 self.ask_run_configuration('parton') 2801 self.banner = None 2802 self.Gdirs = None 2803 2804 if not args: 2805 # No run name assigned -> assigned one automaticaly 2806 self.set_run_name(self.find_available_run_name(self.me_dir)) 2807 else: 2808 self.set_run_name(args[0], reload_card=True) 2809 args.pop(0) 2810 2811 self.configure_directory() 2812 2813 # Running gridpack warmup 2814 opts=[('accuracy', accuracy), # default 0.01 2815 ('points', 1000), 2816 ('iterations',9)] 2817 2818 logger.info('Calculating decay widths with run name %s' % self.run_name) 2819 2820 self.exec_cmd('survey %s %s' % \ 2821 (self.run_name, 2822 " ".join(['--' + opt + '=' + str(val) for (opt,val) \ 2823 in opts])), 2824 postcmd=False) 2825 self.refine_mode = "old" # specify how to combine event 2826 self.exec_cmd('combine_events', postcmd=False) 2827 self.exec_cmd('store_events', postcmd=False) 2828 2829 self.collect_decay_widths() 2830 self.print_results_in_shell(self.results.current) 2831 self.update_status('calculate_decay_widths done', 2832 level='parton', makehtml=False)
2833 2834 2835 ############################################################################
2836 - def collect_decay_widths(self):
2837 """ Collect the decay widths and calculate BRs for all particles, and put 2838 in param_card form. 2839 """ 2840 2841 particle_dict = {} # store the results 2842 run_name = self.run_name 2843 2844 # Looping over the Subprocesses 2845 for P_path in SubProcesses.get_subP(self.me_dir): 2846 ids = SubProcesses.get_subP_ids(P_path) 2847 # due to grouping we need to compute the ratio factor for the 2848 # ungroup resutls (that we need here). Note that initial particles 2849 # grouping are not at the same stage as final particle grouping 2850 nb_output = len(ids) / (len(set([p[0] for p in ids]))) 2851 results = open(pjoin(P_path, run_name + '_results.dat')).read().split('\n')[0] 2852 result = float(results.strip().split(' ')[0]) 2853 for particles in ids: 2854 try: 2855 particle_dict[particles[0]].append([particles[1:], result/nb_output]) 2856 except KeyError: 2857 particle_dict[particles[0]] = [[particles[1:], result/nb_output]] 2858 2859 self.update_width_in_param_card(particle_dict, 2860 initial = pjoin(self.me_dir, 'Cards', 'param_card.dat'), 2861 output=pjoin(self.me_dir, 'Events', run_name, "param_card.dat"))
2862 2863 @staticmethod
2864 - def update_width_in_param_card(decay_info, initial=None, output=None):
2865 # Open the param_card.dat and insert the calculated decays and BRs 2866 2867 if not output: 2868 output = initial 2869 2870 param_card_file = open(initial) 2871 param_card = param_card_file.read().split('\n') 2872 param_card_file.close() 2873 2874 decay_lines = [] 2875 line_number = 0 2876 # Read and remove all decays from the param_card 2877 while line_number < len(param_card): 2878 line = param_card[line_number] 2879 if line.lower().startswith('decay'): 2880 # Read decay if particle in decay_info 2881 # DECAY 6 1.455100e+00 2882 line = param_card.pop(line_number) 2883 line = line.split() 2884 particle = 0 2885 if int(line[1]) not in decay_info: 2886 try: # If formatting is wrong, don't want this particle 2887 particle = int(line[1]) 2888 width = float(line[2]) 2889 except Exception: 2890 particle = 0 2891 # Read BRs for this decay 2892 line = param_card[line_number] 2893 while re.search('^(#|\s|\d)', line): 2894 line = param_card.pop(line_number) 2895 if not particle or line.startswith('#'): 2896 line=param_card[line_number] 2897 continue 2898 # 6.668201e-01 3 5 2 -1 2899 line = line.split() 2900 try: # Remove BR if formatting is wrong 2901 partial_width = float(line[0])*width 2902 decay_products = [int(p) for p in line[2:2+int(line[1])]] 2903 except Exception: 2904 line=param_card[line_number] 2905 continue 2906 try: 2907 decay_info[particle].append([decay_products, partial_width]) 2908 except KeyError: 2909 decay_info[particle] = [[decay_products, partial_width]] 2910 if line_number == len(param_card): 2911 break 2912 line=param_card[line_number] 2913 if particle and particle not in decay_info: 2914 # No decays given, only total width 2915 decay_info[particle] = [[[], width]] 2916 else: # Not decay 2917 line_number += 1 2918 # Clean out possible remaining comments at the end of the card 2919 while not param_card[-1] or param_card[-1].startswith('#'): 2920 param_card.pop(-1) 2921 2922 # Append calculated and read decays to the param_card 2923 param_card.append("#\n#*************************") 2924 param_card.append("# Decay widths *") 2925 param_card.append("#*************************") 2926 for key in sorted(decay_info.keys()): 2927 width = sum([r for p,r in decay_info[key]]) 2928 param_card.append("#\n# PDG Width") 2929 param_card.append("DECAY %i %e" % (key, width.real)) 2930 if not width: 2931 continue 2932 if decay_info[key][0][0]: 2933 param_card.append("# BR NDA ID1 ID2 ...") 2934 brs = [[(val[1]/width).real, val[0]] for val in decay_info[key] if val[1]] 2935 for val in sorted(brs, reverse=True): 2936 param_card.append(" %e %i %s # %s" % 2937 (val[0].real, len(val[1]), 2938 " ".join([str(v) for v in val[1]]), 2939 val[0] * width 2940 )) 2941 decay_table = open(output, 'w') 2942 decay_table.write("\n".join(param_card) + "\n") 2943 decay_table.close() 2944 logger.info("Results written to %s" % output)
2945 2946 2947 ############################################################################
2948 - def do_multi_run(self, line):
2949 2950 args = self.split_arg(line) 2951 # Check argument's validity 2952 mode = self.check_multi_run(args) 2953 nb_run = args.pop(0) 2954 if nb_run == 1: 2955 logger.warn("'multi_run 1' command is not optimal. Think of using generate_events instead") 2956 self.ask_run_configuration(mode) 2957 2958 self.check_survey(args, cmd='multi_run') 2959 main_name = self.run_name 2960 # check if the param_card requires a scan over parameter. 2961 path=pjoin(self.me_dir, 'Cards', 'param_card.dat') 2962 self.check_param_card(path, run=False) 2963 #store it locally to avoid relaunch 2964 param_card_iterator, self.param_card_iterator = self.param_card_iterator, [] 2965 2966 crossoversig = 0 2967 inv_sq_err = 0 2968 nb_event = 0 2969 for i in range(nb_run): 2970 self.nb_refine = 0 2971 self.exec_cmd('generate_events %s_%s -f' % (main_name, i), postcmd=False) 2972 # Update collected value 2973 nb_event += int(self.results[self.run_name][-1]['nb_event']) 2974 self.results.add_detail('nb_event', nb_event , run=main_name) 2975 cross = self.results[self.run_name][-1]['cross'] 2976 error = self.results[self.run_name][-1]['error'] + 1e-99 2977 crossoversig+=cross/error**2 2978 inv_sq_err+=1.0/error**2 2979 self.results[main_name][-1]['cross'] = crossoversig/inv_sq_err 2980 self.results[main_name][-1]['error'] = math.sqrt(1.0/inv_sq_err) 2981 self.results.def_current(main_name) 2982 self.run_name = main_name 2983 self.update_status("Merging LHE files", level='parton') 2984 try: 2985 os.mkdir(pjoin(self.me_dir,'Events', self.run_name)) 2986 except Exception: 2987 pass 2988 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' 2989 % {'bin': self.dirbin, 'event': pjoin(self.me_dir,'Events'), 2990 'name': self.run_name}) 2991 2992 eradir = self.options['exrootanalysis_path'] 2993 if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter')): 2994 self.update_status("Create Root file", level='parton') 2995 path = '%s/%s/unweighted_events.lhe.gz' % (pjoin(self.me_dir,'Events'), self.run_name) 2996 2997 if os.path.exists(path): 2998 misc.gunzip(path) 2999 3000 self.create_root_file('%s/unweighted_events.lhe' % self.run_name, 3001 '%s/unweighted_events.root' % self.run_name) 3002 3003 path = pjoin(self.me_dir, "Events", self.run_name, "unweighted_events.lhe") 3004 self.create_plot('parton', path, 3005 pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html') 3006 ) 3007 3008 3009 if not os.path.exists('%s.gz' % path): 3010 misc.gzip(path) 3011 3012 self.update_status('', level='parton') 3013 self.print_results_in_shell(self.results.current) 3014 3015 cpath = pjoin(self.me_dir,'Cards','param_card.dat') 3016 if param_card_iterator: 3017 3018 param_card_iterator.store_entry(self.run_name, self.results.current['cross'],param_card_path=cpath) 3019 #check if the param_card defines a scan. 3020 orig_name=self.run_name 3021 for card in param_card_iterator: 3022 card.write(cpath) 3023 self.exec_cmd("multi_run %s -f " % nb_run ,precmd=True, postcmd=True,errorhandling=False) 3024 param_card_iterator.store_entry(self.run_name, self.results.current['cross'], param_card_path=cpath) 3025 param_card_iterator.write(pjoin(self.me_dir,'Cards','param_card.dat')) 3026 scan_name = misc.get_scan_name(orig_name, self.run_name) 3027 path = pjoin(self.me_dir, 'Events','scan_%s.txt' % scan_name) 3028 logger.info("write all cross-section results in %s" % path, '$MG:BOLD') 3029 param_card_iterator.write_summary(path)
3030 3031 3032 ############################################################################
3033 - def do_treatcards(self, line, mode=None, opt=None):
3034 """Advanced commands: create .inc files from param_card.dat/run_card.dat""" 3035 3036 if not mode and not opt: 3037 args = self.split_arg(line) 3038 mode, opt = self.check_treatcards(args) 3039 3040 # To decide whether to refresh MadLoop's helicity filters, it is necessary 3041 # to check if the model parameters where modified or not, before doing 3042 # anything else. 3043 need_MadLoopFilterUpdate = False 3044 # Just to record what triggered the reinitialization of MadLoop for a 3045 # nice debug message. 3046 type_of_change = '' 3047 if not opt['forbid_MadLoopInit'] and self.proc_characteristics['loop_induced'] \ 3048 and mode in ['loop', 'all']: 3049 paramDat = pjoin(self.me_dir, 'Cards','param_card.dat') 3050 paramInc = pjoin(opt['output_dir'], 'param_card.inc') 3051 if (not os.path.isfile(paramDat)) or (not os.path.isfile(paramInc)) or \ 3052 (os.path.getmtime(paramDat)-os.path.getmtime(paramInc)) > 0.0: 3053 need_MadLoopFilterUpdate = True 3054 type_of_change = 'model' 3055 3056 ML_in = pjoin(self.me_dir, 'Cards', 'MadLoopParams.dat') 3057 ML_out = pjoin(self.me_dir,"SubProcesses", 3058 "MadLoop5_resources", "MadLoopParams.dat") 3059 if (not os.path.isfile(ML_in)) or (not os.path.isfile(ML_out)) or \ 3060 (os.path.getmtime(ML_in)-os.path.getmtime(ML_out)) > 0.0: 3061 need_MadLoopFilterUpdate = True 3062 type_of_change = 'MadLoop' 3063 3064 #check if no 'Auto' are present in the file 3065 self.check_param_card(pjoin(self.me_dir, 'Cards','param_card.dat')) 3066 3067 if mode in ['param', 'all']: 3068 model = self.find_model_name() 3069 tmp_model = os.path.basename(model) 3070 if tmp_model == 'mssm' or tmp_model.startswith('mssm-'): 3071 if not '--param_card=' in line: 3072 param_card = pjoin(self.me_dir, 'Cards','param_card.dat') 3073 mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat') 3074 check_param_card.convert_to_mg5card(param_card, mg5_param) 3075 check_param_card.check_valid_param_card(mg5_param) 3076 opt['param_card'] = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat') 3077 else: 3078 check_param_card.check_valid_param_card(opt['param_card']) 3079 3080 logger.debug('write compile file for card: %s' % opt['param_card']) 3081 param_card = check_param_card.ParamCard(opt['param_card']) 3082 outfile = pjoin(opt['output_dir'], 'param_card.inc') 3083 ident_card = pjoin(self.me_dir,'Cards','ident_card.dat') 3084 if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')): 3085 default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat') 3086 elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')): 3087 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat') 3088 elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')): 3089 fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w') 3090 fsock.write(' ') 3091 fsock.close() 3092 if mode == 'all': 3093 self.do_treatcards('', 'run', opt) 3094 return 3095 else: 3096 devnull = open(os.devnull,'w') 3097 subprocess.call([sys.executable, 'write_param_card.py'], 3098 cwd=pjoin(self.me_dir,'bin','internal','ufomodel'), 3099 stdout=devnull) 3100 devnull.close() 3101 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat') 3102 3103 need_mp = self.proc_characteristics['loop_induced'] 3104 param_card.write_inc_file(outfile, ident_card, default, need_mp=need_mp) 3105 3106 3107 if mode in ['run', 'all']: 3108 if not hasattr(self, 'run_card'): 3109 run_card = banner_mod.RunCard(opt['run_card']) 3110 else: 3111 run_card = self.run_card 3112 self.run_card = run_card 3113 if self.cluster: 3114 self.cluster.modify_interface(self) 3115 if self.ninitial == 1: 3116 run_card['lpp1'] = 0 3117 run_card['lpp2'] = 0 3118 run_card['ebeam1'] = 0 3119 run_card['ebeam2'] = 0 3120 3121 # Ensure that the bias parameters has all the required input from the 3122 # run_card 3123 if run_card['bias_module'].lower() not in ['dummy','none']: 3124 # Using basename here means that the module will not be overwritten if already existing. 3125 bias_module_path = pjoin(self.me_dir,'Source','BIAS', 3126 os.path.basename(run_card['bias_module'])) 3127 if not os.path.isdir(bias_module_path): 3128 if not os.path.isdir(run_card['bias_module']): 3129 raise InvalidCmd("The bias module at '%s' cannot be found."%run_card['bias_module']) 3130 else: 3131 for mandatory_file in ['makefile','%s.f'%os.path.basename(run_card['bias_module'])]: 3132 if not os.path.isfile(pjoin(run_card['bias_module'],mandatory_file)): 3133 raise InvalidCmd("Could not find the mandatory file '%s' in bias module '%s'."%( 3134 mandatory_file,run_card['bias_module'])) 3135 misc.copytree(run_card['bias_module'], pjoin(self.me_dir,'Source','BIAS', 3136 os.path.basename(run_card['bias_module']))) 3137 3138 #check expected parameters for the module. 3139 default_bias_parameters = {} 3140 start, last = False,False 3141 for line in open(pjoin(bias_module_path,'%s.f'%os.path.basename(bias_module_path))): 3142 if start and last: 3143 break 3144 if not start and not re.search('c\s*parameters\s*=\s*{',line, re.I): 3145 continue 3146 start = True 3147 if not line.startswith('C'): 3148 continue 3149 line = line[1:] 3150 if '{' in line: 3151 line = line.split('{')[-1] 3152 # split for } ! # 3153 split_result = re.split('(\}|!|\#)', line,1, re.M) 3154 line = split_result[0] 3155 sep = split_result[1] if len(split_result)>1 else None 3156 if sep == '}': 3157 last = True 3158 if ',' in line: 3159 for pair in line.split(','): 3160 if not pair.strip(): 3161 continue 3162 x,y =pair.split(':') 3163 x=x.strip() 3164 if x.startswith(('"',"'")) and x.endswith(x[0]): 3165 x = x[1:-1] 3166 default_bias_parameters[x] = y 3167 elif ':' in line: 3168 x,y = line.split(':') 3169 x = x.strip() 3170 if x.startswith(('"',"'")) and x.endswith(x[0]): 3171 x = x[1:-1] 3172 default_bias_parameters[x] = y 3173 for key,value in run_card['bias_parameters'].items(): 3174 if key not in default_bias_parameters: 3175 logger.warning('%s not supported by the bias module. We discard this entry.', key) 3176 else: 3177 default_bias_parameters[key] = value 3178 run_card['bias_parameters'] = default_bias_parameters 3179 3180 3181 # Finally write the include file 3182 run_card.write_include_file(opt['output_dir']) 3183 3184 3185 if self.proc_characteristics['loop_induced'] and mode in ['loop', 'all']: 3186 self.MadLoopparam = banner_mod.MadLoopParam(pjoin(self.me_dir, 3187 'Cards', 'MadLoopParams.dat')) 3188 # The writing out of MadLoop filter is potentially dangerous 3189 # when running in multi-core with a central disk. So it is turned 3190 # off here. If these filters were not initialized then they will 3191 # have to be re-computed at the beginning of each run. 3192 if 'WriteOutFilters' in self.MadLoopparam.user_set and \ 3193 self.MadLoopparam.get('WriteOutFilters'): 3194 logger.info( 3195 """You chose to have MadLoop writing out filters. 3196 Beware that this can be dangerous for local multicore runs.""") 3197 self.MadLoopparam.set('WriteOutFilters',False, changeifuserset=False) 3198 3199 # The conservative settings below for 'CTModeInit' and 'ZeroThres' 3200 # help adress issues for processes like g g > h z, and g g > h g 3201 # where there are some helicity configuration heavily suppressed 3202 # (by several orders of magnitude) so that the helicity filter 3203 # needs high numerical accuracy to correctly handle this spread in 3204 # magnitude. Also, because one cannot use the Born as a reference 3205 # scale, it is better to force quadruple precision *for the 3206 # initialization points only*. This avoids numerical accuracy issues 3207 # when setting up the helicity filters and does not significantly 3208 # slow down the run. 3209 # self.MadLoopparam.set('CTModeInit',4, changeifuserset=False) 3210 # Consequently, we can allow for a finer threshold for vanishing 3211 # helicity configuration 3212 # self.MadLoopparam.set('ZeroThres',1.0e-11, changeifuserset=False) 3213 3214 # It is a bit superficial to use the level 2 which tries to numerically 3215 # map matching helicities (because of CP symmetry typically) together. 3216 # It is useless in the context of MC over helicities and it can 3217 # potentially make the helicity double checking fail. 3218 self.MadLoopparam.set('HelicityFilterLevel',1, changeifuserset=False) 3219 3220 # To be on the safe side however, we ask for 4 consecutive matching 3221 # helicity filters. 3222 self.MadLoopparam.set('CheckCycle',4, changeifuserset=False) 3223 3224 # For now it is tricky to have each channel performing the helicity 3225 # double check. What we will end up doing is probably some kind 3226 # of new initialization round at the beginning of each launch 3227 # command, to reset the filters. 3228 self.MadLoopparam.set('DoubleCheckHelicityFilter',False, 3229 changeifuserset=False) 3230 3231 # Thanks to TIR recycling, TIR is typically much faster for Loop-induced 3232 # processes when not doing MC over helicities, so that we place OPP last. 3233 if not hasattr(self, 'run_card'): 3234 run_card = banner_mod.RunCard(opt['run_card']) 3235 else: 3236 run_card = self.run_card 3237 if run_card['nhel'] == 0: 3238 if 'MLReductionLib' in self.MadLoopparam.user_set and \ 3239 (self.MadLoopparam.get('MLReductionLib').startswith('1') or 3240 self.MadLoopparam.get('MLReductionLib').startswith('6')): 3241 logger.warning( 3242 """You chose to set the preferred reduction technique in MadLoop to be OPP (see parameter MLReductionLib). 3243 Beware that this can bring significant slowdown; the optimal choice --when not MC over helicity-- being to first start with TIR reduction.""") 3244 # We do not include GOLEM for now since it cannot recycle TIR coefs yet. 3245 self.MadLoopparam.set('MLReductionLib','7|6|1', changeifuserset=False) 3246 else: 3247 if 'MLReductionLib' in self.MadLoopparam.user_set and \ 3248 not (self.MadLoopparam.get('MLReductionLib').startswith('1') or 3249 self.MadLoopparam.get('MLReductionLib').startswith('6')): 3250 logger.warning( 3251 """You chose to set the preferred reduction technique in MadLoop to be different than OPP (see parameter MLReductionLib). 3252 Beware that this can bring significant slowdown; the optimal choice --when MC over helicity-- being to first start with OPP reduction.""") 3253 self.MadLoopparam.set('MLReductionLib','6|7|1', changeifuserset=False) 3254 3255 # Also TIR cache will only work when NRotations_DP=0 (but only matters 3256 # when not MC-ing over helicities) so it will be hard-reset by MadLoop 3257 # to zero when not MC-ing over helicities, unless the parameter 3258 # Force_ML_Helicity_Sum is set to True in the matrix<i>.f codes. 3259 if run_card['nhel'] == 0: 3260 if ('NRotations_DP' in self.MadLoopparam.user_set and \ 3261 self.MadLoopparam.get('NRotations_DP')!=0) or \ 3262 ('NRotations_QP' in self.MadLoopparam.user_set and \ 3263 self.MadLoopparam.get('NRotations_QP')!=0): 3264 logger.warning( 3265 """You chose to also use a lorentz rotation for stability tests (see parameter NRotations_[DP|QP]). 3266 Beware that, for optimization purposes, MadEvent uses manual TIR cache clearing which is not compatible 3267 with the lorentz rotation stability test. The number of these rotations to be used will be reset to 3268 zero by MadLoop. You can avoid this by changing the parameter 'FORCE_ML_HELICITY_SUM' int he matrix<i>.f 3269 files to be .TRUE. so that the sum over helicity configurations is performed within MadLoop (in which case 3270 the helicity of final state particles cannot be speicfied in the LHE file.""") 3271 self.MadLoopparam.set('NRotations_DP',0,changeifuserset=False) 3272 self.MadLoopparam.set('NRotations_QP',0,changeifuserset=False) 3273 else: 3274 # When MC-ing over helicities, the manual TIR cache clearing is 3275 # not necessary, so that one can use the lorentz check 3276 # Using NRotations_DP=1 slows down the code by close to 100% 3277 # but it is typicaly safer. 3278 # self.MadLoopparam.set('NRotations_DP',0,changeifuserset=False) 3279 # Revert to the above to be slightly less robust but twice faster. 3280 self.MadLoopparam.set('NRotations_DP',1,changeifuserset=False) 3281 self.MadLoopparam.set('NRotations_QP',0,changeifuserset=False) 3282 3283 # Finally, the stability tests are slightly less reliable for process 3284 # with less or equal than 4 final state particles because the 3285 # accessible kinematic is very limited (i.e. lorentz rotations don't 3286 # shuffle invariants numerics much). In these cases, we therefore 3287 # increase the required accuracy to 10^-7. 3288 # This is important for getting g g > z z [QCD] working with a 3289 # ptheavy cut as low as 1 GeV. 3290 if self.proc_characteristics['nexternal']<=4: 3291 if ('MLStabThres' in self.MadLoopparam.user_set and \ 3292 self.MadLoopparam.get('MLStabThres')>1.0e-7): 3293 logger.warning( 3294 """You chose to increase the default value of the MadLoop parameter 'MLStabThres' above 1.0e-7. 3295 Stability tests can be less reliable on the limited kinematic of processes with less or equal 3296 than four external legs, so this is not recommended (especially not for g g > z z).""") 3297 self.MadLoopparam.set('MLStabThres',1.0e-7,changeifuserset=False) 3298 else: 3299 self.MadLoopparam.set('MLStabThres',1.0e-4,changeifuserset=False) 3300 3301 #write the output file 3302 self.MadLoopparam.write(pjoin(self.me_dir,"SubProcesses","MadLoop5_resources", 3303 "MadLoopParams.dat")) 3304 3305 if self.proc_characteristics['loop_induced'] and mode in ['loop', 'all']: 3306 # Now Update MadLoop filters if necessary (if modifications were made to 3307 # the model parameters). 3308 if need_MadLoopFilterUpdate: 3309 logger.debug('Changes to the %s parameters'%type_of_change+\ 3310 ' have been detected. Madevent will then now reinitialize'+\ 3311 ' MadLoop filters.') 3312 self.exec_cmd('initMadLoop -r -f') 3313 # The need_MadLoopInit condition is just there so as to avoid useless 3314 # printout if there is not initialization to be performed. But even 3315 # without it, and because we call 'initMadLoop' without the '-r' option 3316 # no time would be wasted anyway, since the existing filters would not 3317 # be overwritten. 3318 elif not opt['forbid_MadLoopInit'] and \ 3319 MadLoopInitializer.need_MadLoopInit(self.me_dir): 3320 self.exec_cmd('initMadLoop -f')
3321 3322 ############################################################################
3323 - def do_survey(self, line):
3324 """Advanced commands: launch survey for the current process """ 3325 3326 3327 args = self.split_arg(line) 3328 # Check argument's validity 3329 self.check_survey(args) 3330 # initialize / remove lhapdf mode 3331 3332 if os.path.exists(pjoin(self.me_dir,'error')): 3333 os.remove(pjoin(self.me_dir,'error')) 3334 3335 self.configure_directory() 3336 # Save original random number 3337 self.random_orig = self.random 3338 logger.info("Using random number seed offset = %s" % self.random) 3339 # Update random number 3340 self.update_random() 3341 self.save_random() 3342 self.update_status('Running Survey', level=None) 3343 if self.cluster_mode: 3344 logger.info('Creating Jobs') 3345 3346 self.total_jobs = 0 3347 subproc = [l.strip() for l in open(pjoin(self.me_dir, 3348 'SubProcesses', 'subproc.mg'))] 3349 3350 P_zero_result = [] # check the number of times where they are no phase-space 3351 3352 # File for the loop (for loop induced) 3353 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 3354 'MadLoop5_resources')) and cluster.need_transfer(self.options): 3355 tf=tarfile.open(pjoin(self.me_dir, 'SubProcesses', 3356 'MadLoop5_resources.tar.gz'), 'w:gz', dereference=True) 3357 tf.add(pjoin(self.me_dir,'SubProcesses','MadLoop5_resources'), 3358 arcname='MadLoop5_resources') 3359 tf.close() 3360 3361 logger.info('Working on SubProcesses') 3362 ajobcreator = gen_ximprove.gensym(self) 3363 3364 #check difficult PS case 3365 if float(self.run_card['mmjj']) > 0.01 * (float(self.run_card['ebeam1'])+float(self.run_card['ebeam2'])): 3366 self.pass_in_difficult_integration_mode() 3367 elif self.run_card['hard_survey']: 3368 self.pass_in_difficult_integration_mode(self.run_card['hard_survey']) 3369 3370 if self.proc_characteristics['hel_recycling'] and self.run_card['hel_recycling']: 3371 jobs, P_zero_result = ajobcreator.get_helicity() 3372 else: 3373 for p in subproc: 3374 for f in misc.glob('matrix*_orig.f', pjoin(self.me_dir, 'SubProcesses', p)): 3375 new_file = f.replace('_orig','_optim') 3376 files.cp(f, f.replace('_orig','_optim')) 3377 f = '%s.o' % f[:-2] 3378 if os.path.exists(f): 3379 files.cp(f, f.replace('_orig','_optim')) 3380 try: 3381 os.remove(pjoin(self.me_dir, 'SubProcesses', p, 'Hel', 'selection')) 3382 except Exception as error: 3383 logger.debug(error) 3384 pass 3385 3386 jobs, P_zero_result = ajobcreator.launch() 3387 # Check if all or only some fails 3388 if P_zero_result: 3389 if len(P_zero_result) == len(subproc): 3390 Pdir = pjoin(self.me_dir, 'SubProcesses',subproc[0].strip()) 3391 raise ZeroResult('%s' % \ 3392 open(pjoin(Pdir,'ajob.no_ps.log')).read()) 3393 else: 3394 logger.warning(''' %s SubProcesses doesn\'t have available phase-space. 3395 Please check mass spectrum.''' % ','.join(P_zero_result)) 3396 self.get_Gdir() 3397 for P in P_zero_result: 3398 self.Gdirs[0][pjoin(self.me_dir,'SubProcesses',P)] = [] 3399 3400 self.monitor(run_type='All jobs submitted for survey', html=True) 3401 if not self.history or 'survey' in self.history[-1] or self.ninitial ==1 or \ 3402 self.run_card['gridpack']: 3403 #will be done during the refine (more precisely in gen_ximprove) 3404 cross, error = self.make_make_all_html_results() 3405 self.results.add_detail('cross', cross) 3406 self.results.add_detail('error', error) 3407 self.exec_cmd("print_results %s" % self.run_name, 3408 errorhandling=False, printcmd=False, precmd=False, postcmd=False) 3409 3410 self.results.add_detail('run_statistics', dict(ajobcreator.run_statistics)) 3411 self.update_status('End survey', 'parton', makehtml=False)
3412 3413 ############################################################################
3414 - def pass_in_difficult_integration_mode(self, rate=1):
3415 """be more secure for the integration to not miss it due to strong cut""" 3416 3417 # improve survey options if default 3418 if self.opts['points'] == self._survey_options['points'][1]: 3419 self.opts['points'] = (rate+2) * self._survey_options['points'][1] 3420 if self.opts['iterations'] == self._survey_options['iterations'][1]: 3421 self.opts['iterations'] = 1 + rate + self._survey_options['iterations'][1] 3422 if self.opts['accuracy'] == self._survey_options['accuracy'][1]: 3423 self.opts['accuracy'] = self._survey_options['accuracy'][1]/(rate+2) 3424 3425 # Modify run_config.inc in order to improve the refine 3426 conf_path = pjoin(self.me_dir, 'Source','run_config.inc') 3427 files.cp(conf_path, conf_path + '.bk') 3428 # 3429 text = open(conf_path).read() 3430 min_evt, max_evt = 2500 *(2+rate), 10000*(rate+1) 3431 3432 text = re.sub('''\(min_events = \d+\)''', '(min_events = %i )' % min_evt, text) 3433 text = re.sub('''\(max_events = \d+\)''', '(max_events = %i )' % max_evt, text) 3434 fsock = open(conf_path, 'w') 3435 fsock.write(text) 3436 fsock.close() 3437 3438 # Compile 3439 for name in ['../bin/internal/gen_ximprove', 'all']: 3440 self.compile(arg=[name], cwd=os.path.join(self.me_dir, 'Source'))
3441 3442 3443 ############################################################################
3444 - def do_refine(self, line):
3445 """Advanced commands: launch survey for the current process """ 3446 devnull = open(os.devnull, 'w') 3447 self.nb_refine += 1 3448 args = self.split_arg(line) 3449 treshold=None 3450 3451 3452 3453 for a in args: 3454 if a.startswith('--treshold='): 3455 treshold = float(a.split('=',1)[1]) 3456 old_xsec = self.results.current['prev_cross'] 3457 new_xsec = self.results.current['cross'] 3458 if old_xsec > new_xsec * treshold: 3459 logger.info('No need for second refine due to stability of cross-section') 3460 return 3461 else: 3462 args.remove(a) 3463 break 3464 # Check argument's validity 3465 self.check_refine(args) 3466 3467 refine_opt = {'err_goal': args[0], 'split_channels': True} 3468 precision = args[0] 3469 if len(args) == 2: 3470 refine_opt['max_process']= args[1] 3471 3472 # initialize / remove lhapdf mode 3473 self.configure_directory() 3474 3475 # Update random number 3476 self.update_random() 3477 self.save_random() 3478 3479 if self.cluster_mode: 3480 logger.info('Creating Jobs') 3481 self.update_status('Refine results to %s' % precision, level=None) 3482 3483 self.total_jobs = 0 3484 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 3485 'subproc.mg'))] 3486 3487 # cleanning the previous job 3488 for nb_proc,subdir in enumerate(subproc): 3489 subdir = subdir.strip() 3490 Pdir = pjoin(self.me_dir, 'SubProcesses', subdir) 3491 for match in misc.glob('*ajob*', Pdir): 3492 if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']: 3493 os.remove(match) 3494 3495 x_improve = gen_ximprove.gen_ximprove(self, refine_opt) 3496 # Load the run statistics from the survey 3497 survey_statistics = dict(self.results.get_detail('run_statistics')) 3498 # Printout survey statistics 3499 if __debug__ and survey_statistics: 3500 globalstat = sum_html.RunStatistics() 3501 logger.debug(" === Survey statistics summary ===") 3502 for key, value in survey_statistics.items(): 3503 globalstat.aggregate_statistics(value) 3504 level = 5 3505 if value.has_warning(): 3506 level = 10 3507 logger.log(level, 3508 value.nice_output(str('/'.join([key[0],'G%s'%key[1]]))). 3509 replace(' statistics','')) 3510 logger.debug(globalstat.nice_output('combined', no_warning=True)) 3511 3512 if survey_statistics: 3513 x_improve.run_statistics = survey_statistics 3514 3515 x_improve.launch() # create the ajob for the refinment. 3516 if not self.history or 'refine' not in self.history[-1]: 3517 cross, error = x_improve.update_html() #update html results for survey 3518 if cross == 0: 3519 return 3520 logger.info("- Current estimate of cross-section: %s +- %s" % (cross, error)) 3521 if isinstance(x_improve, gen_ximprove.gen_ximprove_v4): 3522 # Non splitted mode is based on writting ajob so need to track them 3523 # Splitted mode handle the cluster submition internally. 3524 for nb_proc,subdir in enumerate(subproc): 3525 subdir = subdir.strip() 3526 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir) 3527 bindir = pjoin(os.path.relpath(self.dirbin, Pdir)) 3528 3529 logger.info(' %s ' % subdir) 3530 3531 if os.path.exists(pjoin(Pdir, 'ajob1')): 3532 self.compile(['madevent'], cwd=Pdir) 3533 3534 alljobs = misc.glob('ajob*', Pdir) 3535 3536 #remove associated results.dat (ensure to not mix with all data) 3537 Gre = re.compile("\s*j=(G[\d\.\w]+)") 3538 for job in alljobs: 3539 Gdirs = Gre.findall(open(job).read()) 3540 for Gdir in Gdirs: 3541 if os.path.exists(pjoin(Pdir, Gdir, 'results.dat')): 3542 os.remove(pjoin(Pdir, Gdir,'results.dat')) 3543 3544 nb_tot = len(alljobs) 3545 self.total_jobs += nb_tot 3546 for i, job in enumerate(alljobs): 3547 job = os.path.basename(job) 3548 self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1), 3549 run_type='Refine number %s on %s (%s/%s)' % 3550 (self.nb_refine, subdir, nb_proc+1, len(subproc))) 3551 3552 self.monitor(run_type='All job submitted for refine number %s' % self.nb_refine, 3553 html=True) 3554 3555 self.update_status("Combining runs", level='parton') 3556 try: 3557 os.remove(pjoin(Pdir, 'combine_runs.log')) 3558 except Exception: 3559 pass 3560 3561 if isinstance(x_improve, gen_ximprove.gen_ximprove_v4): 3562 # the merge of the events.lhe is handle in the x_improve class 3563 # for splitted runs. (and partly in store_events). 3564 combine_runs.CombineRuns(self.me_dir) 3565 self.refine_mode = "old" 3566 else: 3567 self.refine_mode = "new" 3568 3569 cross, error = self.make_make_all_html_results() 3570 self.results.add_detail('cross', cross) 3571 self.results.add_detail('error', error) 3572 3573 self.results.add_detail('run_statistics', 3574 dict(self.results.get_detail('run_statistics'))) 3575 3576 self.update_status('finish refine', 'parton', makehtml=False) 3577 devnull.close()
3578 3579 ############################################################################
3580 - def do_combine_iteration(self, line):
3581 """Not in help: Combine a given iteration combine_iteration Pdir Gdir S|R step 3582 S is for survey 3583 R is for refine 3584 step is the iteration number (not very critical)""" 3585 3586 self.set_run_name("tmp") 3587 self.configure_directory(html_opening=False) 3588 Pdir, Gdir, mode, step = self.split_arg(line) 3589 if Gdir.startswith("G"): 3590 Gdir = Gdir[1:] 3591 if "SubProcesses" not in Pdir: 3592 Pdir = pjoin(self.me_dir, "SubProcesses", Pdir) 3593 if mode == "S": 3594 self.opts = dict([(key,value[1]) for (key,value) in \ 3595 self._survey_options.items()]) 3596 gensym = gen_ximprove.gensym(self) 3597 gensym.combine_iteration(Pdir, Gdir, int(step)) 3598 elif mode == "R": 3599 refine = gen_ximprove.gen_ximprove_share(self) 3600 refine.combine_iteration(Pdir, Gdir, int(step))
3601 3602 3603 3604 3605 ############################################################################
3606 - def do_combine_events(self, line):
3607 """Advanced commands: Launch combine events""" 3608 3609 args = self.split_arg(line) 3610 # Check argument's validity 3611 self.check_combine_events(args) 3612 self.update_status('Combining Events', level='parton') 3613 3614 3615 if self.run_card['gridpack'] and isinstance(self, GridPackCmd): 3616 return GridPackCmd.do_combine_events(self, line) 3617 3618 3619 # Define The Banner 3620 tag = self.run_card['run_tag'] 3621 # Update the banner with the pythia card 3622 if not self.banner: 3623 self.banner = banner_mod.recover_banner(self.results, 'parton') 3624 self.banner.load_basic(self.me_dir) 3625 # Add cross-section/event information 3626 self.banner.add_generation_info(self.results.current['cross'], self.run_card['nevents']) 3627 if not hasattr(self, 'random_orig'): self.random_orig = 0 3628 self.banner.change_seed(self.random_orig) 3629 if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)): 3630 os.mkdir(pjoin(self.me_dir, 'Events', self.run_name)) 3631 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, 3632 '%s_%s_banner.txt' % (self.run_name, tag))) 3633 3634 3635 get_wgt = lambda event: event.wgt 3636 AllEvent = lhe_parser.MultiEventFile() 3637 AllEvent.banner = self.banner 3638 3639 partials = 0 # if too many file make some partial unweighting 3640 sum_xsec, sum_xerru, sum_axsec = 0,[],0 3641 Gdirs = self.get_Gdir() 3642 Gdirs.sort() 3643 for Gdir in Gdirs: 3644 if os.path.exists(pjoin(Gdir, 'events.lhe')): 3645 result = sum_html.OneResult('') 3646 result.read_results(pjoin(Gdir, 'results.dat')) 3647 sum_xsec += result.get('xsec') 3648 sum_xerru.append(result.get('xerru')) 3649 sum_axsec += result.get('axsec') 3650 3651 if self.run_card['gridpack'] or self.run_card['nevents']==0: 3652 os.remove(pjoin(Gdir, 'events.lhe')) 3653 continue 3654 3655 AllEvent.add(pjoin(Gdir, 'events.lhe'), 3656 result.get('xsec'), 3657 result.get('xerru'), 3658 result.get('axsec') 3659 ) 3660 3661 if len(AllEvent) >= 80: #perform a partial unweighting 3662 AllEvent.unweight(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe.gz" % partials), 3663 get_wgt, log_level=5, trunc_error=1e-2, event_target=self.run_card['nevents']) 3664 AllEvent = lhe_parser.MultiEventFile() 3665 AllEvent.banner = self.banner 3666 AllEvent.add(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe.gz" % partials), 3667 sum_xsec, 3668 math.sqrt(sum(x**2 for x in sum_xerru)), 3669 sum_axsec) 3670 partials +=1 3671 3672 if not hasattr(self,'proc_characteristic'): 3673 self.proc_characteristic = self.get_characteristics() 3674 if len(AllEvent) == 0: 3675 nb_event = 0 3676 else: 3677 nb_event = AllEvent.unweight(pjoin(self.me_dir, "Events", self.run_name, "unweighted_events.lhe.gz"), 3678 get_wgt, trunc_error=1e-2, event_target=self.run_card['nevents'], 3679 log_level=logging.DEBUG, normalization=self.run_card['event_norm'], 3680 proc_charac=self.proc_characteristic) 3681 if partials: 3682 for i in range(partials): 3683 try: 3684 os.remove(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe.gz" % i)) 3685 except Exception: 3686 os.remove(pjoin(self.me_dir, "Events", self.run_name, "partials%s.lhe" % i)) 3687 3688 self.results.add_detail('nb_event', nb_event) 3689 3690 if self.run_card['bias_module'].lower() not in ['dummy', 'none'] and nb_event: 3691 self.correct_bias() 3692 3693 3694 3695 self.to_store.append('event')
3696 3697 ############################################################################
3698 - def correct_bias(self):
3699 """check the first event and correct the weight by the bias 3700 and correct the cross-section. 3701 If the event do not have the bias tag it means that the bias is 3702 one modifying the cross-section/shape so we have nothing to do 3703 """ 3704 3705 lhe = lhe_parser.EventFile(pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')) 3706 init = False 3707 cross = collections.defaultdict(float) 3708 nb_event = 0 3709 for event in lhe: 3710 rwgt_info = event.parse_reweight() 3711 if not init: 3712 if 'bias' in rwgt_info: 3713 output = lhe_parser.EventFile(pjoin(self.me_dir, 'Events', self.run_name, '.unweighted_events.lhe.tmp.gz'),'w') 3714 #output.write(lhe.banner) 3715 init = True 3716 else: 3717 return 3718 #change the weight 3719 event.wgt /= rwgt_info['bias'] 3720 #remove the bias info 3721 del event.reweight_data['bias'] 3722 # compute the new cross-section 3723 cross[event.ievent] += event.wgt 3724 nb_event +=1 3725 output.write(str(event)) 3726 output.write('</LesHouchesEvents>') 3727 output.close() 3728 lhe.close() 3729 3730 # MODIFY THE BANNER i.e. INIT BLOCK 3731 # ensure information compatible with normalisation choice 3732 total_cross = sum(cross[key] for key in cross) 3733 if 'event_norm' in self.run_card: # if not this is "sum" 3734 if self.run_card['event_norm'] == 'average': 3735 total_cross = total_cross / nb_event 3736 for key in cross: 3737 cross[key] /= nb_event 3738 elif self.run_card['event_norm'] == 'unity': 3739 total_cross = self.results.current['cross'] * total_cross / nb_event 3740 for key in cross: 3741 cross[key] *= total_cross / nb_event 3742 3743 bannerfile = lhe_parser.EventFile(pjoin(self.me_dir, 'Events', self.run_name, '.banner.tmp.gz'),'w') 3744 banner = banner_mod.Banner(lhe.banner) 3745 banner.modify_init_cross(cross) 3746 banner.set_lha_strategy(-4) 3747 banner.write(bannerfile, close_tag=False) 3748 bannerfile.close() 3749 # replace the lhe file by the new one 3750 if lhe.name.endswith('.gz'): 3751 os.system('cat %s %s > %s' %(bannerfile.name, output.name, lhe.name)) 3752 else: 3753 os.system('cat %s %s > %s.gz' %(bannerfile.name, output.name, lhe.name)) 3754 os.remove(lhe.name) 3755 os.remove(bannerfile.name) 3756 os.remove(output.name) 3757 3758 3759 self.results.current['cross'] = total_cross 3760 self.results.current['error'] = 0
3761 3762 ############################################################################
3763 - def do_store_events(self, line):
3764 """Advanced commands: Launch store events""" 3765 3766 args = self.split_arg(line) 3767 # Check argument's validity 3768 self.check_combine_events(args) 3769 self.update_status('Storing parton level results', level='parton') 3770 3771 run = self.run_name 3772 tag = self.run_card['run_tag'] 3773 devnull = open(os.devnull, 'w') 3774 3775 if not os.path.exists(pjoin(self.me_dir, 'Events', run)): 3776 os.mkdir(pjoin(self.me_dir, 'Events', run)) 3777 if not os.path.exists(pjoin(self.me_dir, 'HTML', run)): 3778 os.mkdir(pjoin(self.me_dir, 'HTML', run)) 3779 3780 # 1) Store overall process information 3781 #input = pjoin(self.me_dir, 'SubProcesses', 'results.dat') 3782 #output = pjoin(self.me_dir, 'SubProcesses', '%s_results.dat' % run) 3783 #files.cp(input, output) 3784 3785 3786 # 2) Treat the files present in the P directory 3787 # Ensure that the number of events is different of 0 3788 if self.results.current['nb_event'] == 0 and not self.run_card['gridpack']: 3789 logger.warning("No event detected. No cleaning performed! This should allow to run:\n" + 3790 " cd Subprocesses; ../bin/internal/combine_events\n"+ 3791 " to have your events if those one are missing.") 3792 else: 3793 for G_path in self.get_Gdir(): 3794 try: 3795 # Remove events file (if present) 3796 if os.path.exists(pjoin(G_path, 'events.lhe')): 3797 os.remove(pjoin(G_path, 'events.lhe')) 3798 except Exception: 3799 continue 3800 #try: 3801 # # Store results.dat 3802 # if os.path.exists(pjoin(G_path, 'results.dat')): 3803 # input = pjoin(G_path, 'results.dat') 3804 # output = pjoin(G_path, '%s_results.dat' % run) 3805 # files.cp(input, output) 3806 #except Exception: 3807 # continue 3808 # Store log 3809 try: 3810 if os.path.exists(pjoin(G_path, 'log.txt')): 3811 input = pjoin(G_path, 'log.txt') 3812 output = pjoin(G_path, '%s_log.txt' % run) 3813 files.mv(input, output) 3814 except Exception: 3815 continue 3816 #try: 3817 # # Grid 3818 # for name in ['ftn26']: 3819 # if os.path.exists(pjoin(G_path, name)): 3820 # if os.path.exists(pjoin(G_path, '%s_%s.gz'%(run,name))): 3821 # os.remove(pjoin(G_path, '%s_%s.gz'%(run,name))) 3822 # input = pjoin(G_path, name) 3823 # output = pjoin(G_path, '%s_%s' % (run,name)) 3824 # files.mv(input, output) 3825 # misc.gzip(pjoin(G_path, output), error=None) 3826 #except Exception: 3827 # continue 3828 # Delete ftn25 to ensure reproducible runs 3829 if os.path.exists(pjoin(G_path, 'ftn25')): 3830 os.remove(pjoin(G_path, 'ftn25')) 3831 3832 # 3) Update the index.html 3833 self.gen_card_html() 3834 3835 3836 # 4) Move the Files present in Events directory 3837 E_path = pjoin(self.me_dir, 'Events') 3838 O_path = pjoin(self.me_dir, 'Events', run) 3839 3840 # The events file 3841 for name in ['events.lhe', 'unweighted_events.lhe']: 3842 finput = pjoin(E_path, name) 3843 foutput = pjoin(O_path, name) 3844 if os.path.exists(finput): 3845 logger.debug("File %s exists BAAAAD. Not move anymore!" % pjoin(E_path, name)) 3846 if os.path.exists(foutput): 3847 if os.path.exists("%s.gz" % foutput): 3848 os.remove(foutput) 3849 else: 3850 misc.gzip(foutput, stdout="%s.gz" % foutput, error=False) 3851 # if os.path.exists(pjoin(O_path, '%s.gz' % name)): 3852 # os.remove(pjoin(O_path, '%s.gz' % name)) 3853 # input = pjoin(E_path, name) 3854 ## output = pjoin(O_path, name) 3855 3856 3857 self.update_status('End Parton', level='parton', makehtml=False) 3858 devnull.close()
3859 3860 3861 ############################################################################
3862 - def do_create_gridpack(self, line):
3863 """Advanced commands: Create gridpack from present run""" 3864 3865 self.update_status('Creating gridpack', level='parton') 3866 # compile gen_ximprove 3867 misc.compile(['../bin/internal/gen_ximprove'], cwd=pjoin(self.me_dir, "Source")) 3868 3869 Gdir = self.get_Gdir() 3870 Pdir = set([os.path.dirname(G) for G in Gdir]) 3871 for P in Pdir: 3872 allG = misc.glob('G*', path=P) 3873 for G in allG: 3874 if pjoin(P, G) not in Gdir: 3875 logger.debug('removing %s', pjoin(P,G)) 3876 shutil.rmtree(pjoin(P,G)) 3877 3878 3879 args = self.split_arg(line) 3880 self.check_combine_events(args) 3881 if not self.run_tag: self.run_tag = 'tag_1' 3882 os.system("sed -i.bak \"s/ *.false.*=.*GridRun/ .true. = GridRun/g\" %s/Cards/grid_card.dat" \ 3883 % self.me_dir) 3884 misc.call(['./bin/internal/restore_data', self.run_name], 3885 cwd=self.me_dir) 3886 misc.call(['./bin/internal/store4grid', 3887 self.run_name, self.run_tag], 3888 cwd=self.me_dir) 3889 misc.call(['./bin/internal/clean'], cwd=self.me_dir) 3890 misc.call(['./bin/internal/make_gridpack'], cwd=self.me_dir) 3891 files.mv(pjoin(self.me_dir, 'gridpack.tar.gz'), 3892 pjoin(self.me_dir, '%s_gridpack.tar.gz' % self.run_name)) 3893 os.system("sed -i.bak \"s/\s*.true.*=.*GridRun/ .false. = GridRun/g\" %s/Cards/grid_card.dat" \ 3894 % self.me_dir) 3895 self.update_status('gridpack created', level='gridpack')
3896 3897 ############################################################################
3898 - def do_shower(self, line):
3899 """launch the shower""" 3900 3901 args = self.split_arg(line) 3902 if len(args)>1 and args[0] in self._interfaced_showers: 3903 chosen_showers = [args.pop(0)] 3904 elif '--no_default' in line: 3905 # If '--no_default' was specified in the arguments, then only one 3906 # shower will be run, depending on which card is present. 3907 # but we each of them are called. (each of them check if the file exists) 3908 chosen_showers = list(self._interfaced_showers) 3909 else: 3910 chosen_showers = list(self._interfaced_showers) 3911 # It is preferable to run only one shower, even if several are available and no 3912 # specific one has been selected 3913 shower_priority = ['pythia8','pythia'] 3914 chosen_showers = [sorted(chosen_showers,key=lambda sh: 3915 shower_priority.index(sh) if sh in shower_priority else len(shower_priority)+1)[0]] 3916 3917 for shower in chosen_showers: 3918 self.exec_cmd('%s %s'%(shower,' '.join(args)), 3919 postcmd=False, printcmd=False)
3920
3921 - def do_madanalysis5_parton(self, line):
3922 """launch MadAnalysis5 at the parton level.""" 3923 return self.run_madanalysis5(line,mode='parton')
3924 3925 #=============================================================================== 3926 # Return a warning (if applicable) on the consistency of the current Pythia8 3927 # and MG5_aMC version specified. It is placed here because it should be accessible 3928 # from both madgraph5_interface and madevent_interface 3929 #=============================================================================== 3930 @staticmethod
3931 - def mg5amc_py8_interface_consistency_warning(options):
3932 """ Check the consistency of the mg5amc_py8_interface installed with 3933 the current MG5 and Pythia8 versions. """ 3934 3935 # All this is only relevant is Pythia8 is interfaced to MG5 3936 if not options['pythia8_path']: 3937 return None 3938 3939 if not options['mg5amc_py8_interface_path']: 3940 return \ 3941 """ 3942 A Pythia8 path is specified via the option 'pythia8_path' but no path for option 3943 'mg5amc_py8_interface_path' is specified. This means that Pythia8 cannot be used 3944 leading order simulations with MadEvent. 3945 Consider installing the MG5_aMC-PY8 interface with the following command: 3946 MG5_aMC>install mg5amc_py8_interface 3947 """ 3948 3949 mg5amc_py8_interface_path = options['mg5amc_py8_interface_path'] 3950 py8_path = options['pythia8_path'] 3951 # If the specified interface path is relative, make it absolut w.r.t MGDIR if 3952 # avaialble. 3953 if not MADEVENT: 3954 mg5amc_py8_interface_path = pjoin(MG5DIR,mg5amc_py8_interface_path) 3955 py8_path = pjoin(MG5DIR,py8_path) 3956 3957 # Retrieve all the on-install and current versions 3958 fsock = open(pjoin(mg5amc_py8_interface_path, 'MG5AMC_VERSION_ON_INSTALL')) 3959 MG5_version_on_install = fsock.read().replace('\n','') 3960 fsock.close() 3961 if MG5_version_on_install == 'UNSPECIFIED': 3962 MG5_version_on_install = None 3963 fsock = open(pjoin(mg5amc_py8_interface_path, 'PYTHIA8_VERSION_ON_INSTALL')) 3964 PY8_version_on_install = fsock.read().replace('\n','') 3965 fsock.close() 3966 MG5_curr_version =misc.get_pkg_info()['version'] 3967 try: 3968 p = subprocess.Popen(['./get_pythia8_version.py',py8_path], 3969 stdout=subprocess.PIPE, stderr=subprocess.PIPE, 3970 cwd=mg5amc_py8_interface_path) 3971 (out, err) = p.communicate() 3972 out = out.decode().replace('\n','') 3973 PY8_curr_version = out 3974 # In order to test that the version is correctly formed, we try to cast 3975 # it to a float 3976 float(out) 3977 except: 3978 PY8_curr_version = None 3979 3980 if not MG5_version_on_install is None and not MG5_curr_version is None: 3981 if MG5_version_on_install != MG5_curr_version: 3982 return \ 3983 """ 3984 The current version of MG5_aMC (v%s) is different than the one active when 3985 installing the 'mg5amc_py8_interface_path' (which was MG5aMC v%s). 3986 Please consider refreshing the installation of this interface with the command: 3987 MG5_aMC>install mg5amc_py8_interface 3988 """%(MG5_curr_version, MG5_version_on_install) 3989 3990 if not PY8_version_on_install is None and not PY8_curr_version is None: 3991 if PY8_version_on_install != PY8_curr_version: 3992 return \ 3993 """ 3994 The current version of Pythia8 (v%s) is different than the one active when 3995 installing the 'mg5amc_py8_interface' tool (which was Pythia8 v%s). 3996 Please consider refreshing the installation of this interface with the command: 3997 MG5_aMC>install mg5amc_py8_interface 3998 """%(PY8_curr_version,PY8_version_on_install) 3999 4000 return None
4001
4002 - def setup_Pythia8RunAndCard(self, PY8_Card, run_type):
4003 """ Setup the Pythia8 Run environment and card. In particular all the process and run specific parameters 4004 of the card are automatically set here. This function returns the path where HEPMC events will be output, 4005 if any.""" 4006 4007 HepMC_event_output = None 4008 tag = self.run_tag 4009 4010 PY8_Card.subruns[0].systemSet('Beams:LHEF',"unweighted_events.lhe.gz") 4011 if PY8_Card['HEPMCoutput:file'] in ['auto', 'autoremove']: 4012 if PY8_Card['HEPMCoutput:file'] == 'autoremove': 4013 self.to_store.append('nopy8') 4014 elif 'nopy8' in self.to_store: 4015 self.to_store.remove('nopy8') 4016 HepMC_event_output = pjoin(self.me_dir,'Events', self.run_name, 4017 '%s_pythia8_events.hepmc'%tag) 4018 PY8_Card.MadGraphSet('HEPMCoutput:file','%s_pythia8_events.hepmc'%tag, force=True) 4019 elif PY8_Card['HEPMCoutput:file'].startswith('fifo'): 4020 fifo_specs = PY8_Card['HEPMCoutput:file'].split('@') 4021 fifo_path = None 4022 if len(fifo_specs)<=1: 4023 fifo_path = pjoin(self.me_dir,'Events', self.run_name,'PY8.hepmc.fifo') 4024 if os.path.exists(fifo_path): 4025 os.remove(fifo_path) 4026 misc.mkfifo(fifo_path) 4027 # Use defaultSet not to overwrite the current userSet status 4028 PY8_Card.defaultSet('HEPMCoutput:file','PY8.hepmc.fifo') 4029 else: 4030 fifo_path = fifo_specs[1] 4031 if os.path.exists(fifo_path): 4032 if stat.S_ISFIFO(os.stat(fifo_path).st_mode): 4033 logger.warning('PY8 will be reusing already existing '+ 4034 'custom fifo file at:\n %s'%fifo_path) 4035 else: 4036 raise InvalidCmd( 4037 """The fifo path speficied for the PY8 parameter 'HEPMCoutput:file': 4038 %s 4039 already exists and is not a fifo file."""%fifo_path) 4040 else: 4041 misc.mkfifo(fifo_path) 4042 # Use defaultSet not to overwrite the current userSet status 4043 PY8_Card.defaultSet('HEPMCoutput:file',fifo_path) 4044 HepMC_event_output=fifo_path 4045 elif PY8_Card['HEPMCoutput:file'] in ['','/dev/null','None']: 4046 logger.warning('User disabled the HepMC output of Pythia8.') 4047 HepMC_event_output = None 4048 else: 4049 # Normalize the relative path if given as relative by the user. 4050 HepMC_event_output = pjoin(self.me_dir,'Events', self.run_name, 4051 PY8_Card['HEPMCoutput:file']) 4052 4053 # We specify by hand all necessary parameters, so that there is no 4054 # need to read parameters from the Banner. 4055 PY8_Card.MadGraphSet('JetMatching:setMad', False) 4056 if run_type=='MLM': 4057 # When running MLM make sure that we do not write out the parameter 4058 # Merging:xxx as this can interfere with the MLM merging in older 4059 # versions of the driver. 4060 PY8_Card.vetoParamWriteOut('Merging:TMS') 4061 PY8_Card.vetoParamWriteOut('Merging:Process') 4062 PY8_Card.vetoParamWriteOut('Merging:nJetMax') 4063 # MadGraphSet sets the corresponding value (in system mode) 4064 # only if it is not already user_set. 4065 if PY8_Card['JetMatching:qCut']==-1.0: 4066 PY8_Card.MadGraphSet('JetMatching:qCut',1.5*self.run_card['xqcut'], force=True) 4067 4068 if PY8_Card['JetMatching:qCut']<(1.5*self.run_card['xqcut']): 4069 logger.error( 4070 'The MLM merging qCut parameter you chose (%f) is less than '%PY8_Card['JetMatching:qCut']+ 4071 '1.5*xqcut, with xqcut your run_card parameter (=%f).\n'%self.run_card['xqcut']+ 4072 'It would be better/safer to use a larger qCut or a smaller xqcut.') 4073 4074 # Also make sure to use the shower starting scales specified in the LHE 4075 # unless the user specified it 4076 PY8_Card.systemSet('Beams:setProductionScalesFromLHEF',True) 4077 4078 # Automatically set qWeed to xqcut if not defined by the user. 4079 if PY8_Card['SysCalc:qWeed']==-1.0: 4080 PY8_Card.MadGraphSet('SysCalc:qWeed',self.run_card['xqcut'], force=True) 4081 4082 if PY8_Card['SysCalc:qCutList']=='auto': 4083 if self.run_card['use_syst']: 4084 if self.run_card['sys_matchscale']=='auto': 4085 qcut = PY8_Card['JetMatching:qCut'] 4086 value = [factor*qcut for factor in [0.5,0.75,1.0,1.5,2.0] if\ 4087 factor*qcut> 1.5*self.run_card['xqcut'] ] 4088 PY8_Card.MadGraphSet('SysCalc:qCutList', value, force=True) 4089 else: 4090 qCutList = [float(qc) for qc in self.run_card['sys_matchscale'].split()] 4091 if PY8_Card['JetMatching:qCut'] not in qCutList: 4092 qCutList.append(PY8_Card['JetMatching:qCut']) 4093 PY8_Card.MadGraphSet('SysCalc:qCutList', qCutList, force=True) 4094 4095 4096 if PY8_Card['SysCalc:qCutList']!='auto': 4097 for scale in PY8_Card['SysCalc:qCutList']: 4098 if scale<(1.5*self.run_card['xqcut']): 4099 logger.error( 4100 'One of the MLM merging qCut parameter you chose (%f) in the variation list'%scale+\ 4101 " (either via 'SysCalc:qCutList' in the PY8 shower card or "+\ 4102 "'sys_matchscale' in the run_card) is less than 1.5*xqcut, where xqcut is"+ 4103 ' the run_card parameter (=%f)\n'%self.run_card['xqcut']+ 4104 'It would be better/safer to use a larger qCut or a smaller xqcut.') 4105 4106 # Specific MLM settings 4107 # PY8 should not implement the MLM veto since the driver should do it 4108 # if merging scale variation is turned on 4109 if self.run_card['use_syst']: 4110 # We do no force it here, but it is clear that the user should know what 4111 # he's doing if he were to force it to True. 4112 PY8_Card.MadGraphSet('JetMatching:doVeto',False) 4113 PY8_Card.MadGraphSet('JetMatching:merge',True) 4114 PY8_Card.MadGraphSet('JetMatching:scheme',1) 4115 # Use the parameter maxjetflavor for JetMatching:nQmatch which specifies 4116 # up to which parton must be matched.Merging:nQuarksMerge 4117 PY8_Card.MadGraphSet('JetMatching:nQmatch',self.run_card['maxjetflavor']) 4118 # For MLM, a cone radius of 1.0 is to be prefered. 4119 PY8_Card.MadGraphSet('JetMatching:coneRadius',1.0) 4120 # And the value of etaj_max is already infinity by default. 4121 # PY8_Card.MadGraphSet('JetMatching:etaJetMax',1000.0) 4122 if not hasattr(self,'proc_characteristic'): 4123 self.proc_characteristic = self.get_characteristics() 4124 nJetMax = self.proc_characteristic['max_n_matched_jets'] 4125 if PY8_Card['JetMatching:nJetMax'.lower()] == -1: 4126 logger.info("No user-defined value for Pythia8 parameter "+ 4127 "'JetMatching:nJetMax'. Setting it automatically to %d."%nJetMax) 4128 PY8_Card.MadGraphSet('JetMatching:nJetMax',nJetMax, force=True) 4129 # We use the positivity of 'ktdurham' cut as a CKKWl marker. 4130 elif run_type=='CKKW': 4131 4132 # Make sure the user correctly filled in the lowest order process to be considered 4133 if PY8_Card['Merging:Process']=='<set_by_user>': 4134 raise self.InvalidCmd('When running CKKWl merging, the user must'+ 4135 " specifiy the option 'Merging:Process' in pythia8_card.dat.\n"+ 4136 "Read section 'Defining the hard process' of "+\ 4137 "http://home.thep.lu.se/~torbjorn/pythia81html/CKKWLMerging.html for more information.") 4138 4139 # When running CKKWL make sure that we do not write out the parameter 4140 # JetMatching:xxx as this can interfere with the MLM merging in older 4141 # versions of the driver. 4142 PY8_Card.vetoParamWriteOut('JetMatching:qCut') 4143 PY8_Card.vetoParamWriteOut('JetMatching:doShowerKt') 4144 PY8_Card.vetoParamWriteOut('JetMatching:nJetMax') 4145 4146 CKKW_cut = None 4147 # Specific CKKW settings 4148 if self.run_card['ptlund']<=0.0 and self.run_card['ktdurham']>0.0: 4149 PY8_Card.subruns[0].MadGraphSet('Merging:doKTMerging',True) 4150 PY8_Card.subruns[0].MadGraphSet('Merging:Dparameter', 4151 self.run_card['dparameter']) 4152 CKKW_cut = 'ktdurham' 4153 elif self.run_card['ptlund']>0.0 and self.run_card['ktdurham']<=0.0: 4154 PY8_Card.subruns[0].MadGraphSet('Merging:doPTLundMerging',True) 4155 CKKW_cut = 'ptlund' 4156 else: 4157 raise InvalidCmd("*Either* the 'ptlund' or 'ktdurham' cut in "+\ 4158 " the run_card must be turned on to activate CKKW(L) merging"+ 4159 " with Pythia8, but *both* cuts cannot be turned on at the same time."+ 4160 "\n ptlund=%f, ktdurham=%f."%(self.run_card['ptlund'],self.run_card['ktdurham'])) 4161 4162 4163 # Automatically set qWeed to the CKKWL cut if not defined by the user. 4164 if PY8_Card['SysCalc:qWeed']==-1.0: 4165 PY8_Card.MadGraphSet('SysCalc:qWeed',self.run_card[CKKW_cut], force=True) 4166 4167 # MadGraphSet sets the corresponding value (in system mode) 4168 # only if it is not already user_set. 4169 if PY8_Card['Merging:TMS']==-1.0: 4170 if self.run_card[CKKW_cut]>0.0: 4171 PY8_Card.MadGraphSet('Merging:TMS',self.run_card[CKKW_cut], force=True) 4172 else: 4173 raise self.InvalidCmd('When running CKKWl merging, the user'+\ 4174 " select a '%s' cut larger than 0.0 in the run_card."%CKKW_cut) 4175 if PY8_Card['Merging:TMS']<self.run_card[CKKW_cut]: 4176 logger.error( 4177 'The CKKWl merging scale you chose (%f) is less than '%PY8_Card['Merging:TMS']+ 4178 'the %s cut specified in the run_card parameter (=%f).\n'%(CKKW_cut,self.run_card[CKKW_cut])+ 4179 'It is incorrect to use a smaller CKKWl scale than the generation-level %s cut!'%CKKW_cut) 4180 4181 PY8_Card.MadGraphSet('TimeShower:pTmaxMatch',1) 4182 PY8_Card.MadGraphSet('SpaceShower:pTmaxMatch',1) 4183 PY8_Card.MadGraphSet('SpaceShower:rapidityOrder',False) 4184 # PY8 should not implement the CKKW veto since the driver should do it. 4185 if self.run_card['use_syst']: 4186 # We do no force it here, but it is clear that the user should know what 4187 # he's doing if he were to force it to True. 4188 PY8_Card.MadGraphSet('Merging:applyVeto',False) 4189 PY8_Card.MadGraphSet('Merging:includeWeightInXsection',False) 4190 # Use the parameter maxjetflavor for Merging:nQuarksMerge which specifies 4191 # up to which parton must be matched. 4192 PY8_Card.MadGraphSet('Merging:nQuarksMerge',self.run_card['maxjetflavor']) 4193 if not hasattr(self,'proc_characteristic'): 4194 self.proc_characteristic = self.get_characteristics() 4195 nJetMax = self.proc_characteristic['max_n_matched_jets'] 4196 if PY8_Card['Merging:nJetMax'.lower()] == -1: 4197 logger.info("No user-defined value for Pythia8 parameter "+ 4198 "'Merging:nJetMax'. Setting it automatically to %d."%nJetMax) 4199 PY8_Card.MadGraphSet('Merging:nJetMax',nJetMax, force=True) 4200 if PY8_Card['SysCalc:tmsList']=='auto': 4201 if self.run_card['use_syst']: 4202 if self.run_card['sys_matchscale']=='auto': 4203 tms = PY8_Card["Merging:TMS"] 4204 value = [factor*tms for factor in [0.5,0.75,1.0,1.5,2.0] 4205 if factor*tms > self.run_card[CKKW_cut]] 4206 PY8_Card.MadGraphSet('SysCalc:tmsList', value, force=True) 4207 else: 4208 tmsList = [float(tms) for tms in self.run_card['sys_matchscale'].split()] 4209 if PY8_Card['Merging:TMS'] not in tmsList: 4210 tmsList.append(PY8_Card['Merging:TMS']) 4211 PY8_Card.MadGraphSet('SysCalc:tmsList', tmsList, force=True) 4212 #else: 4213 # PY8_Card.MadGraphSet('SysCalc:tmsList', [], force=True) 4214 if PY8_Card['SysCalc:tmsList']!='auto': 4215 for scale in PY8_Card['SysCalc:tmsList']: 4216 if float(scale)<float(self.run_card[CKKW_cut]): 4217 logger.error( 4218 'One of the CKKWl merging scale you chose (%f) in the variation list'%scale+\ 4219 " (either via 'SysCalc:tmsList' in the PY8 shower card or "+\ 4220 "'sys_matchscale' in the run_card) is less than %f, "%self.run_card[CKKW_cut]+ 4221 'the %s cut specified in the run_card parameter.\n'%CKKW_cut+ 4222 'It is incorrect to use a smaller CKKWl scale than the generation-level %s cut!'%CKKW_cut) 4223 else: 4224 # When not performing any merging, make sure that we do not write out the parameter 4225 # JetMatching:xxx or Merging:xxx as this can trigger undesired vetos in an unmerged 4226 # simulation. 4227 PY8_Card.vetoParamWriteOut('Merging:TMS') 4228 PY8_Card.vetoParamWriteOut('Merging:Process') 4229 PY8_Card.vetoParamWriteOut('Merging:nJetMax') 4230 PY8_Card.vetoParamWriteOut('JetMatching:qCut') 4231 PY8_Card.vetoParamWriteOut('JetMatching:doShowerKt') 4232 PY8_Card.vetoParamWriteOut('JetMatching:nJetMax') 4233 4234 return HepMC_event_output
4235
4236 - def do_pythia8(self, line):
4237 """launch pythia8""" 4238 4239 4240 try: 4241 import madgraph 4242 except ImportError: 4243 import internal.histograms as histograms 4244 else: 4245 import madgraph.various.histograms as histograms 4246 4247 # Check argument's validity 4248 args = self.split_arg(line) 4249 if '--no_default' in args: 4250 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia8_card.dat')): 4251 return 4252 no_default = True 4253 args.remove('--no_default') 4254 else: 4255 no_default = False 4256 4257 if not self.run_name: 4258 self.check_pythia8(args) 4259 self.configure_directory(html_opening =False) 4260 else: 4261 # initialize / remove lhapdf mode 4262 self.configure_directory(html_opening =False) 4263 self.check_pythia8(args) 4264 4265 # Update the banner with the pythia card 4266 if not self.banner or len(self.banner) <=1: 4267 # Here the level keyword 'pythia' must not be changed to 'pythia8'. 4268 self.banner = banner_mod.recover_banner(self.results, 'pythia') 4269 4270 # the args are modify and the last arg is always the mode 4271 if not no_default: 4272 self.ask_pythia_run_configuration(args[-1], pythia_version=8, banner=self.banner) 4273 4274 if self.options['automatic_html_opening']: 4275 misc.open_file(os.path.join(self.me_dir, 'crossx.html')) 4276 self.options['automatic_html_opening'] = False 4277 4278 if self.run_card['event_norm'] not in ['unit','average']: 4279 logger.critical("Pythia8 does not support normalization to the sum. Not running Pythia8") 4280 return 4281 #\n"+\ 4282 #"The normalisation of the hepmc output file will be wrong (i.e. non-standard).\n"+\ 4283 #"Please use 'event_norm = average' in the run_card to avoid this problem.") 4284 4285 4286 4287 if not self.options['mg5amc_py8_interface_path'] or not \ 4288 os.path.exists(pjoin(self.options['mg5amc_py8_interface_path'], 4289 'MG5aMC_PY8_interface')): 4290 raise self.InvalidCmd( 4291 """The MG5aMC_PY8_interface tool cannot be found, so that MadEvent cannot steer Pythia8 shower. 4292 Please install this tool with the following MG5_aMC command: 4293 MG5_aMC> install mg5amc_py8_interface_path""") 4294 else: 4295 pythia_main = pjoin(self.options['mg5amc_py8_interface_path'], 4296 'MG5aMC_PY8_interface') 4297 warnings = MadEventCmd.mg5amc_py8_interface_consistency_warning(self.options) 4298 if warnings: 4299 logger.warning(warnings) 4300 4301 self.results.add_detail('run_mode', 'madevent') 4302 4303 # Again here 'pythia' is just a keyword for the simulation level. 4304 self.update_status('\033[92mRunning Pythia8 [arXiv:1410.3012]\033[0m', 'pythia8') 4305 4306 tag = self.run_tag 4307 # Now write Pythia8 card 4308 # Start by reading, starting from the default one so that the 'user_set' 4309 # tag are correctly set. 4310 PY8_Card = banner_mod.PY8Card(pjoin(self.me_dir, 'Cards', 4311 'pythia8_card_default.dat')) 4312 PY8_Card.read(pjoin(self.me_dir, 'Cards', 'pythia8_card.dat'), 4313 setter='user') 4314 4315 run_type = 'default' 4316 merged_run_types = ['MLM','CKKW'] 4317 if int(self.run_card['ickkw'])==1: 4318 run_type = 'MLM' 4319 elif int(self.run_card['ickkw'])==2 or \ 4320 self.run_card['ktdurham']>0.0 or self.run_card['ptlund']>0.0: 4321 run_type = 'CKKW' 4322 4323 # Edit the card and run environment according to the run specification 4324 HepMC_event_output = self.setup_Pythia8RunAndCard(PY8_Card, run_type) 4325 4326 # Now write the card. 4327 pythia_cmd_card = pjoin(self.me_dir, 'Events', self.run_name , 4328 '%s_pythia8.cmd' % tag) 4329 cmd_card = StringIO.StringIO() 4330 PY8_Card.write(cmd_card,pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 4331 direct_pythia_input=True) 4332 4333 # Now setup the preamble to make sure that everything will use the locally 4334 # installed tools (if present) even if the user did not add it to its 4335 # environment variables. 4336 if 'heptools_install_dir' in self.options: 4337 preamble = misc.get_HEPTools_location_setter( 4338 self.options['heptools_install_dir'],'lib') 4339 else: 4340 if MADEVENT: 4341 preamble = misc.get_HEPTools_location_setter( 4342 pjoin(self.options['mg5amc_py8_interface_path'],os.pardir),'lib') 4343 else: 4344 preamble = misc.get_HEPTools_location_setter( 4345 pjoin(MG5DIR,'HEPTools'),'lib') 4346 4347 open(pythia_cmd_card,'w').write("""! 4348 ! It is possible to run this card manually with: 4349 ! %s %s 4350 ! 4351 """%(preamble+pythia_main,os.path.basename(pythia_cmd_card))+cmd_card.getvalue()) 4352 4353 # launch pythia8 4354 pythia_log = pjoin(self.me_dir , 'Events', self.run_name , 4355 '%s_pythia8.log' % tag) 4356 4357 # Write a bash wrapper to run the shower with custom environment variables 4358 wrapper_path = pjoin(self.me_dir,'Events',self.run_name,'run_shower.sh') 4359 wrapper = open(wrapper_path,'w') 4360 shell = 'bash' if misc.get_shell_type() in ['bash',None] else 'tcsh' 4361 shell_exe = None 4362 if os.path.exists('/usr/bin/env'): 4363 shell_exe = '/usr/bin/env %s'%shell 4364 else: 4365 shell_exe = misc.which(shell) 4366 if not shell_exe: 4367 raise self.InvalidCmd('No s hell could be found in your environment.\n'+ 4368 "Make sure that either '%s' is in your path or that the"%shell+\ 4369 " command '/usr/bin/env %s' exists and returns a valid path."%shell) 4370 4371 exe_cmd = "#!%s\n%s"%(shell_exe,' '.join( 4372 [preamble+pythia_main, 4373 os.path.basename(pythia_cmd_card)])) 4374 4375 wrapper.write(exe_cmd) 4376 wrapper.close() 4377 4378 # Set it as executable 4379 st = os.stat(wrapper_path) 4380 os.chmod(wrapper_path, st.st_mode | stat.S_IEXEC) 4381 4382 # If the target HEPMC output file is a fifo, don't hang MG5_aMC and let 4383 # it proceed. 4384 is_HepMC_output_fifo = False if not HepMC_event_output else \ 4385 ( os.path.exists(HepMC_event_output) and \ 4386 stat.S_ISFIFO(os.stat(HepMC_event_output).st_mode)) 4387 startPY8timer = time.time() 4388 4389 # Information that will be extracted from this PY8 run 4390 PY8_extracted_information={ 'sigma_m':None, 'Nacc':None, 'Ntry':None, 4391 'cross_sections':{} } 4392 4393 if is_HepMC_output_fifo: 4394 logger.info( 4395 """Pythia8 is set to output HEPMC events to to a fifo file. 4396 You can follow PY8 run with the following command (in a separate terminal): 4397 tail -f %s"""%pythia_log ) 4398 py8_log = open( pythia_log,'w') 4399 py8_bkgrd_proc = misc.Popen([wrapper_path], 4400 stdout=py8_log,stderr=py8_log, 4401 cwd=pjoin(self.me_dir,'Events',self.run_name)) 4402 # Now directly return to madevent interactive interface if we are piping PY8 4403 if not no_default: 4404 logger.info('You can now run a tool that reads the following fifo file:'+\ 4405 '\n %s\nwhere PY8 outputs HEPMC events (e.g. MadAnalysis5).' 4406 %HepMC_event_output,'$MG:color:GREEN') 4407 return 4408 else: 4409 if self.options ['run_mode']!=0: 4410 # Start a parallelization instance (stored in self.cluster) 4411 self.configure_run_mode(self.options['run_mode']) 4412 if self.options['run_mode']==1: 4413 n_cores = max(int(self.options['cluster_size']),1) 4414 elif self.options['run_mode']==2: 4415 n_cores = max(int(self.cluster.nb_core),1) 4416 4417 lhe_file_name = os.path.basename(PY8_Card.subruns[0]['Beams:LHEF']) 4418 lhe_file = lhe_parser.EventFile(pjoin(self.me_dir,'Events', 4419 self.run_name,PY8_Card.subruns[0]['Beams:LHEF'])) 4420 n_available_events = len(lhe_file) 4421 if PY8_Card['Main:numberOfEvents']==-1: 4422 n_events = n_available_events 4423 else: 4424 n_events = PY8_Card['Main:numberOfEvents'] 4425 if n_events > n_available_events: 4426 raise self.InvalidCmd('You specified more events (%d) in the PY8 parameter'%n_events+\ 4427 "'Main:numberOfEvents' than the total number of events available (%d)"%n_available_events+\ 4428 ' in the event file:\n %s'%pjoin(self.me_dir,'Events',self.run_name,PY8_Card.subruns[0]['Beams:LHEF'])) 4429 4430 # Implement a security to insure a minimum numbe of events per job 4431 if self.options['run_mode']==2: 4432 min_n_events_per_job = 100 4433 elif self.options['run_mode']==1: 4434 min_n_events_per_job = 1000 4435 min_n_core = n_events//min_n_events_per_job 4436 n_cores = max(min(min_n_core,n_cores),1) 4437 4438 if self.options['run_mode']==0 or (self.options['run_mode']==2 and self.options['nb_core']==1): 4439 # No need for parallelization anymore 4440 self.cluster = None 4441 logger.info('Follow Pythia8 shower by running the '+ 4442 'following command (in a separate terminal):\n tail -f %s'%pythia_log) 4443 4444 if self.options['run_mode']==2 and self.options['nb_core']>1: 4445 ret_code = self.cluster.launch_and_wait(wrapper_path, 4446 argument= [], stdout= pythia_log, stderr=subprocess.STDOUT, 4447 cwd=pjoin(self.me_dir,'Events',self.run_name)) 4448 else: 4449 stdout = open(pythia_log,'w') 4450 ret_code = misc.call(wrapper_path, stdout=stdout, stderr=subprocess.STDOUT, 4451 cwd=pjoin(self.me_dir,'Events',self.run_name)) 4452 stdout.close() 4453 if ret_code != 0: 4454 raise self.InvalidCmd('Pythia8 shower interrupted with return'+\ 4455 ' code %d.\n'%ret_code+\ 4456 'You can find more information in this log file:\n%s'%pythia_log) 4457 else: 4458 if self.run_card['event_norm']=='sum': 4459 logger.error("") 4460 logger.error("Either run in single core or change event_norm to 'average'.") 4461 raise InvalidCmd("Pythia8 parallelization with event_norm set to 'sum' is not supported." 4462 "Either run in single core or change event_norm to 'average'.") 4463 4464 # Create the parallelization folder 4465 parallelization_dir = pjoin(self.me_dir,'Events',self.run_name,'PY8_parallelization') 4466 if os.path.isdir(parallelization_dir): 4467 shutil.rmtree(parallelization_dir) 4468 os.mkdir(parallelization_dir) 4469 # Copy what should be the now standalone executable for PY8 4470 shutil.copy(pythia_main,parallelization_dir) 4471 # Add a safe card in parallelization 4472 ParallelPY8Card = copy.copy(PY8_Card) 4473 assert ParallelPY8Card['JetMatching:nJetMax'] == PY8_Card['JetMatching:nJetMax'] 4474 4475 # Normalize the name of the HEPMCouput and lhe input 4476 if HepMC_event_output: 4477 ParallelPY8Card['HEPMCoutput:file']='events.hepmc' 4478 else: 4479 ParallelPY8Card['HEPMCoutput:file']='/dev/null' 4480 4481 ParallelPY8Card.subruns[0].systemSet('Beams:LHEF','events.lhe.gz') 4482 ParallelPY8Card.write(pjoin(parallelization_dir,'PY8Card.dat'), 4483 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 4484 direct_pythia_input=True) 4485 # Write the wrapper 4486 wrapper_path = pjoin(parallelization_dir,'run_PY8.sh') 4487 wrapper = open(wrapper_path,'w') 4488 if self.options['cluster_temp_path'] is None: 4489 exe_cmd = \ 4490 """#!%s 4491 ./%s PY8Card.dat >& PY8_log.txt 4492 """ 4493 else: 4494 exe_cmd = \ 4495 """#!%s 4496 ln -s ./events_$1.lhe.gz ./events.lhe.gz 4497 ./%s PY8Card_$1.dat >& PY8_log.txt 4498 mkdir split_$1 4499 if [ -f ./events.hepmc ]; 4500 then 4501 mv ./events.hepmc ./split_$1/ 4502 fi 4503 if [ -f ./pts.dat ]; 4504 then 4505 mv ./pts.dat ./split_$1/ 4506 fi 4507 if [ -f ./djrs.dat ]; 4508 then 4509 mv ./djrs.dat ./split_$1/ 4510 fi 4511 if [ -f ./PY8_log.txt ]; 4512 then 4513 mv ./PY8_log.txt ./split_$1/ 4514 fi 4515 tar -czf split_$1.tar.gz split_$1 4516 """ 4517 exe_cmd = exe_cmd%(shell_exe,os.path.basename(pythia_main)) 4518 wrapper.write(exe_cmd) 4519 wrapper.close() 4520 # Set it as executable 4521 st = os.stat(wrapper_path) 4522 os.chmod(wrapper_path, st.st_mode | stat.S_IEXEC) 4523 4524 # Split the .lhe event file, create event partition 4525 partition=[n_available_events//n_cores]*n_cores 4526 for i in range(n_available_events%n_cores): 4527 partition[i] += 1 4528 4529 # Splitting according to the total number of events requested by the user 4530 # Will be used to determine the number of events to indicate in the PY8 split cards. 4531 partition_for_PY8=[n_events//n_cores]*n_cores 4532 for i in range(n_events%n_cores): 4533 partition_for_PY8[i] += 1 4534 4535 logger.info('Splitting .lhe event file for PY8 parallelization...') 4536 n_splits = lhe_file.split(partition=partition, cwd=parallelization_dir, zip=True) 4537 4538 if n_splits!=len(partition): 4539 raise MadGraph5Error('Error during lhe file splitting. Expected %d files but obtained %d.' 4540 %(len(partition),n_splits)) 4541 # Distribute the split events 4542 split_files = [] 4543 split_dirs = [] 4544 for split_id in range(n_splits): 4545 split_files.append('events_%s.lhe.gz'%split_id) 4546 split_dirs.append(pjoin(parallelization_dir,'split_%d'%split_id)) 4547 # Add the necessary run content 4548 shutil.move(pjoin(parallelization_dir,lhe_file.name+'_%d.lhe.gz'%split_id), 4549 pjoin(parallelization_dir,split_files[-1])) 4550 4551 logger.info('Submitting Pythia8 jobs...') 4552 for i, split_file in enumerate(split_files): 4553 # We must write a PY8Card tailored for each split so as to correct the normalization 4554 # HEPMCoutput:scaling of each weight since the lhe showered will not longer contain the 4555 # same original number of events 4556 split_PY8_Card = banner_mod.PY8Card(pjoin(parallelization_dir,'PY8Card.dat')) 4557 # Make sure to sure the number of split_events determined during the splitting. 4558 split_PY8_Card.systemSet('Main:numberOfEvents',partition_for_PY8[i]) 4559 split_PY8_Card.systemSet('HEPMCoutput:scaling',split_PY8_Card['HEPMCoutput:scaling']* 4560 (float(partition_for_PY8[i])/float(n_events))) 4561 # Add_missing set to False so as to be sure not to add any additional parameter w.r.t 4562 # the ones in the original PY8 param_card copied. 4563 split_PY8_Card.write(pjoin(parallelization_dir,'PY8Card_%d.dat'%i), 4564 pjoin(parallelization_dir,'PY8Card.dat'), add_missing=False) 4565 in_files = [pjoin(parallelization_dir,os.path.basename(pythia_main)), 4566 pjoin(parallelization_dir,'PY8Card_%d.dat'%i), 4567 pjoin(parallelization_dir,split_file)] 4568 if self.options['cluster_temp_path'] is None: 4569 out_files = [] 4570 os.mkdir(pjoin(parallelization_dir,'split_%d'%i)) 4571 selected_cwd = pjoin(parallelization_dir,'split_%d'%i) 4572 for in_file in in_files+[pjoin(parallelization_dir,'run_PY8.sh')]: 4573 # Make sure to rename the split_file link from events_<x>.lhe.gz to events.lhe.gz 4574 # and similarly for PY8Card 4575 if os.path.basename(in_file)==split_file: 4576 ln(in_file,selected_cwd,name='events.lhe.gz') 4577 elif os.path.basename(in_file).startswith('PY8Card'): 4578 ln(in_file,selected_cwd,name='PY8Card.dat') 4579 else: 4580 ln(in_file,selected_cwd) 4581 in_files = [] 4582 wrapper_path = os.path.basename(wrapper_path) 4583 else: 4584 out_files = ['split_%d.tar.gz'%i] 4585 selected_cwd = parallelization_dir 4586 4587 self.cluster.submit2(wrapper_path, 4588 argument=[str(i)], cwd=selected_cwd, 4589 input_files=in_files, 4590 output_files=out_files, 4591 required_output=out_files) 4592 4593 def wait_monitoring(Idle, Running, Done): 4594 if Idle+Running+Done == 0: 4595 return 4596 logger.info('Pythia8 shower jobs: %d Idle, %d Running, %d Done [%s]'\ 4597 %(Idle, Running, Done, misc.format_time(time.time() - startPY8timer)))
4598 self.cluster.wait(parallelization_dir,wait_monitoring) 4599 4600 logger.info('Merging results from the split PY8 runs...') 4601 if self.options['cluster_temp_path']: 4602 # Decompressing the output 4603 for i, split_file in enumerate(split_files): 4604 misc.call(['tar','-xzf','split_%d.tar.gz'%i],cwd=parallelization_dir) 4605 os.remove(pjoin(parallelization_dir,'split_%d.tar.gz'%i)) 4606 4607 # Now merge logs 4608 pythia_log_file = open(pythia_log,'w') 4609 n_added = 0 4610 for split_dir in split_dirs: 4611 log_file = pjoin(split_dir,'PY8_log.txt') 4612 pythia_log_file.write('='*35+'\n') 4613 pythia_log_file.write(' -> Pythia8 log file for run %d <-'%i+'\n') 4614 pythia_log_file.write('='*35+'\n') 4615 pythia_log_file.write(open(log_file,'r').read()+'\n') 4616 if run_type in merged_run_types: 4617 sigma_m, Nacc, Ntry = self.parse_PY8_log_file(log_file) 4618 if any(elem is None for elem in [sigma_m, Nacc, Ntry]): 4619 continue 4620 n_added += 1 4621 if PY8_extracted_information['sigma_m'] is None: 4622 PY8_extracted_information['sigma_m'] = sigma_m 4623 else: 4624 PY8_extracted_information['sigma_m'] += sigma_m 4625 if PY8_extracted_information['Nacc'] is None: 4626 PY8_extracted_information['Nacc'] = Nacc 4627 else: 4628 PY8_extracted_information['Nacc'] += Nacc 4629 if PY8_extracted_information['Ntry'] is None: 4630 PY8_extracted_information['Ntry'] = Ntry 4631 else: 4632 PY8_extracted_information['Ntry'] += Ntry 4633 4634 # Normalize the values added 4635 if n_added>0: 4636 PY8_extracted_information['sigma_m'] /= float(n_added) 4637 pythia_log_file.close() 4638 4639 # djr plots 4640 djr_HwU = None 4641 n_added = 0 4642 for split_dir in split_dirs: 4643 djr_file = pjoin(split_dir,'djrs.dat') 4644 if not os.path.isfile(djr_file): 4645 continue 4646 xsecs = self.extract_cross_sections_from_DJR(djr_file) 4647 if len(xsecs)>0: 4648 n_added += 1 4649 if len(PY8_extracted_information['cross_sections'])==0: 4650 PY8_extracted_information['cross_sections'] = xsecs 4651 # Square the error term 4652 for key in PY8_extracted_information['cross_sections']: 4653 PY8_extracted_information['cross_sections'][key][1] = \ 4654 PY8_extracted_information['cross_sections'][key][1]**2 4655 else: 4656 for key, value in xsecs.items(): 4657 PY8_extracted_information['cross_sections'][key][0] += value[0] 4658 # Add error in quadrature 4659 PY8_extracted_information['cross_sections'][key][1] += value[1]**2 4660 new_djr_HwU = histograms.HwUList(djr_file,run_id=0) 4661 if djr_HwU is None: 4662 djr_HwU = new_djr_HwU 4663 else: 4664 for i, hist in enumerate(djr_HwU): 4665 djr_HwU[i] = hist + new_djr_HwU[i] 4666 4667 4668 if not djr_HwU is None: 4669 djr_HwU.output(pjoin(self.me_dir,'Events',self.run_name,'djrs'),format='HwU') 4670 shutil.move(pjoin(self.me_dir,'Events',self.run_name,'djrs.HwU'), 4671 pjoin(self.me_dir,'Events',self.run_name,'%s_djrs.dat'%tag)) 4672 4673 if n_added>0: 4674 for key in PY8_extracted_information['cross_sections']: 4675 # The cross-sections in the DJR are normalized for the original number of events, so we should not 4676 # divide by n_added anymore for the cross-section value 4677 # PY8_extracted_information['cross_sections'][key][0] /= float(n_added) 4678 PY8_extracted_information['cross_sections'][key][1] = \ 4679 math.sqrt(PY8_extracted_information['cross_sections'][key][1]) / float(n_added) 4680 4681 # pts plots 4682 pts_HwU = None 4683 for split_dir in split_dirs: 4684 pts_file = pjoin(split_dir,'pts.dat') 4685 if not os.path.isfile(pts_file): 4686 continue 4687 new_pts_HwU = histograms.HwUList(pts_file,run_id=0) 4688 if pts_HwU is None: 4689 pts_HwU = new_pts_HwU 4690 else: 4691 for i, hist in enumerate(pts_HwU): 4692 pts_HwU[i] = hist + new_pts_HwU[i] 4693 if not pts_HwU is None: 4694 pts_HwU.output(pjoin(self.me_dir,'Events',self.run_name,'pts'),format='HwU') 4695 shutil.move(pjoin(self.me_dir,'Events',self.run_name,'pts.HwU'), 4696 pjoin(self.me_dir,'Events',self.run_name,'%s_pts.dat'%tag)) 4697 4698 # HepMC events now. 4699 all_hepmc_files = [] 4700 for split_dir in split_dirs: 4701 hepmc_file = pjoin(split_dir,'events.hepmc') 4702 if not os.path.isfile(hepmc_file): 4703 continue 4704 all_hepmc_files.append(hepmc_file) 4705 4706 if len(all_hepmc_files)>0: 4707 hepmc_output = pjoin(self.me_dir,'Events',self.run_name,HepMC_event_output) 4708 with misc.TMP_directory() as tmp_dir: 4709 # Use system calls to quickly put these together 4710 header = open(pjoin(tmp_dir,'header.hepmc'),'w') 4711 n_head = 0 4712 for line in open(all_hepmc_files[0],'r'): 4713 if not line.startswith('E'): 4714 n_head += 1 4715 header.write(line) 4716 else: 4717 break 4718 header.close() 4719 tail = open(pjoin(tmp_dir,'tail.hepmc'),'w') 4720 n_tail = 0 4721 4722 for line in misc.reverse_readline(all_hepmc_files[-1]): 4723 if line.startswith('HepMC::'): 4724 n_tail += 1 4725 tail.write(line) 4726 else: 4727 break 4728 tail.close() 4729 if n_tail>1: 4730 raise MadGraph5Error('HEPMC files should only have one trailing command.') 4731 ###################################################################### 4732 # This is the most efficient way of putting together HEPMC's, *BUT* # 4733 # WARNING: NEED TO RENDER THE CODE BELOW SAFE TOWARDS INJECTION # 4734 ###################################################################### 4735 for hepmc_file in all_hepmc_files: 4736 # Remove in an efficient way the starting and trailing HEPMC tags 4737 # check for support of negative argument in head 4738 devnull = open(os.path.devnull, 'w') 4739 pid = misc.call(['head','-n', '-1', __file__], stdout=devnull, stderr=devnull) 4740 devnull.close() 4741 if pid == 0: 4742 misc.call('head -n -1 %s | tail -n +%d > %s/tmpfile' % 4743 (hepmc_file, n_head+1, os.path.dirname(hepmc_file)), shell=True) 4744 misc.call(['mv', 'tmpfile', os.path.basename(hepmc_file)], cwd=os.path.dirname(hepmc_file)) 4745 elif sys.platform == 'darwin': 4746 # sed on MAC has slightly different synthax than on 4747 os.system(' '.join(['sed','-i',"''","'%s;$d'"% 4748 (';'.join('%id'%(i+1) for i in range(n_head))),hepmc_file])) 4749 else: 4750 # other UNIX systems 4751 os.system(' '.join(['sed','-i']+["-e '%id'"%(i+1) for i in range(n_head)]+ 4752 ["-e '$d'",hepmc_file])) 4753 4754 os.system(' '.join(['cat',pjoin(tmp_dir,'header.hepmc')]+all_hepmc_files+ 4755 [pjoin(tmp_dir,'tail.hepmc'),'>',hepmc_output])) 4756 4757 # We are done with the parallelization directory. Clean it. 4758 if os.path.isdir(parallelization_dir): 4759 shutil.rmtree(parallelization_dir) 4760 4761 # Properly rename the djr and pts output if present. 4762 djr_output = pjoin(self.me_dir,'Events', self.run_name, 'djrs.dat') 4763 if os.path.isfile(djr_output): 4764 shutil.move(djr_output, pjoin(self.me_dir,'Events', 4765 self.run_name, '%s_djrs.dat' % tag)) 4766 pt_output = pjoin(self.me_dir,'Events', self.run_name, 'pts.dat') 4767 if os.path.isfile(pt_output): 4768 shutil.move(pt_output, pjoin(self.me_dir,'Events', 4769 self.run_name, '%s_pts.dat' % tag)) 4770 4771 if not os.path.isfile(pythia_log) or \ 4772 'Inclusive cross section:' not in '\n'.join(open(pythia_log,'r').readlines()[-20:]): 4773 logger.warning('Fail to produce a pythia8 output. More info in \n %s'%pythia_log) 4774 return 4775 4776 # Plot for Pythia8 4777 successful = self.create_plot('Pythia8') 4778 if not successful: 4779 logger.warning('Failed to produce Pythia8 merging plots.') 4780 4781 self.to_store.append('pythia8') 4782 4783 # Study matched cross-sections 4784 if run_type in merged_run_types: 4785 # From the log file 4786 if all(PY8_extracted_information[_] is None for _ in ['sigma_m','Nacc','Ntry']): 4787 # When parallelization is enable we shouldn't have cannot look in the log in this way 4788 if self.options['run_mode']==0 or (self.options['run_mode']==2 and self.options['nb_core']==1): 4789 PY8_extracted_information['sigma_m'],PY8_extracted_information['Nacc'],\ 4790 PY8_extracted_information['Ntry'] = self.parse_PY8_log_file( 4791 pjoin(self.me_dir,'Events', self.run_name,'%s_pythia8.log' % tag)) 4792 else: 4793 logger.warning('Pythia8 cross-section could not be retreived.\n'+ 4794 'Try turning parallelization off by setting the option nb_core to 1. YYYYY') 4795 4796 if not any(PY8_extracted_information[_] is None for _ in ['sigma_m','Nacc','Ntry']): 4797 self.results.add_detail('cross_pythia', PY8_extracted_information['sigma_m']) 4798 self.results.add_detail('nb_event_pythia', PY8_extracted_information['Nacc']) 4799 # Shorthands 4800 Nacc = PY8_extracted_information['Nacc'] 4801 Ntry = PY8_extracted_information['Ntry'] 4802 sigma_m = PY8_extracted_information['sigma_m'] 4803 # Compute pythia error 4804 error = self.results[self.run_name].return_tag(self.run_tag)['error'] 4805 try: 4806 error_m = math.sqrt((error * Nacc/Ntry)**2 + sigma_m**2 *(1-Nacc/Ntry)/Nacc) 4807 except ZeroDivisionError: 4808 # Cannot compute error 4809 error_m = -1.0 4810 # works both for fixed number of generated events and fixed accepted events 4811 self.results.add_detail('error_pythia', error_m) 4812 4813 if self.run_card['use_syst']: 4814 self.results.add_detail('cross_pythia', -1) 4815 self.results.add_detail('error_pythia', 0) 4816 4817 # From the djr file generated 4818 djr_output = pjoin(self.me_dir,'Events',self.run_name,'%s_djrs.dat'%tag) 4819 if os.path.isfile(djr_output) and len(PY8_extracted_information['cross_sections'])==0: 4820 # When parallelization is enable we shouldn't have cannot look in the log in this way 4821 if self.options['run_mode']==0 or (self.options['run_mode']==2 and self.options['nb_core']==1): 4822 PY8_extracted_information['cross_sections'] = self.extract_cross_sections_from_DJR(djr_output) 4823 else: 4824 logger.warning('Pythia8 merged cross-sections could not be retreived.\n'+ 4825 'Try turning parallelization off by setting the option nb_core to 1.XXXXX') 4826 PY8_extracted_information['cross_sections'] = {} 4827 4828 cross_sections = PY8_extracted_information['cross_sections'] 4829 if cross_sections: 4830 # Filter the cross_sections specified an keep only the ones 4831 # with central parameters and a different merging scale 4832 a_float_re = '[\+|-]?\d+(\.\d*)?([EeDd][\+|-]?\d+)?' 4833 central_merging_re = re.compile( 4834 '^\s*Weight_MERGING\s*=\s*(?P<merging>%s)\s*$'%a_float_re, 4835 re.IGNORECASE) 4836 cross_sections = dict( 4837 (float(central_merging_re.match(xsec).group('merging')),value) 4838 for xsec, value in cross_sections.items() if not 4839 central_merging_re.match(xsec) is None) 4840 central_scale = PY8_Card['JetMatching:qCut'] if \ 4841 int(self.run_card['ickkw'])==1 else PY8_Card['Merging:TMS'] 4842 if central_scale in cross_sections: 4843 self.results.add_detail('cross_pythia8', cross_sections[central_scale][0]) 4844 self.results.add_detail('error_pythia8', cross_sections[central_scale][1]) 4845 4846 #logger.info('Pythia8 merged cross-sections are:') 4847 #for scale in sorted(cross_sections.keys()): 4848 # logger.info(' > Merging scale = %-6.4g : %-11.5g +/- %-7.2g [pb]'%\ 4849 # (scale,cross_sections[scale][0],cross_sections[scale][1])) 4850 4851 xsecs_file = open(pjoin(self.me_dir,'Events',self.run_name, 4852 '%s_merged_xsecs.txt'%tag),'w') 4853 if cross_sections: 4854 xsecs_file.write('%-20s%-20s%-20s\n'%('Merging scale', 4855 'Cross-section [pb]','MC uncertainty [pb]')) 4856 for scale in sorted(cross_sections.keys()): 4857 xsecs_file.write('%-20.4g%-20.6e%-20.2e\n'% 4858 (scale,cross_sections[scale][0],cross_sections[scale][1])) 4859 else: 4860 xsecs_file.write('Cross-sections could not be read from the'+\ 4861 "XML node 'xsection' of the .dat file produced by Pythia8.") 4862 xsecs_file.close() 4863 4864 #Update the banner 4865 # We add directly the pythia command card because it has the full 4866 # information 4867 self.banner.add(pythia_cmd_card) 4868 4869 if int(self.run_card['ickkw']): 4870 # Add the matched cross-section 4871 if 'MGGenerationInfo' in self.banner: 4872 self.banner['MGGenerationInfo'] += '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 4873 else: 4874 self.banner['MGGenerationInfo'] = '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 4875 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)) 4876 self.banner.write(banner_path) 4877 4878 self.update_status('Pythia8 shower finished after %s.'%misc.format_time(time.time() - startPY8timer), level='pythia8') 4879 if self.options['delphes_path']: 4880 self.exec_cmd('delphes --no_default', postcmd=False, printcmd=False) 4881 self.print_results_in_shell(self.results.current) 4882
4883 - def parse_PY8_log_file(self, log_file_path):
4884 """ Parse a log file to extract number of event and cross-section. """ 4885 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\-\+]+)") 4886 pythia_xsec_re = re.compile("Inclusive cross section\s*:\s*(?P<xsec>[\d\.e\-\+]+)\s*(?P<xsec_error>[\d\.e\-\+]+)") 4887 sigma_m, Nacc, Ntry = None, None, None 4888 for line in misc.BackRead(log_file_path): 4889 info = pythiare.search(line) 4890 if not info: 4891 # Also try to obtain the cross-section and error from the final xsec line of pythia8 log 4892 # which is more reliable, in general for example when there is merging and the last event 4893 # is skipped. 4894 final_PY8_xsec = pythia_xsec_re.search(line) 4895 if not final_PY8_xsec: 4896 continue 4897 else: 4898 sigma_m = float(final_PY8_xsec.group('xsec')) *1e9 4899 continue 4900 else: 4901 try: 4902 # Pythia cross section in mb, we want pb 4903 if sigma_m is None: 4904 sigma_m = float(info.group('xsec')) *1e9 4905 if Nacc is None: 4906 Nacc = int(info.group('generated')) 4907 if Ntry is None: 4908 Ntry = int(info.group('tried')) 4909 if Nacc==0: 4910 raise self.InvalidCmd('Pythia8 shower failed since it'+\ 4911 ' did not accept any event from the MG5aMC event file.') 4912 return sigma_m, Nacc, Ntry 4913 except ValueError: 4914 return None,None,None 4915 4916 raise self.InvalidCmd("Could not find cross-section and event number information "+\ 4917 "in Pythia8 log\n '%s'."%log_file_path)
4918
4919 - def extract_cross_sections_from_DJR(self,djr_output):
4920 """Extract cross-sections from a djr XML output.""" 4921 import xml.dom.minidom as minidom 4922 run_nodes = minidom.parse(djr_output).getElementsByTagName("run") 4923 all_nodes = dict((int(node.getAttribute('id')),node) for 4924 node in run_nodes) 4925 try: 4926 selected_run_node = all_nodes[0] 4927 except: 4928 return {} 4929 xsections = selected_run_node.getElementsByTagName("xsection") 4930 # In the DJR, the conversion to pb is already performed 4931 return dict((xsec.getAttribute('name'), 4932 [float(xsec.childNodes[0].data.split()[0]), 4933 float(xsec.childNodes[0].data.split()[1])]) 4934 for xsec in xsections)
4935
4936 - def do_pythia(self, line):
4937 """launch pythia""" 4938 4939 4940 # Check argument's validity 4941 args = self.split_arg(line) 4942 if '--no_default' in args: 4943 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia_card.dat')): 4944 return 4945 no_default = True 4946 args.remove('--no_default') 4947 else: 4948 no_default = False 4949 4950 if not self.run_name: 4951 self.check_pythia(args) 4952 self.configure_directory(html_opening =False) 4953 else: 4954 # initialize / remove lhapdf mode 4955 self.configure_directory(html_opening =False) 4956 self.check_pythia(args) 4957 4958 if self.run_card['event_norm'] != 'sum': 4959 logger.error('pythia-pgs require event_norm to be on sum. Do not run pythia6') 4960 return 4961 4962 # the args are modify and the last arg is always the mode 4963 if not no_default: 4964 self.ask_pythia_run_configuration(args[-1]) 4965 if self.options['automatic_html_opening']: 4966 misc.open_file(os.path.join(self.me_dir, 'crossx.html')) 4967 self.options['automatic_html_opening'] = False 4968 4969 # Update the banner with the pythia card 4970 if not self.banner or len(self.banner) <=1: 4971 self.banner = banner_mod.recover_banner(self.results, 'pythia') 4972 4973 pythia_src = pjoin(self.options['pythia-pgs_path'],'src') 4974 4975 self.results.add_detail('run_mode', 'madevent') 4976 4977 self.update_status('Running Pythia', 'pythia') 4978 try: 4979 os.remove(pjoin(self.me_dir,'Events','pythia.done')) 4980 except Exception: 4981 pass 4982 4983 ## LAUNCHING PYTHIA 4984 # check that LHAPATH is define. 4985 if not re.search(r'^\s*LHAPATH=%s/PDFsets' % pythia_src, 4986 open(pjoin(self.me_dir,'Cards','pythia_card.dat')).read(), 4987 re.M): 4988 f = open(pjoin(self.me_dir,'Cards','pythia_card.dat'),'a') 4989 f.write('\n LHAPATH=%s/PDFsets' % pythia_src) 4990 f.close() 4991 tag = self.run_tag 4992 pythia_log = pjoin(self.me_dir, 'Events', self.run_name , '%s_pythia.log' % tag) 4993 #self.cluster.launch_and_wait('../bin/internal/run_pythia', 4994 # argument= [pythia_src], stdout= pythia_log, 4995 # stderr=subprocess.STDOUT, 4996 # cwd=pjoin(self.me_dir,'Events')) 4997 output_files = ['pythia_events.hep'] 4998 if self.run_card['use_syst']: 4999 output_files.append('syst.dat') 5000 if self.run_card['ickkw'] == 1: 5001 output_files += ['beforeveto.tree', 'xsecs.tree', 'events.tree'] 5002 5003 os.environ['PDG_MASS_TBL'] = pjoin(pythia_src,'mass_width_2004.mc') 5004 self.cluster.launch_and_wait(pjoin(pythia_src, 'pythia'), 5005 input_files=[pjoin(self.me_dir, "Events", "unweighted_events.lhe"), 5006 pjoin(self.me_dir,'Cards','pythia_card.dat'), 5007 pjoin(pythia_src,'mass_width_2004.mc')], 5008 output_files=output_files, 5009 stdout= pythia_log, 5010 stderr=subprocess.STDOUT, 5011 cwd=pjoin(self.me_dir,'Events')) 5012 5013 5014 os.remove(pjoin(self.me_dir, "Events", "unweighted_events.lhe")) 5015 5016 if not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')): 5017 logger.warning('Fail to produce pythia output. More info in \n %s' % pythia_log) 5018 return 5019 5020 self.to_store.append('pythia') 5021 5022 # Find the matched cross-section 5023 if int(self.run_card['ickkw']): 5024 # read the line from the bottom of the file 5025 #pythia_log = misc.BackRead(pjoin(self.me_dir,'Events', self.run_name, 5026 # '%s_pythia.log' % tag)) 5027 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") 5028 for line in misc.reverse_readline(pjoin(self.me_dir,'Events', self.run_name, 5029 '%s_pythia.log' % tag)): 5030 info = pythiare.search(line) 5031 if not info: 5032 continue 5033 try: 5034 # Pythia cross section in mb, we want pb 5035 sigma_m = float(info.group('xsec').replace('D','E')) *1e9 5036 Nacc = int(info.group('generated')) 5037 Ntry = int(info.group('tried')) 5038 except ValueError: 5039 # xsec is not float - this should not happen 5040 self.results.add_detail('cross_pythia', 0) 5041 self.results.add_detail('nb_event_pythia', 0) 5042 self.results.add_detail('error_pythia', 0) 5043 else: 5044 self.results.add_detail('cross_pythia', sigma_m) 5045 self.results.add_detail('nb_event_pythia', Nacc) 5046 #compute pythia error 5047 error = self.results[self.run_name].return_tag(self.run_tag)['error'] 5048 if Nacc: 5049 error_m = math.sqrt((error * Nacc/Ntry)**2 + sigma_m**2 *(1-Nacc/Ntry)/Nacc) 5050 else: 5051 error_m = 10000 * sigma_m 5052 # works both for fixed number of generated events and fixed accepted events 5053 self.results.add_detail('error_pythia', error_m) 5054 break 5055 5056 #pythia_log.close() 5057 5058 pydir = pjoin(self.options['pythia-pgs_path'], 'src') 5059 eradir = self.options['exrootanalysis_path'] 5060 madir = self.options['madanalysis_path'] 5061 td = self.options['td_path'] 5062 5063 #Update the banner 5064 self.banner.add(pjoin(self.me_dir, 'Cards','pythia_card.dat')) 5065 if int(self.run_card['ickkw']): 5066 # Add the matched cross-section 5067 if 'MGGenerationInfo' in self.banner: 5068 self.banner['MGGenerationInfo'] += '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 5069 else: 5070 self.banner['MGGenerationInfo'] = '# Matched Integrated weight (pb) : %s\n' % self.results.current['cross_pythia'] 5071 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)) 5072 self.banner.write(banner_path) 5073 5074 # Creating LHE file 5075 self.run_hep2lhe(banner_path) 5076 5077 if int(self.run_card['ickkw']): 5078 misc.gzip(pjoin(self.me_dir,'Events','beforeveto.tree'), 5079 stdout=pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_beforeveto.tree.gz')) 5080 5081 5082 if self.run_card['use_syst'] in self.true: 5083 # Calculate syscalc info based on syst.dat 5084 try: 5085 self.run_syscalc('Pythia') 5086 except SysCalcError as error: 5087 logger.error(str(error)) 5088 else: 5089 if os.path.exists(pjoin(self.me_dir,'Events', 'syst.dat')): 5090 # Store syst.dat 5091 misc.gzip(pjoin(self.me_dir,'Events', 'syst.dat'), 5092 stdout=pjoin(self.me_dir,'Events',self.run_name, tag + '_pythia_syst.dat.gz')) 5093 5094 # Store syscalc.dat 5095 if os.path.exists(pjoin(self.me_dir, 'Events', 'syscalc.dat')): 5096 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 5097 '%s_syscalc.dat' % self.run_tag) 5098 misc.gzip(pjoin(self.me_dir, 'Events','syscalc.dat'), 5099 stdout = "%s.gz" % filename) 5100 5101 # Plot for pythia 5102 self.create_plot('Pythia') 5103 5104 if os.path.exists(pjoin(self.me_dir,'Events','pythia_events.lhe')): 5105 misc.gzip(pjoin(self.me_dir,'Events','pythia_events.lhe'), 5106 stdout=pjoin(self.me_dir,'Events', self.run_name,'%s_pythia_events.lhe.gz' % tag)) 5107 5108 self.update_status('finish', level='pythia', makehtml=False) 5109 self.exec_cmd('pgs --no_default', postcmd=False, printcmd=False) 5110 if self.options['delphes_path']: 5111 self.exec_cmd('delphes --no_default', postcmd=False, printcmd=False) 5112 self.print_results_in_shell(self.results.current)
5113 5114 5115 ################################################################################
5116 - def do_remove(self, line):
5117 """Remove one/all run or only part of it""" 5118 5119 args = self.split_arg(line) 5120 run, tag, mode = self.check_remove(args) 5121 if 'banner' in mode: 5122 mode.append('all') 5123 5124 5125 if run == 'all': 5126 # Check first if they are not a run with a name run. 5127 if os.path.exists(pjoin(self.me_dir, 'Events', 'all')): 5128 logger.warning('A run with name all exists. So we will not supress all processes.') 5129 else: 5130 for match in misc.glob(pjoin('*','*_banner.txt'), pjoin(self.me_dir, 'Events')): 5131 run = match.rsplit(os.path.sep,2)[1] 5132 if self.force: 5133 args.append('-f') 5134 try: 5135 self.exec_cmd('remove %s %s' % (run, ' '.join(args[1:]) ) ) 5136 except self.InvalidCmd as error: 5137 logger.info(error) 5138 pass # run already clear 5139 return 5140 5141 # Check that run exists 5142 if not os.path.exists(pjoin(self.me_dir, 'Events', run)): 5143 raise self.InvalidCmd('No run \'%s\' detected' % run) 5144 5145 try: 5146 self.resuls.def_current(run) 5147 self.update_status(' Cleaning %s' % run, level=None) 5148 except Exception: 5149 misc.sprint('fail to update results or html status') 5150 pass # Just ensure that html never makes crash this function 5151 5152 5153 # Found the file to delete 5154 5155 to_delete = misc.glob('*', pjoin(self.me_dir, 'Events', run)) 5156 to_delete += misc.glob('*', pjoin(self.me_dir, 'HTML', run)) 5157 # forbid the banner to be removed 5158 to_delete = [os.path.basename(f) for f in to_delete if 'banner' not in f] 5159 if tag: 5160 to_delete = [f for f in to_delete if tag in f] 5161 if 'parton' in mode or 'all' in mode: 5162 try: 5163 if self.results[run][0]['tag'] != tag: 5164 raise Exception('dummy') 5165 except Exception: 5166 pass 5167 else: 5168 nb_rm = len(to_delete) 5169 if os.path.exists(pjoin(self.me_dir, 'Events', run, 'events.lhe.gz')): 5170 to_delete.append('events.lhe.gz') 5171 if os.path.exists(pjoin(self.me_dir, 'Events', run, 'unweighted_events.lhe.gz')): 5172 to_delete.append('unweighted_events.lhe.gz') 5173 if os.path.exists(pjoin(self.me_dir, 'HTML', run,'plots_parton.html')): 5174 to_delete.append(pjoin(self.me_dir, 'HTML', run,'plots_parton.html')) 5175 if nb_rm != len(to_delete): 5176 logger.warning('Be carefull that partonic information are on the point to be removed.') 5177 if 'all' in mode: 5178 pass # delete everything 5179 else: 5180 if 'pythia' not in mode: 5181 to_delete = [f for f in to_delete if 'pythia' not in f] 5182 if 'pgs' not in mode: 5183 to_delete = [f for f in to_delete if 'pgs' not in f] 5184 if 'delphes' not in mode: 5185 to_delete = [f for f in to_delete if 'delphes' not in f] 5186 if 'parton' not in mode: 5187 to_delete = [f for f in to_delete if 'delphes' in f 5188 or 'pgs' in f 5189 or 'pythia' in f] 5190 if not self.force and len(to_delete): 5191 question = 'Do you want to delete the following files?\n %s' % \ 5192 '\n '.join(to_delete) 5193 ans = self.ask(question, 'y', choices=['y','n']) 5194 else: 5195 ans = 'y' 5196 5197 if ans == 'y': 5198 for file2rm in to_delete: 5199 if os.path.exists(pjoin(self.me_dir, 'Events', run, file2rm)): 5200 try: 5201 os.remove(pjoin(self.me_dir, 'Events', run, file2rm)) 5202 except Exception: 5203 shutil.rmtree(pjoin(self.me_dir, 'Events', run, file2rm)) 5204 else: 5205 try: 5206 os.remove(pjoin(self.me_dir, 'HTML', run, file2rm)) 5207 except Exception: 5208 shutil.rmtree(pjoin(self.me_dir, 'HTML', run, file2rm)) 5209 5210 5211 5212 # Remove file in SubProcess directory 5213 if 'all' in mode or 'channel' in mode: 5214 try: 5215 if tag and self.results[run][0]['tag'] != tag: 5216 raise Exception('dummy') 5217 except Exception: 5218 pass 5219 else: 5220 to_delete = misc.glob('%s*' % run, pjoin(self.me_dir, 'SubProcesses')) 5221 to_delete += misc.glob(pjoin('*','%s*' % run), pjoin(self.me_dir, 'SubProcesses')) 5222 to_delete += misc.glob(pjoin('*','*','%s*' % run), pjoin(self.me_dir, 'SubProcesses')) 5223 5224 if self.force or len(to_delete) == 0: 5225 ans = 'y' 5226 else: 5227 question = 'Do you want to delete the following files?\n %s' % \ 5228 '\n '.join(to_delete) 5229 ans = self.ask(question, 'y', choices=['y','n']) 5230 5231 if ans == 'y': 5232 for file2rm in to_delete: 5233 os.remove(file2rm) 5234 5235 if 'banner' in mode: 5236 to_delete = misc.glob('*', pjoin(self.me_dir, 'Events', run)) 5237 if tag: 5238 # remove banner 5239 try: 5240 os.remove(pjoin(self.me_dir, 'Events',run,'%s_%s_banner.txt' % (run,tag))) 5241 except Exception: 5242 logger.warning('fail to remove the banner') 5243 # remove the run from the html output 5244 if run in self.results: 5245 self.results.delete_run(run, tag) 5246 return 5247 elif any(['banner' not in os.path.basename(p) for p in to_delete]): 5248 if to_delete: 5249 raise MadGraph5Error('''Some output still exists for this run. 5250 Please remove those output first. Do for example: 5251 remove %s all banner 5252 ''' % run) 5253 else: 5254 shutil.rmtree(pjoin(self.me_dir, 'Events',run)) 5255 if run in self.results: 5256 self.results.delete_run(run) 5257 return 5258 else: 5259 logger.info('''The banner is not removed. In order to remove it run: 5260 remove %s all banner %s''' % (run, tag and '--tag=%s ' % tag or '')) 5261 5262 # update database. 5263 self.results.clean(mode, run, tag) 5264 self.update_status('', level='all')
5265 5266 5267 5268 ############################################################################
5269 - def do_plot(self, line):
5270 """Create the plot for a given run""" 5271 5272 # Since in principle, all plot are already done automaticaly 5273 self.store_result() 5274 args = self.split_arg(line) 5275 # Check argument's validity 5276 self.check_plot(args) 5277 logger.info('plot for run %s' % self.run_name) 5278 if not self.force: 5279 self.ask_edit_cards(['plot_card.dat'], args, plot=True) 5280 5281 if any([arg in ['all','parton'] for arg in args]): 5282 filename = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe') 5283 if os.path.exists(filename+'.gz'): 5284 misc.gunzip('%s.gz' % filename, keep=True) 5285 if os.path.exists(filename): 5286 files.ln(filename, pjoin(self.me_dir, 'Events')) 5287 self.create_plot('parton') 5288 if not os.path.exists(filename+'.gz'): 5289 misc.gzip(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), 5290 stdout= "%s.gz" % filename) 5291 else: 5292 try: 5293 os.remove(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')) 5294 os.remove(filename) 5295 except Exception: 5296 pass 5297 else: 5298 logger.info('No valid files for partonic plot') 5299 5300 if any([arg in ['all','pythia'] for arg in args]): 5301 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 5302 '%s_pythia_events.lhe' % self.run_tag) 5303 if os.path.exists(filename+'.gz'): 5304 misc.gunzip("%s.gz" % filename) 5305 if os.path.exists(filename): 5306 shutil.move(filename, pjoin(self.me_dir, 'Events','pythia_events.lhe')) 5307 self.create_plot('Pythia') 5308 misc.gzip(pjoin(self.me_dir, 'Events','pythia_events.lhe'), 5309 stdout= "%s.gz" % filename) 5310 else: 5311 logger.info('No valid files for pythia plot') 5312 5313 5314 if any([arg in ['all','pgs'] for arg in args]): 5315 filename = pjoin(self.me_dir, 'Events', self.run_name, 5316 '%s_pgs_events.lhco' % self.run_tag) 5317 if os.path.exists(filename+'.gz'): 5318 misc.gunzip("%s.gz" % filename) 5319 if os.path.exists(filename): 5320 self.create_plot('PGS') 5321 misc.gzip(filename) 5322 else: 5323 logger.info('No valid files for pgs plot') 5324 5325 if any([arg in ['all','delphes'] for arg in args]): 5326 filename = pjoin(self.me_dir, 'Events', self.run_name, 5327 '%s_delphes_events.lhco' % self.run_tag) 5328 if os.path.exists(filename+'.gz'): 5329 misc.gunzip("%s.gz" % filename) 5330 if os.path.exists(filename): 5331 self.create_plot('Delphes') 5332 misc.gzip(filename) 5333 else: 5334 logger.info('No valid files for delphes plot')
5335 5336 ############################################################################
5337 - def do_syscalc(self, line):
5338 """Evaluate systematics variation weights for a given run""" 5339 5340 # Since in principle, all systematics run are already done automaticaly 5341 self.store_result() 5342 args = self.split_arg(line) 5343 # Check argument's validity 5344 self.check_syscalc(args) 5345 if self.ninitial == 1: 5346 logger.error('SysCalc can\'t be run for decay processes') 5347 return 5348 5349 logger.info('Calculating systematics for run %s' % self.run_name) 5350 5351 self.ask_edit_cards(['run_card.dat'], args, plot=False) 5352 self.run_card = banner_mod.RunCard(pjoin(self.me_dir, 'Cards', 'run_card.dat')) 5353 if any([arg in ['all','parton'] for arg in args]): 5354 filename = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe') 5355 if os.path.exists(filename+'.gz'): 5356 misc.gunzip("%s.gz" % filename) 5357 if os.path.exists(filename): 5358 shutil.move(filename, pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')) 5359 self.run_syscalc('parton') 5360 misc.gzip(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), 5361 stdout="%s.gz" % filename) 5362 else: 5363 logger.info('No valid files for parton level systematics run.') 5364 5365 if any([arg in ['all','pythia'] for arg in args]): 5366 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 5367 '%s_pythia_syst.dat' % self.run_tag) 5368 if os.path.exists(filename+'.gz'): 5369 misc.gunzip("%s.gz" % filename) 5370 if os.path.exists(filename): 5371 shutil.move(filename, pjoin(self.me_dir, 'Events','syst.dat')) 5372 try: 5373 self.run_syscalc('Pythia') 5374 except SysCalcError as error: 5375 logger.warning(str(error)) 5376 return 5377 misc.gzip(pjoin(self.me_dir, 'Events','syst.dat'), "%s.gz" % filename) 5378 filename = pjoin(self.me_dir, 'Events' ,self.run_name, 5379 '%s_syscalc.dat' % self.run_tag) 5380 misc.gzip(pjoin(self.me_dir, 'Events','syscalc.dat'), 5381 stdout=filename) 5382 else: 5383 logger.info('No valid files for pythia level')
5384 5385
5386 - def store_result(self):
5387 """ tar the pythia results. This is done when we are quite sure that 5388 the pythia output will not be use anymore """ 5389 5390 if not self.run_name: 5391 return 5392 5393 5394 5395 if not self.to_store: 5396 return 5397 5398 tag = self.run_card['run_tag'] 5399 self.update_status('storing files of previous run', level=None,\ 5400 error=True) 5401 if 'event' in self.to_store: 5402 if not os.path.exists(pjoin(self.me_dir, 'Events',self.run_name, 'unweighted_events.lhe.gz')) and\ 5403 os.path.exists(pjoin(self.me_dir, 'Events',self.run_name, 'unweighted_events.lhe')): 5404 logger.info("gzipping output file: unweighted_events.lhe") 5405 misc.gzip(pjoin(self.me_dir,'Events',self.run_name,"unweighted_events.lhe")) 5406 if os.path.exists(pjoin(self.me_dir,'Events','reweight.lhe')): 5407 os.remove(pjoin(self.me_dir,'Events', 'reweight.lhe')) 5408 5409 if 'pythia' in self.to_store: 5410 self.update_status('Storing Pythia files of previous run', level='pythia', error=True) 5411 p = pjoin(self.me_dir,'Events') 5412 n = self.run_name 5413 t = tag 5414 self.to_store.remove('pythia') 5415 misc.gzip(pjoin(p,'pythia_events.hep'), 5416 stdout=pjoin(p, str(n),'%s_pythia_events.hep' % t),forceexternal=True) 5417 5418 if 'pythia8' in self.to_store: 5419 p = pjoin(self.me_dir,'Events') 5420 n = self.run_name 5421 t = tag 5422 file_path = pjoin(p, n ,'%s_pythia8_events.hepmc'%t) 5423 self.to_store.remove('pythia8') 5424 if os.path.isfile(file_path): 5425 if 'nopy8' in self.to_store: 5426 os.remove(file_path) 5427 else: 5428 self.update_status('Storing Pythia8 files of previous run', 5429 level='pythia', error=True) 5430 misc.gzip(file_path,stdout=file_path) 5431 5432 self.update_status('Done', level='pythia',makehtml=False,error=True) 5433 self.results.save() 5434 5435 self.to_store = []
5436
5437 - def launch_job(self,exe, cwd=None, stdout=None, argument = [], remaining=0, 5438 run_type='', mode=None, **opt):
5439 """ """ 5440 argument = [str(arg) for arg in argument] 5441 if mode is None: 5442 mode = self.cluster_mode 5443 5444 # ensure that exe is executable 5445 if os.path.exists(exe) and not os.access(exe, os.X_OK): 5446 os.system('chmod +x %s ' % exe) 5447 elif (cwd and os.path.exists(pjoin(cwd, exe))) and not \ 5448 os.access(pjoin(cwd, exe), os.X_OK): 5449 os.system('chmod +x %s ' % pjoin(cwd, exe)) 5450 5451 if mode == 0: 5452 self.update_status((remaining, 1, 5453 self.total_jobs - remaining -1, run_type), level=None, force=False) 5454 start = time.time() 5455 #os.system('cd %s; ./%s' % (cwd,exe)) 5456 status = misc.call([exe] + argument, cwd=cwd, stdout=stdout, **opt) 5457 logger.info('%s run in %f s' % (exe, time.time() -start)) 5458 if status: 5459 raise MadGraph5Error('%s didn\'t stop properly. Stop all computation' % exe) 5460 5461 5462 elif mode in [1,2]: 5463 exename = os.path.basename(exe) 5464 # For condor cluster, create the input/output files 5465 if 'ajob' in exename: 5466 input_files = ['madevent','input_app.txt','symfact.dat','iproc.dat','dname.mg', 5467 pjoin(self.me_dir, 'SubProcesses','randinit')] 5468 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 5469 'MadLoop5_resources.tar.gz')) and cluster.need_transfer(self.options): 5470 input_files.append(pjoin(self.me_dir,'SubProcesses', 'MadLoop5_resources.tar.gz')) 5471 5472 output_files = [] 5473 required_output = [] 5474 5475 5476 #Find the correct PDF input file 5477 input_files.append(self.get_pdf_input_filename()) 5478 5479 #Find the correct ajob 5480 Gre = re.compile("\s*j=(G[\d\.\w]+)") 5481 origre = re.compile("grid_directory=(G[\d\.\w]+)") 5482 try : 5483 fsock = open(exe) 5484 except Exception: 5485 fsock = open(pjoin(cwd,exe)) 5486 text = fsock.read() 5487 output_files = Gre.findall(text) 5488 if not output_files: 5489 Ire = re.compile("for i in ([\d\.\s]*) ; do") 5490 data = Ire.findall(text) 5491 data = ' '.join(data).split() 5492 for nb in data: 5493 output_files.append('G%s' % nb) 5494 required_output.append('G%s/results.dat' % nb) 5495 else: 5496 for G in output_files: 5497 if os.path.isdir(pjoin(cwd,G)): 5498 input_files.append(G) 5499 required_output.append('%s/results.dat' % G) 5500 5501 if origre.search(text): 5502 G_grid = origre.search(text).groups()[0] 5503 input_files.append(pjoin(G_grid, 'ftn26')) 5504 5505 #submitting 5506 self.cluster.submit2(exe, stdout=stdout, cwd=cwd, 5507 input_files=input_files, output_files=output_files, 5508 required_output=required_output) 5509 elif 'survey' in exename: 5510 input_files = ['madevent','input_app.txt','symfact.dat','iproc.dat', 'dname.mg', 5511 pjoin(self.me_dir, 'SubProcesses','randinit')] 5512 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 5513 'MadLoop5_resources.tar.gz')) and cluster.need_transfer(self.options): 5514 input_files.append(pjoin(self.me_dir,'SubProcesses', 5515 'MadLoop5_resources.tar.gz')) 5516 5517 #Find the correct PDF input file 5518 input_files.append(self.get_pdf_input_filename()) 5519 5520 5521 output_files = [] 5522 required_output = [] 5523 5524 #Find the correct ajob 5525 suffix = "_%s" % int(float(argument[0])) 5526 if suffix == '_0': 5527 suffix = '' 5528 output_files = ['G%s%s' % (i, suffix) for i in argument[1:]] 5529 for G in output_files: 5530 required_output.append('%s/results.dat' % G) 5531 5532 # add the grid information if needed 5533 for G in output_files: 5534 if '.' in argument[0]: 5535 offset = int(str(argument[0]).split('.')[1]) 5536 else: 5537 offset = 0 5538 5539 if offset ==0 or offset == int(float(argument[0])): 5540 if os.path.exists(pjoin(cwd, G, 'input_app.txt')): 5541 os.remove(pjoin(cwd, G, 'input_app.txt')) 5542 5543 if os.path.exists(os.path.realpath(pjoin(cwd, G, 'ftn25'))): 5544 if offset == 0 or offset == int(float(argument[0])): 5545 os.remove(pjoin(cwd, G, 'ftn25')) 5546 continue 5547 else: 5548 input_files.append(pjoin(cwd, G, 'ftn25')) 5549 input_files.remove('input_app.txt') 5550 input_files.append(pjoin(cwd, G, 'input_app.txt')) 5551 elif os.path.lexists(pjoin(cwd, G, 'ftn25')): 5552 try: 5553 os.remove(pjoin(cwd,G,'ftn25')) 5554 except: 5555 pass 5556 5557 #submitting 5558 self.cluster.cluster_submit(exe, stdout=stdout, cwd=cwd, argument=argument, 5559 input_files=input_files, output_files=output_files, 5560 required_output=required_output, **opt) 5561 elif "refine_splitted.sh" in exename: 5562 input_files = ['madevent','symfact.dat','iproc.dat', 'dname.mg', 5563 pjoin(self.me_dir, 'SubProcesses','randinit')] 5564 5565 if os.path.exists(pjoin(self.me_dir,'SubProcesses', 5566 'MadLoop5_resources.tar.gz')) and cluster.need_transfer(self.options): 5567 input_files.append(pjoin(self.me_dir,'SubProcesses', 5568 'MadLoop5_resources.tar.gz')) 5569 5570 #Find the correct PDF input file 5571 input_files.append(self.get_pdf_input_filename()) 5572 5573 5574 output_files = [argument[0]] 5575 required_output = [] 5576 for G in output_files: 5577 required_output.append('%s/results.dat' % G) 5578 input_files.append(pjoin(argument[1], "input_app.txt")) 5579 input_files.append(pjoin(argument[1], "ftn26")) 5580 5581 #submitting 5582 self.cluster.cluster_submit(exe, stdout=stdout, cwd=cwd, argument=argument, 5583 input_files=input_files, output_files=output_files, 5584 required_output=required_output, **opt) 5585 5586 5587 5588 else: 5589 self.cluster.submit(exe, argument=argument, stdout=stdout, cwd=cwd, **opt)
5590 5591 5592 ############################################################################
5593 - def find_madevent_mode(self):
5594 """Find if Madevent is in Group mode or not""" 5595 5596 # The strategy is too look in the files Source/run_configs.inc 5597 # if we found: ChanPerJob=3 then it's a group mode. 5598 file_path = pjoin(self.me_dir, 'Source', 'run_config.inc') 5599 text = open(file_path).read() 5600 if re.search(r'''s*parameter\s+\(ChanPerJob=2\)''', text, re.I+re.M): 5601 return 'group' 5602 else: 5603 return 'v4'
5604 5605 ############################################################################
5606 - def monitor(self, run_type='monitor', mode=None, html=False):
5607 """ monitor the progress of running job """ 5608 5609 5610 starttime = time.time() 5611 if mode is None: 5612 mode = self.cluster_mode 5613 if mode > 0: 5614 if html: 5615 update_status = lambda idle, run, finish: \ 5616 self.update_status((idle, run, finish, run_type), level=None, 5617 force=False, starttime=starttime) 5618 update_first = lambda idle, run, finish: \ 5619 self.update_status((idle, run, finish, run_type), level=None, 5620 force=True, starttime=starttime) 5621 else: 5622 update_status = lambda idle, run, finish: None 5623 update_first = None 5624 try: 5625 self.cluster.wait(self.me_dir, update_status, update_first=update_first) 5626 except Exception as error: 5627 logger.info(error) 5628 if not self.force: 5629 ans = self.ask('Cluster Error detected. Do you want to clean the queue? ("c"=continue the run anyway)', 5630 default = 'y', choices=['y','n', 'c']) 5631 else: 5632 ans = 'y' 5633 if ans == 'y': 5634 self.cluster.remove() 5635 elif ans == 'c': 5636 return self.monitor(run_type=run_type, mode=mode, html=html) 5637 raise 5638 except KeyboardInterrupt as error: 5639 self.cluster.remove() 5640 raise
5641 5642 5643 5644 ############################################################################
5645 - def configure_directory(self, html_opening=True):
5646 """ All action require before any type of run """ 5647 5648 # Basic check 5649 assert os.path.exists(pjoin(self.me_dir,'SubProcesses')) 5650 5651 # environmental variables to be included in make_opts 5652 self.make_opts_var = {} 5653 5654 #see when the last file was modified 5655 time_mod = max([os.path.getmtime(pjoin(self.me_dir,'Cards','run_card.dat')), 5656 os.path.getmtime(pjoin(self.me_dir,'Cards','param_card.dat'))]) 5657 5658 if self.configured >= time_mod and hasattr(self, 'random') and hasattr(self, 'run_card'): 5659 #just ensure that cluster specific are correctly handled 5660 if self.cluster: 5661 self.cluster.modify_interface(self) 5662 return 5663 else: 5664 self.configured = time_mod 5665 self.update_status('compile directory', level=None, update_results=True) 5666 if self.options['automatic_html_opening'] and html_opening: 5667 misc.open_file(os.path.join(self.me_dir, 'crossx.html')) 5668 self.options['automatic_html_opening'] = False 5669 #open only once the web page 5670 # Change current working directory 5671 self.launching_dir = os.getcwd() 5672 5673 # Check if we need the MSSM special treatment 5674 model = self.find_model_name() 5675 if model == 'mssm' or model.startswith('mssm-'): 5676 param_card = pjoin(self.me_dir, 'Cards','param_card.dat') 5677 mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat') 5678 check_param_card.convert_to_mg5card(param_card, mg5_param) 5679 check_param_card.check_valid_param_card(mg5_param) 5680 5681 # limit the number of event to 100k 5682 self.check_nb_events() 5683 5684 # this is in order to avoid conflicts between runs with and without 5685 # lhapdf 5686 misc.compile(['clean4pdf'], cwd = pjoin(self.me_dir, 'Source')) 5687 5688 # set lhapdf. 5689 if self.run_card['pdlabel'] == "lhapdf": 5690 self.make_opts_var['lhapdf'] = 'True' 5691 self.link_lhapdf(pjoin(self.me_dir,'lib')) 5692 pdfsetsdir = self.get_lhapdf_pdfsetsdir() 5693 lhaid_list = [int(self.run_card['lhaid'])] 5694 self.copy_lhapdf_set(lhaid_list, pdfsetsdir) 5695 if self.run_card['pdlabel'] != "lhapdf": 5696 self.pdffile = None 5697 self.make_opts_var['lhapdf'] = "" 5698 5699 # set random number 5700 if self.run_card['iseed'] != 0: 5701 self.random = int(self.run_card['iseed']) 5702 self.run_card['iseed'] = 0 5703 # Reset seed in run_card to 0, to ensure that following runs 5704 # will be statistically independent 5705 self.run_card.write(pjoin(self.me_dir, 'Cards','run_card.dat'), template=pjoin(self.me_dir, 'Cards','run_card.dat')) 5706 time_mod = max([os.path.getmtime(pjoin(self.me_dir,'Cards','run_card.dat')), 5707 os.path.getmtime(pjoin(self.me_dir,'Cards','param_card.dat'))]) 5708 self.configured = time_mod 5709 elif os.path.exists(pjoin(self.me_dir,'SubProcesses','randinit')): 5710 for line in open(pjoin(self.me_dir,'SubProcesses','randinit')): 5711 data = line.split('=') 5712 assert len(data) ==2 5713 self.random = int(data[1]) 5714 break 5715 else: 5716 self.random = random.randint(1, 30107) 5717 5718 #set random seed for python part of the code 5719 if self.run_card['python_seed'] == -2: #-2 means same as run_card 5720 import random 5721 random.seed(self.random) 5722 elif self.run_card['python_seed'] >= 0: 5723 import random 5724 random.seed(self.run_card['python_seed']) 5725 if self.run_card['ickkw'] == 2: 5726 logger.info('Running with CKKW matching') 5727 self.treat_ckkw_matching() 5728 5729 # add the make_opts_var to make_opts 5730 self.update_make_opts(self.run_card) 5731 # reset list of Gdirectory 5732 self.Gdirs = None 5733 5734 # create param_card.inc and run_card.inc 5735 self.do_treatcards('') 5736 5737 logger.info("compile Source Directory") 5738 5739 # Compile 5740 for name in [ 'all']:#, '../bin/internal/combine_events']: 5741 self.compile(arg=[name], cwd=os.path.join(self.me_dir, 'Source')) 5742 5743 bias_name = os.path.basename(self.run_card['bias_module']) 5744 if bias_name.lower()=='none': 5745 bias_name = 'dummy' 5746 5747 # Always refresh the bias dependencies file 5748 if os.path.exists(pjoin(self.me_dir, 'SubProcesses','bias_dependencies')): 5749 os.remove(pjoin(self.me_dir, 'SubProcesses','bias_dependencies')) 5750 if os.path.exists(pjoin(self.me_dir, 'Source','BIAS',bias_name,'bias_dependencies')): 5751 files.ln(pjoin(self.me_dir, 'Source','BIAS',bias_name,'bias_dependencies'), 5752 pjoin(self.me_dir, 'SubProcesses')) 5753 5754 if self.proc_characteristics['bias_module']!=bias_name and \ 5755 os.path.isfile(pjoin(self.me_dir, 'lib','libbias.a')): 5756 os.remove(pjoin(self.me_dir, 'lib','libbias.a')) 5757 5758 # Finally compile the bias module as well 5759 if self.run_card['bias_module']!='dummy': 5760 logger.debug("Compiling the bias module '%s'"%bias_name) 5761 # Verify the compatibility of the specified module 5762 bias_module_valid = misc.Popen(['make','requirements'], 5763 cwd=os.path.join(self.me_dir, 'Source','BIAS',bias_name), 5764 stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0].decode() 5765 if 'VALID' not in str(bias_module_valid).upper() or \ 5766 'INVALID' in str(bias_module_valid).upper(): 5767 raise InvalidCmd("The bias module '%s' cannot be used because of:\n%s"% 5768 (bias_name,bias_module_valid)) 5769 5770 self.compile(arg=[], cwd=os.path.join(self.me_dir, 'Source','BIAS',bias_name)) 5771 self.proc_characteristics['bias_module']=bias_name 5772 # Update the proc_characterstics file 5773 self.proc_characteristics.write( 5774 pjoin(self.me_dir,'SubProcesses','proc_characteristics')) 5775 # Make sure that madevent will be recompiled 5776 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 5777 'subproc.mg'))] 5778 for nb_proc,subdir in enumerate(subproc): 5779 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir.strip()) 5780 self.compile(['clean'], cwd=Pdir) 5781 5782 #see when the last file was modified 5783 time_mod = max([os.path.getmtime(pjoin(self.me_dir,'Cards','run_card.dat')), 5784 os.path.getmtime(pjoin(self.me_dir,'Cards','param_card.dat'))]) 5785 5786 self.configured = time_mod
5787 5788 ############################################################################ 5789 ## HELPING ROUTINE 5790 ############################################################################ 5791 @staticmethod
5792 - def check_dir(path, default=''):
5793 """check if the directory exists. if so return the path otherwise the 5794 default""" 5795 5796 if os.path.isdir(path): 5797 return path 5798 else: 5799 return default
5800 5801 5802 5803 ############################################################################
5804 - def get_Gdir(self, Pdir=None, symfact=None):
5805 """get the list of Gdirectory if not yet saved.""" 5806 5807 if hasattr(self, "Gdirs") and self.Gdirs: 5808 if self.me_dir in self.Gdirs[0]: 5809 if Pdir is None: 5810 if not symfact: 5811 return list(itertools.chain(*list(self.Gdirs[0].values()))) 5812 else: 5813 return list(itertools.chain(*list(self.Gdirs[0].values()))), self.Gdirs[1] 5814 else: 5815 if not symfact: 5816 return self.Gdirs[0][Pdir] 5817 else: 5818 return self.Gdirs[0][Pdir], self.Gdirs[1] 5819 5820 5821 Pdirs = self.get_Pdir() 5822 Gdirs = {self.me_dir:[]} 5823 mfactors = {} 5824 for P in Pdirs: 5825 Gdirs[P] = [] 5826 #for the next line do not use P, since in readonly mode it might not have symfact 5827 for line in open(pjoin(self.me_dir, 'SubProcesses',os.path.basename(P), "symfact.dat")): 5828 tag, mfactor = line.split() 5829 if int(mfactor) > 0: 5830 Gdirs[P].append( pjoin(P, "G%s" % tag) ) 5831 mfactors[pjoin(P, "G%s" % tag)] = mfactor 5832 self.Gdirs = (Gdirs, mfactors) 5833 return self.get_Gdir(Pdir, symfact=symfact)
5834 5835 ############################################################################
5836 - def set_run_name(self, name, tag=None, level='parton', reload_card=False, 5837 allow_new_tag=True):
5838 """define the run name, the run_tag, the banner and the results.""" 5839 5840 def get_last_tag(self, level): 5841 # Return the tag of the previous run having the required data for this 5842 # tag/run to working wel. 5843 if level == 'parton': 5844 return 5845 elif level in ['pythia','pythia8','madanalysis5_parton','madanalysis5_hadron']: 5846 return self.results[self.run_name][0]['tag'] 5847 else: 5848 for i in range(-1,-len(self.results[self.run_name])-1,-1): 5849 tagRun = self.results[self.run_name][i] 5850 if tagRun.pythia or tagRun.shower or tagRun.pythia8 : 5851 return tagRun['tag']
5852 5853 5854 # when are we force to change the tag new_run:previous run requiring changes 5855 upgrade_tag = {'parton': ['parton','pythia','pgs','delphes','madanalysis5_hadron','madanalysis5_parton'], 5856 'pythia': ['pythia','pgs','delphes','madanalysis5_hadron'], 5857 'pythia8': ['pythia8','pgs','delphes','madanalysis5_hadron'], 5858 'pgs': ['pgs'], 5859 'delphes':['delphes'], 5860 'madanalysis5_hadron':['madanalysis5_hadron'], 5861 'madanalysis5_parton':['madanalysis5_parton'], 5862 'plot':[], 5863 'syscalc':[]} 5864 5865 if name == self.run_name: 5866 if reload_card: 5867 run_card = pjoin(self.me_dir, 'Cards','run_card.dat') 5868 self.run_card = banner_mod.RunCard(run_card) 5869 5870 #check if we need to change the tag 5871 if tag: 5872 self.run_card['run_tag'] = tag 5873 self.run_tag = tag 5874 self.results.add_run(self.run_name, self.run_card) 5875 else: 5876 for tag in upgrade_tag[level]: 5877 if getattr(self.results[self.run_name][-1], tag): 5878 tag = self.get_available_tag() 5879 self.run_card['run_tag'] = tag 5880 self.run_tag = tag 5881 self.results.add_run(self.run_name, self.run_card) 5882 break 5883 return get_last_tag(self, level) 5884 5885 5886 # save/clean previous run 5887 if self.run_name: 5888 self.store_result() 5889 # store new name 5890 self.run_name = name 5891 5892 new_tag = False 5893 # First call for this run -> set the banner 5894 self.banner = banner_mod.recover_banner(self.results, level, name) 5895 if 'mgruncard' in self.banner: 5896 self.run_card = self.banner.charge_card('run_card') 5897 else: 5898 # Read run_card 5899 run_card = pjoin(self.me_dir, 'Cards','run_card.dat') 5900 self.run_card = banner_mod.RunCard(run_card) 5901 5902 if tag: 5903 self.run_card['run_tag'] = tag 5904 new_tag = True 5905 elif not self.run_name in self.results and level =='parton': 5906 pass # No results yet, so current tag is fine 5907 elif not self.run_name in self.results: 5908 #This is only for case when you want to trick the interface 5909 logger.warning('Trying to run data on unknown run.') 5910 self.results.add_run(name, self.run_card) 5911 self.results.update('add run %s' % name, 'all', makehtml=False) 5912 else: 5913 for tag in upgrade_tag[level]: 5914 5915 if getattr(self.results[self.run_name][-1], tag): 5916 # LEVEL is already define in the last tag -> need to switch tag 5917 tag = self.get_available_tag() 5918 self.run_card['run_tag'] = tag 5919 new_tag = True 5920 break 5921 if not new_tag: 5922 # We can add the results to the current run 5923 tag = self.results[self.run_name][-1]['tag'] 5924 self.run_card['run_tag'] = tag # ensure that run_tag is correct 5925 5926 if allow_new_tag and (name in self.results and not new_tag): 5927 self.results.def_current(self.run_name) 5928 else: 5929 self.results.add_run(self.run_name, self.run_card) 5930 5931 self.run_tag = self.run_card['run_tag'] 5932 5933 return get_last_tag(self, level) 5934 5935 5936 5937 ############################################################################
5938 - def check_nb_events(self):
5939 """Find the number of event in the run_card, and check that this is not 5940 too large""" 5941 5942 5943 nb_event = int(self.run_card['nevents']) 5944 if nb_event > 1000000: 5945 logger.warning("Attempting to generate more than 1M events") 5946 logger.warning("Limiting number to 1M. Use multi_run for larger statistics.") 5947 path = pjoin(self.me_dir, 'Cards', 'run_card.dat') 5948 os.system(r"""perl -p -i.bak -e "s/\d+\s*=\s*nevents/1000000 = nevents/" %s""" \ 5949 % path) 5950 self.run_card['nevents'] = 1000000 5951 5952 return
5953 5954 5955 ############################################################################
5956 - def update_random(self):
5957 """ change random number""" 5958 5959 self.random += 3 5960 if self.random > 30081*30081: # can't use too big random number 5961 raise MadGraph5Error('Random seed too large ' + str(self.random) + ' > 30081*30081') 5962 if self.run_card['python_seed'] == -2: 5963 import random 5964 random.seed(self.random)
5965 5966 ############################################################################
5967 - def save_random(self):
5968 """save random number in appropirate file""" 5969 5970 fsock = open(pjoin(self.me_dir, 'SubProcesses','randinit'),'w') 5971 fsock.writelines('r=%s\n' % self.random)
5972
5973 - def do_quit(self, *args, **opts):
5974 5975 return common_run.CommonRunCmd.do_quit(self, *args, **opts)
5976 #return CmdExtended.do_quit(self, *args, **opts) 5977 5978 ############################################################################
5979 - def treat_CKKW_matching(self):
5980 """check for ckkw""" 5981 5982 lpp1 = self.run_card['lpp1'] 5983 lpp2 = self.run_card['lpp2'] 5984 e1 = self.run_card['ebeam1'] 5985 e2 = self.run_card['ebeam2'] 5986 pd = self.run_card['pdlabel'] 5987 lha = self.run_card['lhaid'] 5988 xq = self.run_card['xqcut'] 5989 translation = {'e1': e1, 'e2':e2, 'pd':pd, 5990 'lha':lha, 'xq':xq} 5991 5992 if lpp1 or lpp2: 5993 # Remove ':s from pd 5994 if pd.startswith("'"): 5995 pd = pd[1:] 5996 if pd.endswith("'"): 5997 pd = pd[:-1] 5998 5999 if xq >2 or xq ==2: 6000 xq = 2 6001 6002 # find data file 6003 if pd == "lhapdf": 6004 issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(lha)s-%(xq)s.dat.gz' 6005 else: 6006 issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(xq)s.dat.gz' 6007 if self.web: 6008 issudfile = pjoin(self.webbin, issudfile % translation) 6009 else: 6010 issudfile = pjoin(self.me_dir, issudfile % translation) 6011 6012 logger.info('Sudakov grid file: %s' % issudfile) 6013 6014 # check that filepath exists 6015 if os.path.exists(issudfile): 6016 path = pjoin(self.me_dir, 'lib', 'issudgrid.dat') 6017 misc.gunzip(issudfile, keep=True, stdout=path) 6018 else: 6019 msg = 'No sudakov grid file for parameter choice. Start to generate it. This might take a while' 6020 logger.info(msg) 6021 self.update_status('GENERATE SUDAKOV GRID', level='parton') 6022 6023 for i in range(-2,6): 6024 self.cluster.submit('%s/gensudgrid ' % self.dirbin, 6025 argument = ['%d'%i], 6026 cwd=self.me_dir, 6027 stdout=open(pjoin(self.me_dir, 'gensudgrid%s.log' % i),'w')) 6028 self.monitor() 6029 for i in range(-2,6): 6030 path = pjoin(self.me_dir, 'lib', 'issudgrid.dat') 6031 os.system('cat %s/gensudgrid%s.log >> %s' % (self.me_dir, path)) 6032 misc.gzip(path, stdout=issudfile)
6033 6034 ############################################################################
6035 - def create_root_file(self, input='unweighted_events.lhe', 6036 output='unweighted_events.root' ):
6037 """create the LHE root file """ 6038 self.update_status('Creating root files', level='parton') 6039 6040 eradir = self.options['exrootanalysis_path'] 6041 totar = False 6042 torm = False 6043 if input.endswith('.gz'): 6044 if not os.path.exists(input) and os.path.exists(input[:-3]): 6045 totar = True 6046 input = input[:-3] 6047 else: 6048 misc.gunzip(input, keep=True) 6049 totar = False 6050 torm = True 6051 input = input[:-3] 6052 6053 try: 6054 misc.call(['%s/ExRootLHEFConverter' % eradir, 6055 input, output], 6056 cwd=pjoin(self.me_dir, 'Events')) 6057 except Exception: 6058 logger.warning('fail to produce Root output [problem with ExRootAnalysis]') 6059 6060 if totar: 6061 if os.path.exists('%s.gz' % input): 6062 try: 6063 os.remove('%s.gz' % input) 6064 except: 6065 pass 6066 else: 6067 misc.gzip(input) 6068 if torm: 6069 os.remove(input)
6070
6071 - def run_syscalc(self, mode='parton', event_path=None, output=None):
6072 """create the syscalc output""" 6073 6074 if self.run_card['use_syst'] not in self.true: 6075 return 6076 6077 scdir = self.options['syscalc_path'] 6078 if not scdir or not os.path.exists(scdir): 6079 return 6080 6081 if self.run_card['event_norm'] != 'sum': 6082 logger.critical('SysCalc works only when event_norm is on \'sum\'.') 6083 return 6084 logger.info('running SysCalc on mode %s' % mode) 6085 6086 # Restore the old default for SysCalc+PY6 6087 if self.run_card['sys_matchscale']=='auto': 6088 self.run_card['sys_matchscale'] = "30 50" 6089 6090 # Check that all pdfset are correctly installed 6091 lhaid = [self.run_card.get_lhapdf_id()] 6092 if '&&' in self.run_card['sys_pdf']: 6093 line = ' '.join(self.run_card['sys_pdf']) 6094 sys_pdf = line.split('&&') 6095 lhaid += [l.split()[0] for l in sys_pdf] 6096 else: 6097 lhaid += [l for l in self.run_card['sys_pdf'].split() if not l.isdigit() or int(l) > 500] 6098 try: 6099 pdfsets_dir = self.get_lhapdf_pdfsetsdir() 6100 except Exception as error: 6101 logger.debug(str(error)) 6102 logger.warning('Systematic computation requires lhapdf to run. Bypass SysCalc') 6103 return 6104 6105 # Copy all the relevant PDF sets 6106 [self.copy_lhapdf_set([onelha], pdfsets_dir) for onelha in lhaid] 6107 6108 to_syscalc={'sys_scalefact': self.run_card['sys_scalefact'], 6109 'sys_alpsfact': self.run_card['sys_alpsfact'], 6110 'sys_matchscale': self.run_card['sys_matchscale'], 6111 'sys_scalecorrelation': self.run_card['sys_scalecorrelation'], 6112 'sys_pdf': self.run_card['sys_pdf']} 6113 6114 tag = self.run_card['run_tag'] 6115 card = pjoin(self.me_dir, 'bin','internal', 'syscalc_card.dat') 6116 template = open(pjoin(self.me_dir, 'bin','internal', 'syscalc_template.dat')).read() 6117 6118 if '&&' in to_syscalc['sys_pdf']: 6119 to_syscalc['sys_pdf'] = to_syscalc['sys_pdf'].split('#',1)[0].replace('&&',' \n ') 6120 else: 6121 data = to_syscalc['sys_pdf'].split() 6122 new = [] 6123 for d in data: 6124 if not d.isdigit(): 6125 new.append(d) 6126 elif int(d) > 500: 6127 new.append(d) 6128 else: 6129 new[-1] += ' %s' % d 6130 to_syscalc['sys_pdf'] = '\n'.join(new) 6131 6132 if to_syscalc['sys_pdf'].lower() in ['', 'f', 'false', 'none', '.false.']: 6133 to_syscalc['sys_pdf'] = '' 6134 if to_syscalc['sys_alpsfact'].lower() in ['', 'f', 'false', 'none','.false.']: 6135 to_syscalc['sys_alpsfact'] = '' 6136 6137 6138 6139 6140 # check if the scalecorrelation parameter is define: 6141 if not 'sys_scalecorrelation' in self.run_card: 6142 self.run_card['sys_scalecorrelation'] = -1 6143 open(card,'w').write(template % self.run_card) 6144 6145 if not os.path.exists(card): 6146 return False 6147 6148 6149 6150 event_dir = pjoin(self.me_dir, 'Events') 6151 6152 if not event_path: 6153 if mode == 'parton': 6154 event_path = pjoin(event_dir,self.run_name, 'unweighted_events.lhe') 6155 if not (os.path.exists(event_path) or os.path.exists(event_path+".gz")): 6156 event_path = pjoin(event_dir, 'unweighted_events.lhe') 6157 output = pjoin(event_dir, 'syscalc.lhe') 6158 stdout = open(pjoin(event_dir, self.run_name, '%s_systematics.log' % (mode)),'w') 6159 elif mode == 'Pythia': 6160 stdout = open(pjoin(event_dir, self.run_name, '%s_%s_syscalc.log' % (tag,mode)),'w') 6161 if 'mgpythiacard' in self.banner: 6162 pat = re.compile('''^\s*qcut\s*=\s*([\+\-\d.e]*)''', re.M+re.I) 6163 data = pat.search(self.banner['mgpythiacard']) 6164 if data: 6165 qcut = float(data.group(1)) 6166 xqcut = abs(self.run_card['xqcut']) 6167 for value in self.run_card['sys_matchscale'].split(): 6168 if float(value) < qcut: 6169 raise SysCalcError('qcut value for sys_matchscale lower than qcut in pythia_card. Bypass syscalc') 6170 if float(value) < xqcut: 6171 raise SysCalcError('qcut value for sys_matchscale lower than xqcut in run_card. Bypass syscalc') 6172 6173 6174 event_path = pjoin(event_dir,'syst.dat') 6175 output = pjoin(event_dir, 'syscalc.dat') 6176 else: 6177 raise self.InvalidCmd('Invalid mode %s' % mode) 6178 6179 if not os.path.exists(event_path): 6180 if os.path.exists(event_path+'.gz'): 6181 misc.gunzip(event_path+'.gz') 6182 else: 6183 raise SysCalcError('Events file %s does not exits' % event_path) 6184 6185 self.update_status('Calculating systematics for %s level' % mode, level = mode.lower()) 6186 try: 6187 proc = misc.call([os.path.join(scdir, 'sys_calc'), 6188 event_path, card, output], 6189 stdout = stdout, 6190 stderr = subprocess.STDOUT, 6191 cwd=event_dir) 6192 # Wait 5 s to make sure file is finished writing 6193 time.sleep(5) 6194 except OSError as error: 6195 logger.error('fail to run syscalc: %s. Please check that SysCalc is correctly installed.' % error) 6196 else: 6197 if not os.path.exists(output): 6198 logger.warning('SysCalc Failed. Please read the associate log to see the reason. Did you install the associate PDF set?') 6199 elif mode == 'parton': 6200 files.mv(output, event_path) 6201 6202 self.update_status('End syscalc for %s level' % mode, level = mode.lower(), 6203 makehtml=False) 6204 6205 return True
6206 6207 6208 action_switcher = AskRun 6209 ############################################################################
6210 - def ask_run_configuration(self, mode=None, args=[]):
6211 """Ask the question when launching generate_events/multi_run""" 6212 6213 passing_cmd = [] 6214 if '-R' in args or '--reweight' in args: 6215 passing_cmd.append('reweight=ON') 6216 if '-M' in args or '--madspin' in args: 6217 passing_cmd.append('madspin=ON') 6218 6219 switch, cmd_switch = self.ask('', '0', [], ask_class = self.action_switcher, 6220 mode=mode, line_args=args, force=self.force, 6221 first_cmd=passing_cmd, return_instance=True) 6222 # 6223 self.switch = switch # store the value of the switch for plugin purpose 6224 if 'dynamical' in switch: 6225 mode = 'auto' 6226 6227 # Now that we know in which mode we are check that all the card 6228 #exists (copy default if needed) 6229 6230 cards = ['param_card.dat', 'run_card.dat'] 6231 if switch['shower'] == 'Pythia6': 6232 cards.append('pythia_card.dat') 6233 if switch['shower'] == 'Pythia8': 6234 cards.append('pythia8_card.dat') 6235 if switch['detector'] in ['PGS','DELPHES+PGS']: 6236 cards.append('pgs_card.dat') 6237 if switch['detector'] in ['Delphes', 'DELPHES+PGS']: 6238 cards.append('delphes_card.dat') 6239 delphes3 = True 6240 if os.path.exists(pjoin(self.options['delphes_path'], 'data')): 6241 delphes3 = False 6242 cards.append('delphes_trigger.dat') 6243 if switch['madspin'] != 'OFF': 6244 cards.append('madspin_card.dat') 6245 if switch['reweight'] != 'OFF': 6246 cards.append('reweight_card.dat') 6247 if switch['analysis'].upper() in ['MADANALYSIS5']: 6248 cards.append('madanalysis5_parton_card.dat') 6249 if switch['analysis'].upper() in ['MADANALYSIS5'] and not switch['shower']=='OFF': 6250 cards.append('madanalysis5_hadron_card.dat') 6251 if switch['analysis'].upper() in ['MADANALYSIS4']: 6252 cards.append('plot_card.dat') 6253 6254 self.keep_cards(cards) 6255 6256 first_cmd = cmd_switch.get_cardcmd() 6257 6258 if os.path.isfile(pjoin(self.me_dir,'Cards','MadLoopParams.dat')): 6259 cards.append('MadLoopParams.dat') 6260 6261 if self.force: 6262 self.check_param_card(pjoin(self.me_dir,'Cards','param_card.dat' )) 6263 return switch 6264 6265 6266 if 'dynamical' in switch and switch['dynamical']: 6267 self.ask_edit_cards(cards, plot=False, mode='auto', first_cmd=first_cmd) 6268 else: 6269 self.ask_edit_cards(cards, plot=False, first_cmd=first_cmd) 6270 return switch
6271 6272 ############################################################################
6273 - def ask_pythia_run_configuration(self, mode=None, pythia_version=6, banner=None):
6274 """Ask the question when launching pythia""" 6275 6276 pythia_suffix = '' if pythia_version==6 else '%d'%pythia_version 6277 6278 available_mode = ['0', '1'] 6279 if pythia_version==6: 6280 available_mode.append('2') 6281 if self.options['delphes_path']: 6282 available_mode.append('3') 6283 name = {'0': 'auto', '2':'pgs', '3':'delphes'} 6284 name['1'] = 'pythia%s'%pythia_suffix 6285 options = available_mode + [name[val] for val in available_mode] 6286 question = """Which programs do you want to run? 6287 0 / auto : running existing cards\n""" 6288 if pythia_version==6: 6289 question += """ 1. pythia : Pythia\n""" 6290 question += """ 2. pgs : Pythia + PGS\n""" 6291 else: 6292 question += """ 1. pythia8 : Pythia8\n""" 6293 6294 if '3' in available_mode: 6295 question += """ 3. delphes : Pythia%s + Delphes.\n"""%pythia_suffix 6296 6297 if not self.force: 6298 if not mode: 6299 mode = self.ask(question, '0', options) 6300 elif not mode: 6301 mode = 'auto' 6302 6303 if mode.isdigit(): 6304 mode = name[mode] 6305 6306 auto = False 6307 if mode == 'auto': 6308 auto = True 6309 if pythia_version==6 and os.path.exists(pjoin(self.me_dir, 6310 'Cards', 'pgs_card.dat')): 6311 mode = 'pgs' 6312 elif os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')): 6313 mode = 'delphes' 6314 else: 6315 mode = 'pythia%s'%pythia_suffix 6316 logger.info('Will run in mode %s' % mode) 6317 # Now that we know in which mode we are check that all the card 6318 #exists (copy default if needed) remove pointless one 6319 cards = ['pythia%s_card.dat'%pythia_suffix] 6320 if mode == 'pgs' and pythia_version==6: 6321 cards.append('pgs_card.dat') 6322 if mode == 'delphes': 6323 cards.append('delphes_card.dat') 6324 delphes3 = True 6325 if os.path.exists(pjoin(self.options['delphes_path'], 'data')): 6326 delphes3 = False 6327 cards.append('delphes_trigger.dat') 6328 self.keep_cards(cards, ignore=['madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat', 6329 'plot_card.dat']) 6330 6331 if self.force: 6332 return mode 6333 6334 if not banner: 6335 banner = self.banner 6336 6337 if auto: 6338 self.ask_edit_cards(cards, from_banner=['param', 'run'], 6339 mode='auto', plot=(pythia_version==6), banner=banner 6340 ) 6341 else: 6342 self.ask_edit_cards(cards, from_banner=['param', 'run'], 6343 plot=(pythia_version==6), banner=banner) 6344 6345 return mode
6346
6347 #=============================================================================== 6348 # MadEventCmd 6349 #=============================================================================== 6350 -class MadEventCmdShell(MadEventCmd, cmd.CmdShell):
6351 """The command line processor of MadGraph"""
6352
6353 6354 6355 #=============================================================================== 6356 # HELPING FUNCTION For Subprocesses 6357 #=============================================================================== 6358 -class SubProcesses(object):
6359 6360 name_to_pdg = {} 6361 6362 @classmethod
6363 - def clean(cls):
6364 cls.name_to_pdg = {}
6365 6366 @staticmethod
6367 - def get_subP(me_dir):
6368 """return the list of Subprocesses""" 6369 6370 out = [] 6371 for line in open(pjoin(me_dir,'SubProcesses', 'subproc.mg')): 6372 if not line: 6373 continue 6374 name = line.strip() 6375 if os.path.exists(pjoin(me_dir, 'SubProcesses', name)): 6376 out.append(pjoin(me_dir, 'SubProcesses', name)) 6377 6378 return out
6379 6380 6381 6382 @staticmethod
6383 - def get_subP_info(path):
6384 """ return the list of processes with their name""" 6385 6386 nb_sub = 0 6387 names = {} 6388 old_main = '' 6389 6390 if not os.path.exists(os.path.join(path,'processes.dat')): 6391 return SubProcesses.get_subP_info_v4(path) 6392 6393 for line in open(os.path.join(path,'processes.dat')): 6394 main = line[:8].strip() 6395 if main == 'mirror': 6396 main = old_main 6397 if line[8:].strip() == 'none': 6398 continue 6399 else: 6400 main = int(main) 6401 old_main = main 6402 6403 sub_proccess = line[8:] 6404 nb_sub += sub_proccess.count(',') + 1 6405 if main in names: 6406 names[main] += [sub_proccess.split(',')] 6407 else: 6408 names[main]= [sub_proccess.split(',')] 6409 6410 return names
6411 6412 @staticmethod
6413 - def get_subP_info_v4(path):
6414 """ return the list of processes with their name in case without grouping """ 6415 6416 nb_sub = 0 6417 names = {'':[[]]} 6418 path = os.path.join(path, 'auto_dsig.f') 6419 found = 0 6420 for line in open(path): 6421 if line.startswith('C Process:'): 6422 found += 1 6423 names[''][0].append(line[15:]) 6424 elif found >1: 6425 break 6426 return names
6427 6428 6429 @staticmethod
6430 - def get_subP_ids(path):
6431 """return the pdg codes of the particles present in the Subprocesses""" 6432 6433 all_ids = [] 6434 for line in open(pjoin(path, 'leshouche.inc')): 6435 if not 'IDUP' in line: 6436 continue 6437 particles = re.search("/([\d,-]+)/", line) 6438 all_ids.append([int(p) for p in particles.group(1).split(',')]) 6439 return all_ids
6440
6441 6442 #=============================================================================== 6443 -class GridPackCmd(MadEventCmd):
6444 """The command for the gridpack --Those are not suppose to be use interactively--""" 6445
6446 - def __init__(self, me_dir = None, nb_event=0, seed=0, gran=-1, *completekey, **stdin):
6447 """Initialize the command and directly run""" 6448 6449 # Initialize properly 6450 self.readonly = False 6451 MadEventCmd.__init__(self, me_dir, *completekey, **stdin) 6452 self.run_mode = 0 6453 self.random = seed 6454 self.random_orig = self.random 6455 self.granularity = gran 6456 6457 self.options['automatic_html_opening'] = False 6458 #write the grid_card.dat on disk 6459 self.nb_event = int(nb_event) 6460 self.write_gridcard(nb_event, seed, gran) # set readonly on True if needed 6461 self.prepare_local_dir() # move to gridpack dir or create local structure 6462 # Now it's time to run! 6463 if me_dir and nb_event and seed: 6464 self.launch(nb_event, seed) 6465 else: 6466 raise MadGraph5Error('Gridpack run failed: ' + str(me_dir) + str(nb_event) + \ 6467 str(seed))
6468 6469
6470 - def update_status(self, *args, **opts):
6471 return
6472
6473 - def load_results_db(self):
6474 """load the current results status""" 6475 model = self.find_model_name() 6476 process = self.process # define in find_model_name 6477 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir) 6478 self.last_mode=''
6479
6480 - def save_random(self):
6481 """save random number in appropirate file""" 6482 6483 if not self.readonly: 6484 fsock = open(pjoin(self.me_dir, 'SubProcesses','randinit'),'w') 6485 else: 6486 fsock = open('randinit','w') 6487 fsock.writelines('r=%s\n' % self.random)
6488
6489 - def write_RunWeb(self, me_dir):
6490 try: 6491 super(GridPackCmd, self).write_RunWeb(me_dir) 6492 except IOError: 6493 self.readonly =True
6494
6495 - def write_gridcard(self, nb_event, seed, gran):
6496 """write the grid_card.dat file at appropriate location""" 6497 6498 # first try to write grid_card within the gridpack. 6499 print("WRITE GRIDCARD", self.me_dir) 6500 if self.readonly: 6501 if not os.path.exists('Cards'): 6502 os.mkdir('Cards') 6503 fsock = open('grid_card.dat','w') 6504 else: 6505 fsock = open(pjoin(self.me_dir, 'Cards', 'grid_card.dat'),'w') 6506 6507 gridpackcard = banner_mod.GridpackCard() 6508 gridpackcard['GridRun'] = True 6509 gridpackcard['gevents'] = nb_event 6510 gridpackcard['gseed'] = seed 6511 gridpackcard['ngran'] = gran 6512 6513 gridpackcard.write(fsock)
6514 6515 ############################################################################
6516 - def get_Pdir(self):
6517 """get the list of Pdirectory if not yet saved.""" 6518 6519 if hasattr(self, "Pdirs"): 6520 if self.me_dir in self.Pdirs[0]: 6521 return self.Pdirs 6522 6523 if not self.readonly: 6524 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip()) 6525 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))] 6526 else: 6527 self.Pdirs = [l.strip() 6528 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))] 6529 6530 return self.Pdirs
6531
6532 - def prepare_local_dir(self):
6533 """create the P directory structure in the local directory""" 6534 6535 if not self.readonly: 6536 os.chdir(self.me_dir) 6537 else: 6538 for line in open(pjoin(self.me_dir,'SubProcesses','subproc.mg')): 6539 p = line.strip() 6540 os.mkdir(p) 6541 files.cp(pjoin(self.me_dir,'SubProcesses',p,'symfact.dat'), 6542 pjoin(p, 'symfact.dat'))
6543 6544
6545 - def launch(self, nb_event, seed):
6546 """ launch the generation for the grid """ 6547 6548 # 1) Restore the default data 6549 logger.info('generate %s events' % nb_event) 6550 self.set_run_name('GridRun_%s' % seed) 6551 if not self.readonly: 6552 self.update_status('restoring default data', level=None) 6553 misc.call([pjoin(self.me_dir,'bin','internal','restore_data'), 6554 'default'], cwd=self.me_dir) 6555 6556 if self.run_card['python_seed'] == -2: 6557 import random 6558 random.seed(seed) 6559 elif self.run_card['python_seed'] > 0: 6560 import random 6561 random.seed(self.run_card['python_seed']) 6562 # 2) Run the refine for the grid 6563 self.update_status('Generating Events', level=None) 6564 #misc.call([pjoin(self.me_dir,'bin','refine4grid'), 6565 # str(nb_event), '0', 'Madevent','1','GridRun_%s' % seed], 6566 # cwd=self.me_dir) 6567 self.refine4grid(nb_event) 6568 6569 # 3) Combine the events/pythia/... 6570 self.exec_cmd('combine_events') 6571 if not self.readonly: 6572 self.exec_cmd('store_events') 6573 self.print_results_in_shell(self.results.current) 6574 if self.run_card['systematics_program'] == 'systematics' and self.run_card['use_syst']: 6575 self.exec_cmd('systematics %s --from_card' % self.run_name, 6576 postcmd=False,printcmd=False) 6577 self.exec_cmd('decay_events -from_cards', postcmd=False) 6578 elif self.run_card['use_syst'] and self.run_card['systematics_program'] == 'systematics': 6579 self.options['nb_core'] = 1 6580 self.exec_cmd('systematics %s --from_card' % 6581 pjoin('Events', self.run_name, 'unweighted_events.lhe.gz'), 6582 postcmd=False,printcmd=False)
6583 6584
6585 - def refine4grid(self, nb_event):
6586 """Special refine for gridpack run.""" 6587 self.nb_refine += 1 6588 6589 precision = nb_event 6590 6591 self.opts = dict([(key,value[1]) for (key,value) in \ 6592 self._survey_options.items()]) 6593 6594 # initialize / remove lhapdf mode 6595 # self.configure_directory() # All this has been done before 6596 self.cluster_mode = 0 # force single machine 6597 6598 # Store seed in randinit file, to be read by ranmar.f 6599 self.save_random() 6600 6601 self.update_status('Refine results to %s' % precision, level=None) 6602 logger.info("Using random number seed offset = %s" % self.random) 6603 6604 refine_opt = {'err_goal': nb_event, 'split_channels': False, 6605 'ngran':self.granularity, 'readonly': self.readonly} 6606 x_improve = gen_ximprove.gen_ximprove_gridpack(self, refine_opt) 6607 x_improve.launch() # create the ajob for the refinment and run those! 6608 self.gscalefact = x_improve.gscalefact #store jacobian associate to the gridpack 6609 6610 6611 #bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses'))) 6612 #print 'run combine!!!' 6613 #combine_runs.CombineRuns(self.me_dir) 6614 6615 return 6616 #update html output 6617 Presults = sum_html.collect_result(self) 6618 cross, error = Presults.xsec, Presults.xerru 6619 self.results.add_detail('cross', cross) 6620 self.results.add_detail('error', error) 6621 6622 6623 #self.update_status('finish refine', 'parton', makehtml=False) 6624 #devnull.close() 6625 6626 6627 6628 return 6629 self.total_jobs = 0 6630 subproc = [P for P in os.listdir(pjoin(self.me_dir,'SubProcesses')) if 6631 P.startswith('P') and os.path.isdir(pjoin(self.me_dir,'SubProcesses', P))] 6632 devnull = open(os.devnull, 'w') 6633 for nb_proc,subdir in enumerate(subproc): 6634 subdir = subdir.strip() 6635 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir) 6636 bindir = pjoin(os.path.relpath(self.dirbin, Pdir)) 6637 6638 logger.info(' %s ' % subdir) 6639 # clean previous run 6640 for match in misc.glob('*ajob*', Pdir): 6641 if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']: 6642 os.remove(pjoin(Pdir, match)) 6643 6644 6645 logfile = pjoin(Pdir, 'gen_ximprove.log') 6646 misc.call([pjoin(bindir, 'gen_ximprove')], 6647 stdin=subprocess.PIPE, 6648 stdout=open(logfile,'w'), 6649 cwd=Pdir) 6650 6651 if os.path.exists(pjoin(Pdir, 'ajob1')): 6652 alljobs = misc.glob('ajob*', Pdir) 6653 nb_tot = len(alljobs) 6654 self.total_jobs += nb_tot 6655 for i, job in enumerate(alljobs): 6656 job = os.path.basename(job) 6657 self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1), 6658 run_type='Refine number %s on %s (%s/%s)' % 6659 (self.nb_refine, subdir, nb_proc+1, len(subproc))) 6660 if os.path.exists(pjoin(self.me_dir,'error')): 6661 self.monitor(html=True) 6662 raise MadEventError('Error detected in dir %s: %s' % \ 6663 (Pdir, open(pjoin(self.me_dir,'error')).read())) 6664 self.monitor(run_type='All job submitted for refine number %s' % 6665 self.nb_refine) 6666 6667 self.update_status("Combining runs", level='parton') 6668 try: 6669 os.remove(pjoin(Pdir, 'combine_runs.log')) 6670 except Exception: 6671 pass 6672 6673 bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses'))) 6674 combine_runs.CombineRuns(self.me_dir) 6675 6676 #update html output 6677 cross, error = self.make_make_all_html_results() 6678 self.results.add_detail('cross', cross) 6679 self.results.add_detail('error', error) 6680 6681 6682 self.update_status('finish refine', 'parton', makehtml=False) 6683 devnull.close()
6684
6685 - def do_combine_events(self, line):
6686 """Advanced commands: Launch combine events""" 6687 6688 if self.readonly: 6689 outdir = 'Events' 6690 if not os.path.exists(outdir): 6691 os.mkdir(outdir) 6692 else: 6693 outdir = pjoin(self.me_dir, 'Events') 6694 args = self.split_arg(line) 6695 # Check argument's validity 6696 self.check_combine_events(args) 6697 gscalefact = self.gscalefact # {(C.get('name')): jac} 6698 # Define The Banner 6699 tag = self.run_card['run_tag'] 6700 # Update the banner with the pythia card 6701 if not self.banner: 6702 self.banner = banner_mod.recover_banner(self.results, 'parton') 6703 self.banner.load_basic(self.me_dir) 6704 # Add cross-section/event information 6705 self.banner.add_generation_info(self.results.current['cross'], self.run_card['nevents']) 6706 if not hasattr(self, 'random_orig'): self.random_orig = 0 6707 self.banner.change_seed(self.random_orig) 6708 6709 6710 if not os.path.exists(pjoin(outdir, self.run_name)): 6711 os.mkdir(pjoin(outdir, self.run_name)) 6712 self.banner.write(pjoin(outdir, self.run_name, 6713 '%s_%s_banner.txt' % (self.run_name, tag))) 6714 6715 get_wgt = lambda event: event.wgt 6716 AllEvent = lhe_parser.MultiEventFile() 6717 AllEvent.banner = self.banner 6718 6719 partials = 0 # if too many file make some partial unweighting 6720 sum_xsec, sum_xerru, sum_axsec = 0,[],0 6721 Gdirs = self.get_Gdir() 6722 Gdirs.sort() 6723 for Gdir in Gdirs: 6724 #mfactor already taken into accoun in auto_dsig.f 6725 if os.path.exists(pjoin(Gdir, 'events.lhe')): 6726 result = sum_html.OneResult('') 6727 result.read_results(pjoin(Gdir, 'results.dat')) 6728 AllEvent.add(pjoin(Gdir, 'events.lhe'), 6729 result.get('xsec')*gscalefact[Gdir], 6730 result.get('xerru')*gscalefact[Gdir], 6731 result.get('axsec')*gscalefact[Gdir] 6732 ) 6733 6734 sum_xsec += result.get('xsec')*gscalefact[Gdir] 6735 sum_xerru.append(result.get('xerru')*gscalefact[Gdir]) 6736 sum_axsec += result.get('axsec')*gscalefact[Gdir] 6737 6738 if len(AllEvent) >= 80: #perform a partial unweighting 6739 AllEvent.unweight(pjoin(outdir, self.run_name, "partials%s.lhe.gz" % partials), 6740 get_wgt, log_level=5, trunc_error=1e-2, event_target=self.nb_event) 6741 AllEvent = lhe_parser.MultiEventFile() 6742 AllEvent.banner = self.banner 6743 AllEvent.add(pjoin(outdir, self.run_name, "partials%s.lhe.gz" % partials), 6744 sum_xsec, 6745 math.sqrt(sum(x**2 for x in sum_xerru)), 6746 sum_axsec) 6747 partials +=1 6748 6749 if not hasattr(self,'proc_characteristic'): 6750 self.proc_characteristic = self.get_characteristics() 6751 6752 self.banner.add_generation_info(sum_xsec, self.nb_event) 6753 nb_event = AllEvent.unweight(pjoin(outdir, self.run_name, "unweighted_events.lhe.gz"), 6754 get_wgt, trunc_error=1e-2, event_target=self.nb_event, 6755 log_level=logging.DEBUG, normalization=self.run_card['event_norm'], 6756 proc_charac=self.proc_characteristic) 6757 6758 6759 if partials: 6760 for i in range(partials): 6761 try: 6762 os.remove(pjoin(outdir, self.run_name, "partials%s.lhe.gz" % i)) 6763 except Exception: 6764 os.remove(pjoin(outdir, self.run_name, "partials%s.lhe" % i)) 6765 6766 self.results.add_detail('nb_event', nb_event) 6767 self.banner.add_generation_info(sum_xsec, nb_event) 6768 if self.run_card['bias_module'].lower() not in ['dummy', 'none']: 6769 self.correct_bias()
6770
6771 6772 -class MadLoopInitializer(object):
6773 """ A container class for the various methods for initializing MadLoop. It is 6774 placed in MadEventInterface because it is used by Madevent for loop-induced 6775 simulations. """ 6776 6777 @staticmethod
6778 - def make_and_run(dir_name,checkRam=False):
6779 """ Compile the check program in the directory dir_name. 6780 Return the compilation and running time. """ 6781 6782 # Make sure to recreate the executable and modified source 6783 # (The time stamps are sometimes not actualized if it is too fast) 6784 if os.path.isfile(pjoin(dir_name,'check')): 6785 os.remove(pjoin(dir_name,'check')) 6786 os.remove(pjoin(dir_name,'check_sa.o')) 6787 os.remove(pjoin(dir_name,'loop_matrix.o')) 6788 # Now run make 6789 devnull = open(os.devnull, 'w') 6790 start=time.time() 6791 retcode = misc.compile(arg=['-j1','check'], cwd=dir_name, nb_core=1) 6792 compilation_time = time.time()-start 6793 if retcode != 0: 6794 logging.info("Error while executing make in %s" % dir_name) 6795 return None, None, None 6796 6797 if not checkRam: 6798 start=time.time() 6799 retcode = subprocess.call('./check', 6800 cwd=dir_name, stdout=devnull, stderr=devnull) 6801 6802 run_time = time.time()-start 6803 ram_usage = None 6804 else: 6805 ptimer = misc.ProcessTimer(['./check'], cwd=dir_name, shell=False, \ 6806 stdout=devnull, stderr=devnull, close_fds=True) 6807 try: 6808 ptimer.execute() 6809 #poll as often as possible; otherwise the subprocess might 6810 # "sneak" in some extra memory usage while you aren't looking 6811 # Accuracy of .2 seconds is enough for the timing. 6812 while ptimer.poll(): 6813 time.sleep(.2) 6814 finally: 6815 #make sure that we don't leave the process dangling. 6816 ptimer.close() 6817 # Notice that ptimer.max_vms_memory is also available if needed. 6818 ram_usage = ptimer.max_rss_memory 6819 # Unfortunately the running time is less precise than with the 6820 # above version 6821 run_time = (ptimer.t1 - ptimer.t0) 6822 retcode = ptimer.p.returncode 6823 6824 devnull.close() 6825 6826 if retcode != 0: 6827 logging.warning("Error while executing ./check in %s" % dir_name) 6828 return None, None, None 6829 6830 return compilation_time, run_time, ram_usage
6831 6832 @staticmethod
6833 - def fix_PSPoint_in_check(dir_path, read_ps = True, npoints = 1, 6834 hel_config = -1, mu_r=0.0, split_orders=-1):
6835 """Set check_sa.f to be reading PS.input assuming a working dir dir_name. 6836 if hel_config is different than -1 then check_sa.f is configured so to 6837 evaluate only the specified helicity. 6838 If mu_r > 0.0, then the renormalization constant value will be hardcoded 6839 directly in check_sa.f, if is is 0 it will be set to Sqrt(s) and if it 6840 is < 0.0 the value in the param_card.dat is used. 6841 If the split_orders target (i.e. the target squared coupling orders for 6842 the computation) is != -1, it will be changed in check_sa.f via the 6843 subroutine CALL SET_COUPLINGORDERS_TARGET(split_orders).""" 6844 6845 file_path = dir_path 6846 if not os.path.isfile(dir_path) or \ 6847 not os.path.basename(dir_path)=='check_sa.f': 6848 file_path = pjoin(dir_path,'check_sa.f') 6849 if not os.path.isfile(file_path): 6850 directories = [d for d in misc.glob('P*_*', dir_path) \ 6851 if (re.search(r'.*P\d+_\w*$', d) and os.path.isdir(d))] 6852 if len(directories)>0: 6853 file_path = pjoin(directories[0],'check_sa.f') 6854 if not os.path.isfile(file_path): 6855 raise MadGraph5Error('Could not find the location of check_sa.f'+\ 6856 ' from the specified path %s.'%str(file_path)) 6857 6858 file = open(file_path, 'r') 6859 check_sa = file.read() 6860 file.close() 6861 6862 file = open(file_path, 'w') 6863 check_sa = re.sub(r"READPS = \S+\)","READPS = %s)"%('.TRUE.' if read_ps \ 6864 else '.FALSE.'), check_sa) 6865 check_sa = re.sub(r"NPSPOINTS = \d+","NPSPOINTS = %d"%npoints, check_sa) 6866 if hel_config != -1: 6867 check_sa = re.sub(r"SLOOPMATRIX\S+\(\S+,MATELEM,", 6868 "SLOOPMATRIXHEL_THRES(P,%d,MATELEM,"%hel_config, check_sa) 6869 else: 6870 check_sa = re.sub(r"SLOOPMATRIX\S+\(\S+,MATELEM,", 6871 "SLOOPMATRIX_THRES(P,MATELEM,",check_sa) 6872 if mu_r > 0.0: 6873 check_sa = re.sub(r"MU_R=SQRTS","MU_R=%s"%\ 6874 (("%.17e"%mu_r).replace('e','d')),check_sa) 6875 elif mu_r < 0.0: 6876 check_sa = re.sub(r"MU_R=SQRTS","",check_sa) 6877 6878 if split_orders > 0: 6879 check_sa = re.sub(r"SET_COUPLINGORDERS_TARGET\(-?\d+\)", 6880 "SET_COUPLINGORDERS_TARGET(%d)"%split_orders,check_sa) 6881 6882 file.write(check_sa) 6883 file.close()
6884 6885 @staticmethod
6886 - def run_initialization(run_dir=None, SubProc_dir=None, infos=None,\ 6887 req_files = ['HelFilter.dat','LoopFilter.dat'], 6888 attempts = [4,15]):
6889 """ Run the initialization of the process in 'run_dir' with success 6890 characterized by the creation of the files req_files in this directory. 6891 The directory containing the driving source code 'check_sa.f'. 6892 The list attempt gives the successive number of PS points the 6893 initialization should be tried with before calling it failed. 6894 Returns the number of PS points which were necessary for the init. 6895 Notice at least run_dir or SubProc_dir must be provided. 6896 A negative attempt number given in input means that quadprec will be 6897 forced for initialization.""" 6898 6899 # If the user does not want detailed info, then set the dictionary 6900 # to a dummy one. 6901 if infos is None: 6902 infos={} 6903 6904 if SubProc_dir is None and run_dir is None: 6905 raise MadGraph5Error('At least one of [SubProc_dir,run_dir] must'+\ 6906 ' be provided in run_initialization.') 6907 6908 # If the user does not specify where is check_sa.f, then it is assumed 6909 # to be one levels above run_dir 6910 if SubProc_dir is None: 6911 SubProc_dir = os.path.abspath(pjoin(run_dir,os.pardir)) 6912 6913 if run_dir is None: 6914 directories =[ dir for dir in misc.glob('P[0-9]*', SubProc_dir) 6915 if os.path.isdir(dir) ] 6916 if directories: 6917 run_dir = directories[0] 6918 else: 6919 raise MadGraph5Error('Could not find a valid running directory'+\ 6920 ' in %s.'%str(SubProc_dir)) 6921 6922 # Use the presence of the file born_matrix.f to decide if it is a 6923 # loop-induced process or not. It's not crucial, but just that because 6924 # of the dynamic adjustment of the ref scale used for deciding what are 6925 # the zero contributions, more points are neeeded for loop-induced. 6926 if not os.path.isfile(pjoin(run_dir,'born_matrix.f')): 6927 if len(attempts)>=1 and attempts[0]<8: 6928 attempts[0]=8 6929 if len(attempts)>=2 and attempts[1]<25: 6930 attempts[1]=25 6931 6932 to_attempt = list(attempts) 6933 to_attempt.reverse() 6934 my_req_files = list(req_files) 6935 6936 MLCardPath = pjoin(SubProc_dir,'MadLoopParams.dat') 6937 if not os.path.isfile(MLCardPath): 6938 raise MadGraph5Error('Could not find MadLoopParams.dat at %s.'\ 6939 %MLCardPath) 6940 else: 6941 MLCard = banner_mod.MadLoopParam(MLCardPath) 6942 MLCard_orig = banner_mod.MadLoopParam(MLCard) 6943 6944 # Make sure that LoopFilter really is needed. 6945 if not MLCard['UseLoopFilter']: 6946 try: 6947 my_req_files.remove('LoopFilter.dat') 6948 except ValueError: 6949 pass 6950 6951 if MLCard['HelicityFilterLevel']==0: 6952 try: 6953 my_req_files.remove('HelFilter.dat') 6954 except ValueError: 6955 pass 6956 6957 def need_init(): 6958 """ True if init not done yet.""" 6959 proc_prefix_file = open(pjoin(run_dir,'proc_prefix.txt'),'r') 6960 proc_prefix = proc_prefix_file.read() 6961 proc_prefix_file.close() 6962 return any([not os.path.exists(pjoin(run_dir,'MadLoop5_resources', 6963 proc_prefix+fname)) for fname in my_req_files]) or \ 6964 not os.path.isfile(pjoin(run_dir,'check')) or \ 6965 not os.access(pjoin(run_dir,'check'), os.X_OK)
6966 6967 # Check if this is a process without born by checking the presence of the 6968 # file born_matrix.f 6969 is_loop_induced = os.path.exists(pjoin(run_dir,'born_matrix.f')) 6970 6971 # For loop induced processes, always attempt quadruple precision if 6972 # double precision attempts fail and the user didn't specify himself 6973 # quadruple precision initializations attempts 6974 if not any(attempt<0 for attempt in to_attempt): 6975 to_attempt = [-attempt for attempt in to_attempt] + to_attempt 6976 use_quad_prec = 1 6977 curr_attempt = 1 6978 6979 MLCard.set('WriteOutFilters',True) 6980 6981 while to_attempt!=[] and need_init(): 6982 curr_attempt = to_attempt.pop() 6983 # if the attempt is a negative number it means we must force 6984 # quadruple precision at initialization time 6985 if curr_attempt < 0: 6986 use_quad_prec = -1 6987 # In quadruple precision we can lower the ZeroThres threshold 6988 MLCard.set('CTModeInit',4) 6989 MLCard.set('ZeroThres',1e-11) 6990 else: 6991 # Restore the default double precision intialization params 6992 MLCard.set('CTModeInit',1) 6993 MLCard.set('ZeroThres',1e-9) 6994 # Plus one because the filter are written on the next PS point after 6995 curr_attempt = abs(curr_attempt+1) 6996 MLCard.set('MaxAttempts',curr_attempt) 6997 MLCard.write(pjoin(SubProc_dir,'MadLoopParams.dat')) 6998 6999 # initialization is performed. 7000 MadLoopInitializer.fix_PSPoint_in_check(run_dir, read_ps = False, 7001 npoints = curr_attempt) 7002 compile_time, run_time, ram_usage = \ 7003 MadLoopInitializer.make_and_run(run_dir) 7004 if compile_time==None: 7005 logging.error("Failed at running the process in %s."%run_dir) 7006 attempts = None 7007 return None 7008 # Only set process_compilation time for the first compilation. 7009 if 'Process_compilation' not in list(infos.keys()) or \ 7010 infos['Process_compilation']==None: 7011 infos['Process_compilation'] = compile_time 7012 infos['Initialization'] = run_time 7013 7014 MLCard_orig.write(pjoin(SubProc_dir,'MadLoopParams.dat')) 7015 if need_init(): 7016 return None 7017 else: 7018 return use_quad_prec*(curr_attempt-1)
7019 7020 @staticmethod
7021 - def need_MadLoopInit(proc_dir, subproc_prefix='PV'):
7022 """Checks whether the necessary filters are present or not.""" 7023 7024 def need_init(ML_resources_path, proc_prefix, r_files): 7025 """ Returns true if not all required files are present. """ 7026 return any([not os.path.exists(pjoin(ML_resources_path, 7027 proc_prefix+fname)) for fname in r_files])
7028 7029 MLCardPath = pjoin(proc_dir,'SubProcesses','MadLoopParams.dat') 7030 if not os.path.isfile(MLCardPath): 7031 raise MadGraph5Error('Could not find MadLoopParams.dat at %s.'\ 7032 %MLCardPath) 7033 MLCard = banner_mod.MadLoopParam(MLCardPath) 7034 7035 req_files = ['HelFilter.dat','LoopFilter.dat'] 7036 # Make sure that LoopFilter really is needed. 7037 if not MLCard['UseLoopFilter']: 7038 try: 7039 req_files.remove('LoopFilter.dat') 7040 except ValueError: 7041 pass 7042 if MLCard['HelicityFilterLevel']==0: 7043 try: 7044 req_files.remove('HelFilter.dat') 7045 except ValueError: 7046 pass 7047 7048 for v_folder in glob.iglob(pjoin(proc_dir,'SubProcesses', 7049 '%s*'%subproc_prefix)): 7050 # Make sure it is a valid MadLoop directory 7051 if not os.path.isdir(v_folder) or not os.path.isfile(\ 7052 pjoin(v_folder,'loop_matrix.f')): 7053 continue 7054 proc_prefix_file = open(pjoin(v_folder,'proc_prefix.txt'),'r') 7055 proc_prefix = proc_prefix_file.read() 7056 proc_prefix_file.close() 7057 if need_init(pjoin(proc_dir,'SubProcesses','MadLoop5_resources'), 7058 proc_prefix, req_files): 7059 return True 7060 7061 return False 7062 7063 @staticmethod
7064 - def init_MadLoop(proc_dir, n_PS=None, subproc_prefix='PV', MG_options=None, 7065 interface = None):
7066 """Advanced commands: Compiles and run MadLoop on RAMBO random PS points to initilize the 7067 filters.""" 7068 7069 logger.debug('Compiling Source materials necessary for MadLoop '+ 7070 'initialization.') 7071 # Initialize all the virtuals directory, so as to generate the necessary 7072 # filters (essentially Helcity filter). 7073 # Make sure that the MadLoopCard has the loop induced settings 7074 if interface is None: 7075 misc.compile(arg=['treatCardsLoopNoInit'], cwd=pjoin(proc_dir,'Source')) 7076 else: 7077 interface.do_treatcards('all --no_MadLoopInit') 7078 7079 # First make sure that IREGI and CUTTOOLS are compiled if needed 7080 if os.path.exists(pjoin(proc_dir,'Source','CutTools')): 7081 misc.compile(arg=['libcuttools'],cwd=pjoin(proc_dir,'Source')) 7082 if os.path.exists(pjoin(proc_dir,'Source','IREGI')): 7083 misc.compile(arg=['libiregi'],cwd=pjoin(proc_dir,'Source')) 7084 # Then make sure DHELAS and MODEL are compiled 7085 misc.compile(arg=['libmodel'],cwd=pjoin(proc_dir,'Source')) 7086 misc.compile(arg=['libdhelas'],cwd=pjoin(proc_dir,'Source')) 7087 7088 # Now initialize the MadLoop outputs 7089 logger.info('Initializing MadLoop loop-induced matrix elements '+\ 7090 '(this can take some time)...') 7091 7092 # Setup parallelization 7093 if MG_options: 7094 mcore = cluster.MultiCore(**MG_options) 7095 else: 7096 mcore = cluster.onecore 7097 def run_initialization_wrapper(run_dir, infos, attempts): 7098 if attempts is None: 7099 n_PS = MadLoopInitializer.run_initialization( 7100 run_dir=run_dir, infos=infos) 7101 else: 7102 n_PS = MadLoopInitializer.run_initialization( 7103 run_dir=run_dir, infos=infos, attempts=attempts) 7104 infos['nPS'] = n_PS 7105 return 0
7106 7107 def wait_monitoring(Idle, Running, Done): 7108 if Idle+Running+Done == 0: 7109 return 7110 logger.debug('MadLoop initialization jobs: %d Idle, %d Running, %d Done'\ 7111 %(Idle, Running, Done)) 7112 7113 init_info = {} 7114 # List all virtual folders while making sure they are valid MadLoop folders 7115 VirtualFolders = [f for f in glob.iglob(pjoin(proc_dir,'SubProcesses', 7116 '%s*'%subproc_prefix)) if (os.path.isdir(f) or 7117 os.path.isfile(pjoin(f,'loop_matrix.f')))] 7118 logger.debug("Now Initializing MadLoop matrix element in %d folder%s:"%\ 7119 (len(VirtualFolders),'s' if len(VirtualFolders)>1 else '')) 7120 logger.debug(', '.join("'%s'"%os.path.basename(v_folder) for v_folder in 7121 VirtualFolders)) 7122 for v_folder in VirtualFolders: 7123 init_info[v_folder] = {} 7124 7125 # We try all multiples of n_PS from 1 to max_mult, first in DP and then 7126 # in QP before giving up, or use default values if n_PS is None. 7127 max_mult = 3 7128 if n_PS is None: 7129 # Then use the default list of number of PS points to try 7130 mcore.submit(run_initialization_wrapper, 7131 [pjoin(v_folder), init_info[v_folder], None]) 7132 else: 7133 # Use specific set of PS points 7134 mcore.submit(run_initialization_wrapper, [pjoin(v_folder), 7135 init_info[v_folder], 7136 [n_PS*multiplier for multiplier in range(1,max_mult+1)]]) 7137 7138 # Wait for all jobs to finish. 7139 mcore.wait('',wait_monitoring,update_first=wait_monitoring) 7140 for v_folder in VirtualFolders: 7141 init = init_info[v_folder] 7142 if init['nPS'] is None: 7143 raise MadGraph5Error('Failed the initialization of'+\ 7144 " loop-induced matrix element '%s'%s."%\ 7145 (os.path.basename(v_folder),' (using default n_PS points)' if\ 7146 n_PS is None else ' (trying with a maximum of %d PS points)'\ 7147 %(max_mult*n_PS))) 7148 if init['nPS']==0: 7149 logger.debug("Nothing to be done in '%s', all filters already "%\ 7150 os.path.basename(v_folder)+\ 7151 "present (use the '-r' option to force their recomputation)") 7152 else: 7153 logger.debug("'%s' finished using "%os.path.basename(v_folder)+ 7154 '%d PS points (%s), in %.3g(compil.) + %.3g(init.) secs.'%( 7155 abs(init['nPS']),'DP' if init['nPS']>0 else 'QP', 7156 init['Process_compilation'],init['Initialization'])) 7157 7158 logger.info('MadLoop initialization finished.') 7159 7160 AskforEditCard = common_run.AskforEditCard 7161 7162 7163 if '__main__' == __name__: 7164 # Launch the interface without any check if one code is already running. 7165 # This can ONLY run a single command !! 7166 import sys 7167 if not sys.version_info[0] in [2,3] or sys.version_info[1] < 6: 7168 sys.exit('MadGraph/MadEvent 5 works only with python 2.6, 2.7 or python 3.7 or later).\n'+\ 7169 'Please upgrate your version of python.') 7170 7171 import os 7172 import optparse 7173 # Get the directory of the script real path (bin) 7174 # and add it to the current PYTHONPATH 7175 root_path = os.path.dirname(os.path.dirname(os.path.realpath( __file__ ))) 7176 sys.path.insert(0, root_path)
7177 7178 - class MyOptParser(optparse.OptionParser):
7179 - class InvalidOption(Exception): pass
7180 - def error(self, msg=''):
7181 raise MyOptParser.InvalidOption(msg)
7182 # Write out nice usage message if called with -h or --help 7183 usage = "usage: %prog [options] [FILE] " 7184 parser = MyOptParser(usage=usage) 7185 parser.add_option("-l", "--logging", default='INFO', 7186 help="logging level (DEBUG|INFO|WARNING|ERROR|CRITICAL) [%default]") 7187 parser.add_option("","--web", action="store_true", default=False, dest='web', \ 7188 help='force toce to be in secure mode') 7189 parser.add_option("","--debug", action="store_true", default=False, dest='debug', \ 7190 help='force to launch debug mode') 7191 parser_error = '' 7192 done = False 7193 7194 for i in range(len(sys.argv)-1): 7195 try: 7196 (options, args) = parser.parse_args(sys.argv[1:len(sys.argv)-i]) 7197 done = True 7198 except MyOptParser.InvalidOption as error: 7199 pass 7200 else: 7201 args += sys.argv[len(sys.argv)-i:] 7202 if not done: 7203 # raise correct error: 7204 try: 7205 (options, args) = parser.parse_args() 7206 except MyOptParser.InvalidOption as error: 7207 print(error) 7208 sys.exit(2) 7209 7210 if len(args) == 0: 7211 args = '' 7212 7213 import subprocess 7214 import logging 7215 import logging.config 7216 # Set logging level according to the logging level given by options 7217 #logging.basicConfig(level=vars(logging)[options.logging]) 7218 import internal.coloring_logging 7219 try: 7220 if __debug__ and options.logging == 'INFO': 7221 options.logging = 'DEBUG' 7222 if options.logging.isdigit(): 7223 level = int(options.logging) 7224 else: 7225 level = eval('logging.' + options.logging) 7226 logging.config.fileConfig(os.path.join(root_path, 'internal', 'me5_logging.conf')) 7227 logging.root.setLevel(level) 7228 logging.getLogger('madgraph').setLevel(level) 7229 except: 7230 raise 7231 pass 7232 7233 # Call the cmd interface main loop 7234 try: 7235 if args: 7236 # a single command is provided 7237 if '--web' in args: 7238 i = args.index('--web') 7239 args.pop(i) 7240 cmd_line = MadEventCmd(os.path.dirname(root_path),force_run=True) 7241 else: 7242 cmd_line = MadEventCmdShell(os.path.dirname(root_path),force_run=True) 7243 if not hasattr(cmd_line, 'do_%s' % args[0]): 7244 if parser_error: 7245 print(parser_error) 7246 print('and %s can not be interpreted as a valid command.' % args[0]) 7247 else: 7248 print('ERROR: %s not a valid command. Please retry' % args[0]) 7249 else: 7250 cmd_line.use_rawinput = False 7251 cmd_line.run_cmd(' '.join(args)) 7252 cmd_line.run_cmd('quit') 7253 7254 except KeyboardInterrupt: 7255 print('quit on KeyboardInterrupt') 7256 pass 7257