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

Source Code for Module madgraph.interface.common_run_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   
  21   
  22  import ast 
  23  import logging 
  24  import math 
  25  import os 
  26  import re 
  27  import shutil 
  28  import signal 
  29  import stat 
  30  import subprocess 
  31  import sys 
  32  import time 
  33  import traceback 
  34  import urllib 
  35  import glob 
  36  import StringIO 
  37   
  38  try: 
  39      import readline 
  40      GNU_SPLITTING = ('GNU' in readline.__doc__) 
  41  except: 
  42      GNU_SPLITTING = True 
  43        
  44  root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 
  45  root_path = os.path.split(root_path)[0] 
  46  sys.path.insert(0, os.path.join(root_path,'bin')) 
  47   
  48  # usefull shortcut 
  49  pjoin = os.path.join 
  50  # Special logger for the Cmd Interface 
  51  logger = logging.getLogger('madgraph.stdout') # -> stdout 
  52  logger_stderr = logging.getLogger('madgraph.stderr') # ->stderr 
  53   
  54  try: 
  55      import madgraph 
  56  except ImportError: 
  57      # import from madevent directory 
  58      import internal.extended_cmd as cmd 
  59      import internal.banner as banner_mod 
  60      import internal.shower_card as shower_card_mod 
  61      import internal.misc as misc 
  62      import internal.cluster as cluster 
  63      import internal.check_param_card as param_card_mod 
  64      import internal.files as files 
  65  #    import internal.histograms as histograms # imported later to not slow down the loading of the code 
  66      import internal.save_load_object as save_load_object 
  67      import internal.gen_crossxhtml as gen_crossxhtml 
  68      import internal.lhe_parser as lhe_parser 
  69      import internal.FO_analyse_card as FO_analyse_card  
  70      import internal.sum_html as sum_html 
  71      from internal import InvalidCmd, MadGraph5Error 
  72       
  73      MADEVENT=True     
  74  else: 
  75      # import from madgraph directory 
  76      import madgraph.interface.extended_cmd as cmd 
  77      import madgraph.various.banner as banner_mod 
  78      import madgraph.various.shower_card as shower_card_mod 
  79      import madgraph.various.misc as misc 
  80      import madgraph.iolibs.files as files 
  81      import madgraph.various.cluster as cluster 
  82      import madgraph.various.lhe_parser as lhe_parser 
  83      import madgraph.various.FO_analyse_card as FO_analyse_card  
  84      import madgraph.iolibs.save_load_object as save_load_object 
  85      import madgraph.madevent.gen_crossxhtml as gen_crossxhtml 
  86      import models.check_param_card as param_card_mod 
  87      import madgraph.madevent.sum_html as sum_html 
  88  #    import madgraph.various.histograms as histograms # imported later to not slow down the loading of the code 
  89       
  90      from madgraph import InvalidCmd, MadGraph5Error, MG5DIR 
  91      MADEVENT=False 
92 93 #=============================================================================== 94 # HelpToCmd 95 #=============================================================================== 96 -class HelpToCmd(object):
97 """ The Series of help routins in common between amcatnlo_run and 98 madevent interface""" 99
100 - def help_treatcards(self):
101 logger.info("syntax: treatcards [param|run] [--output_dir=] [--param_card=] [--run_card=]") 102 logger.info("-- create the .inc files containing the cards information." )
103
104 - def help_set(self):
105 logger.info("syntax: set %s argument" % "|".join(self._set_options)) 106 logger.info("-- set options") 107 logger.info(" stdout_level DEBUG|INFO|WARNING|ERROR|CRITICAL") 108 logger.info(" change the default level for printed information") 109 logger.info(" timeout VALUE") 110 logger.info(" (default 20) Seconds allowed to answer questions.") 111 logger.info(" Note that pressing tab always stops the timer.") 112 logger.info(" cluster_temp_path PATH") 113 logger.info(" (default None) Allow to perform the run in PATH directory") 114 logger.info(" This allow to not run on the central disk. This is not used") 115 logger.info(" by condor cluster (since condor has it's own way to prevent it).")
116
117 - def help_plot(self):
118 logger.info("syntax: plot [RUN] [%s] [-f]" % '|'.join(self._plot_mode)) 119 logger.info("-- create the plot for the RUN (current run by default)") 120 logger.info(" at the different stage of the event generation") 121 logger.info(" Note than more than one mode can be specified in the same command.") 122 logger.info(" This requires to have MadAnalysis and td installed.") 123 logger.info(" -f options: answer all question by default.")
124
125 - def help_compute_widths(self):
126 logger.info("syntax: compute_widths Particle [Particles] [OPTIONS]") 127 logger.info("-- Compute the widths for the particles specified.") 128 logger.info(" By default, this takes the current param_card and overwrites it.") 129 logger.info(" Precision allows to define when to include three/four/... body decays (LO).") 130 logger.info(" If this number is an integer then all N-body decay will be included.") 131 logger.info(" Various options:\n") 132 logger.info(" --body_decay=X: Parameter to control the precision of the computation") 133 logger.info(" if X is an integer, we compute all channels up to X-body decay.") 134 logger.info(" if X <1, then we stop when the estimated error is lower than X.") 135 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer") 136 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.") 137 logger.info(" default: 4.0025") 138 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.") 139 logger.info(" default: precision (decimal part of the body_decay options) divided by four") 140 logger.info(" --precision_channel=X: requested numerical precision for each channel") 141 logger.info(" default: 0.01") 142 logger.info(" --path=X: path for param_card") 143 logger.info(" default: take value from the model") 144 logger.info(" --output=X: path where to write the resulting card. ") 145 logger.info(" default: overwrite input file. If no input file, write it in the model directory") 146 logger.info(" --nlo: Compute NLO width [if the model support it]")
147
148 - def help_shower(self):
149 logger.info("syntax: shower [shower_name] [shower_options]") 150 logger.info("-- This is equivalent to running '[shower_name] [shower_options]'")
151
152 - def help_pgs(self):
153 logger.info("syntax: pgs [RUN] [--run_options]") 154 logger.info("-- run pgs on RUN (current one by default)") 155 self.run_options_help([('-f','answer all question by default'), 156 ('--tag=', 'define the tag for the pgs run'), 157 ('--no_default', 'not run if pgs_card not present')])
158
159 - def help_delphes(self):
160 logger.info("syntax: delphes [RUN] [--run_options]") 161 logger.info("-- run delphes on RUN (current one by default)") 162 self.run_options_help([('-f','answer all question by default'), 163 ('--tag=', 'define the tag for the delphes run'), 164 ('--no_default', 'not run if delphes_card not present')])
165
166 - def help_decay_events(self, skip_syntax=False):
167 if not skip_syntax: 168 logger.info("syntax: decay_events [RUN]") 169 logger.info("This functionality allows for the decay of resonances") 170 logger.info("in a .lhe file, keeping track of the spin correlation effets.") 171 logger.info("BE AWARE OF THE CURRENT LIMITATIONS:") 172 logger.info(" (1) Only a succession of 2 body decay are currently allowed")
173
174 175 176 -class CheckValidForCmd(object):
177 """ The Series of check routines in common between amcatnlo_run and 178 madevent interface""" 179
180 - def check_set(self, args):
181 """ check the validity of the line""" 182 183 184 if len(args) < 2: 185 if len(args)==1 and "=" in args[0]: 186 args[:] = args[0].split("=",1) 187 else: 188 self.help_set() 189 raise self.InvalidCmd('set needs an option and an argument') 190 191 if args[0] not in self._set_options + self.options.keys(): 192 self.help_set() 193 raise self.InvalidCmd('Possible options for set are %s' % \ 194 (self._set_options+self.options.keys())) 195 196 if args[0] in ['stdout_level']: 197 if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] \ 198 and not args[1].isdigit(): 199 raise self.InvalidCmd('output_level needs ' + \ 200 'a valid level') 201 202 if args[0] in ['timeout']: 203 if not args[1].isdigit(): 204 raise self.InvalidCmd('timeout values should be a integer')
205
206 - def check_compute_widths(self, args):
207 """check that the model is loadable and check that the format is of the 208 type: PART PATH --output=PATH -f --precision=N 209 return the model. 210 """ 211 212 # Check that MG5 directory is present . 213 if MADEVENT and not self.options['mg5_path']: 214 raise self.InvalidCmd, '''The automatic computations of widths requires that MG5 is installed on the system. 215 You can install it and set his path in ./Cards/me5_configuration.txt''' 216 elif MADEVENT: 217 sys.path.append(self.options['mg5_path']) 218 try: 219 import models.model_reader as model_reader 220 import models.import_ufo as import_ufo 221 except ImportError: 222 raise self.ConfigurationError, '''Can\'t load MG5. 223 The variable mg5_path should not be correctly configure.''' 224 225 226 ufo_path = pjoin(self.me_dir,'bin','internal', 'ufomodel') 227 # Import model 228 if not MADEVENT: 229 modelname = self.find_model_name() 230 #restrict_file = None 231 #if os.path.exists(pjoin(ufo_path, 'restrict_default.dat')): 232 # restrict_file = pjoin(ufo_path, 'restrict_default.dat') 233 234 force_CMS = self.mother and self.mother.options['complex_mass_scheme'] 235 model = import_ufo.import_model(modelname, decay=True, 236 restrict=True, complex_mass_scheme=force_CMS) 237 else: 238 force_CMS = self.proc_characteristics['complex_mass_scheme'] 239 model = import_ufo.import_model(pjoin(self.me_dir,'bin','internal', 240 'ufomodel'), decay=True, complex_mass_scheme=force_CMS) 241 242 # if not hasattr(model.get('particles')[0], 'partial_widths'): 243 # raise self.InvalidCmd, 'The UFO model does not include partial widths information. Impossible to compute widths automatically' 244 245 # check if the name are passed to default MG5 246 if '-modelname' not in open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')).read(): 247 model.pass_particles_name_in_mg_default() 248 model = model_reader.ModelReader(model) 249 particles_name = dict([(p.get('name'), p.get('pdg_code')) 250 for p in model.get('particles')]) 251 particles_name.update(dict([(p.get('antiname'), p.get('pdg_code')) 252 for p in model.get('particles')])) 253 254 output = {'model': model, 'force': False, 'output': None, 255 'path':None, 'particles': set(), 'body_decay':4.0025, 256 'min_br':None, 'precision_channel':0.01} 257 for arg in args: 258 if arg.startswith('--output='): 259 output_path = arg.split('=',1)[1] 260 if not os.path.exists(output_path): 261 raise self.InvalidCmd, 'Invalid Path for the output. Please retry.' 262 if not os.path.isfile(output_path): 263 output_path = pjoin(output_path, 'param_card.dat') 264 output['output'] = output_path 265 elif arg == '-f': 266 output['force'] = True 267 elif os.path.isfile(arg): 268 ftype = self.detect_card_type(arg) 269 if ftype != 'param_card.dat': 270 raise self.InvalidCmd , '%s is not a valid param_card.' % arg 271 output['path'] = arg 272 elif arg.startswith('--path='): 273 arg = arg.split('=',1)[1] 274 ftype = self.detect_card_type(arg) 275 if ftype != 'param_card.dat': 276 raise self.InvalidCmd , '%s is not a valid param_card.' % arg 277 output['path'] = arg 278 elif arg.startswith('--'): 279 if "=" in arg: 280 name, value = arg.split('=',1) 281 try: 282 value = float(value) 283 except Exception: 284 raise self.InvalidCmd, '--%s requires integer or a float' % name 285 output[name[2:]] = float(value) 286 elif arg == "--nlo": 287 output["nlo"] = True 288 elif arg in particles_name: 289 # should be a particles 290 output['particles'].add(particles_name[arg]) 291 elif arg.isdigit() and int(arg) in particles_name.values(): 292 output['particles'].add(ast.literal_eval(arg)) 293 elif arg == 'all': 294 output['particles'] = set(['all']) 295 else: 296 self.help_compute_widths() 297 raise self.InvalidCmd, '%s is not a valid argument for compute_widths' % arg 298 if self.force: 299 output['force'] = True 300 301 if not output['particles']: 302 raise self.InvalidCmd, '''This routines requires at least one particle in order to compute 303 the related width''' 304 305 if output['output'] is None: 306 output['output'] = output['path'] 307 308 return output
309
310 - def check_delphes(self, arg, nodefault=False):
311 """Check the argument for pythia command 312 syntax: delphes [NAME] 313 Note that other option are already remove at this point 314 """ 315 316 # If not pythia-pgs path 317 if not self.options['delphes_path']: 318 logger.info('Retry to read configuration file to find delphes path') 319 self.set_configuration() 320 321 if not self.options['delphes_path']: 322 error_msg = 'No valid Delphes path set.\n' 323 error_msg += 'Please use the set command to define the path and retry.\n' 324 error_msg += 'You can also define it in the configuration file.\n' 325 raise self.InvalidCmd(error_msg) 326 327 tag = [a for a in arg if a.startswith('--tag=')] 328 if tag: 329 arg.remove(tag[0]) 330 tag = tag[0][6:] 331 332 333 if len(arg) == 0 and not self.run_name: 334 if self.results.lastrun: 335 arg.insert(0, self.results.lastrun) 336 else: 337 raise self.InvalidCmd('No run name currently define. Please add this information.') 338 339 if len(arg) == 1 and self.run_name == arg[0]: 340 arg.pop(0) 341 342 filepath = None 343 if not len(arg): 344 prev_tag = self.set_run_name(self.run_name, tag, 'delphes') 345 paths = [pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia_events.hep.gz'), 346 pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia8_events.hepmc.gz'), 347 pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia_events.hep'), 348 pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia8_events.hepmc'), 349 pjoin(self.me_dir,'Events','pythia_events.hep'), 350 pjoin(self.me_dir,'Events','pythia_events.hepmc'), 351 pjoin(self.me_dir,'Events','pythia8_events.hep.gz'), 352 pjoin(self.me_dir,'Events','pythia8_events.hepmc.gz') 353 ] 354 for p in paths: 355 if os.path.exists(p % {'tag': prev_tag}): 356 filepath = p % {'tag': prev_tag} 357 break 358 else: 359 a = raw_input("NO INPUT") 360 if nodefault: 361 return False 362 else: 363 self.help_pgs() 364 raise self.InvalidCmd('''No file file pythia_events.* currently available 365 Please specify a valid run_name''') 366 367 if len(arg) == 1: 368 prev_tag = self.set_run_name(arg[0], tag, 'delphes') 369 if os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)): 370 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag) 371 elif os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc.gz' % prev_tag)): 372 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc.gz' % prev_tag) 373 elif os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep' % prev_tag)): 374 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag) 375 elif os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc' % prev_tag)): 376 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc.gz' % prev_tag) 377 else: 378 raise self.InvalidCmd('No events file corresponding to %s run with tag %s.:%s '\ 379 % (self.run_name, prev_tag, 380 pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag))) 381 else: 382 if tag: 383 self.run_card['run_tag'] = tag 384 self.set_run_name(self.run_name, tag, 'delphes') 385 386 return filepath
387 388 389 390 391 392 393
394 - def check_open(self, args):
395 """ check the validity of the line """ 396 397 if len(args) != 1: 398 self.help_open() 399 raise self.InvalidCmd('OPEN command requires exactly one argument') 400 401 if args[0].startswith('./'): 402 if not os.path.isfile(args[0]): 403 raise self.InvalidCmd('%s: not such file' % args[0]) 404 return True 405 406 # if special : create the path. 407 if not self.me_dir: 408 if not os.path.isfile(args[0]): 409 self.help_open() 410 raise self.InvalidCmd('No MadEvent path defined. Unable to associate this name to a file') 411 else: 412 return True 413 414 path = self.me_dir 415 if os.path.isfile(os.path.join(path,args[0])): 416 args[0] = os.path.join(path,args[0]) 417 elif os.path.isfile(os.path.join(path,'Cards',args[0])): 418 args[0] = os.path.join(path,'Cards',args[0]) 419 elif os.path.isfile(os.path.join(path,'HTML',args[0])): 420 args[0] = os.path.join(path,'HTML',args[0]) 421 # special for card with _default define: copy the default and open it 422 elif '_card.dat' in args[0]: 423 name = args[0].replace('_card.dat','_card_default.dat') 424 if os.path.isfile(os.path.join(path,'Cards', name)): 425 files.cp(os.path.join(path,'Cards', name), os.path.join(path,'Cards', args[0])) 426 args[0] = os.path.join(path,'Cards', args[0]) 427 else: 428 raise self.InvalidCmd('No default path for this file') 429 elif not os.path.isfile(args[0]): 430 raise self.InvalidCmd('No default path for this file')
431
432 - def check_treatcards(self, args):
433 """check that treatcards arguments are valid 434 [param|run|all] [--output_dir=] [--param_card=] [--run_card=] 435 """ 436 437 opt = {'output_dir':pjoin(self.me_dir,'Source'), 438 'param_card':pjoin(self.me_dir,'Cards','param_card.dat'), 439 'run_card':pjoin(self.me_dir,'Cards','run_card.dat')} 440 mode = 'all' 441 for arg in args: 442 if arg.startswith('--') and '=' in arg: 443 key,value =arg[2:].split('=',1) 444 if not key in opt: 445 self.help_treatcards() 446 raise self.InvalidCmd('Invalid option for treatcards command:%s ' \ 447 % key) 448 if key in ['param_card', 'run_card']: 449 if os.path.isfile(value): 450 card_name = self.detect_card_type(value) 451 if card_name != key: 452 raise self.InvalidCmd('Format for input file detected as %s while expecting %s' 453 % (card_name, key)) 454 opt[key] = value 455 elif os.path.isfile(pjoin(self.me_dir,value)): 456 card_name = self.detect_card_type(pjoin(self.me_dir,value)) 457 if card_name != key: 458 raise self.InvalidCmd('Format for input file detected as %s while expecting %s' 459 % (card_name, key)) 460 opt[key] = value 461 else: 462 raise self.InvalidCmd('No such file: %s ' % value) 463 elif key in ['output_dir']: 464 if os.path.isdir(value): 465 opt[key] = value 466 elif os.path.isdir(pjoin(self.me_dir,value)): 467 opt[key] = pjoin(self.me_dir, value) 468 else: 469 raise self.InvalidCmd('No such directory: %s' % value) 470 elif arg in ['MadLoop','param','run','all']: 471 mode = arg 472 else: 473 self.help_treatcards() 474 raise self.InvalidCmd('Unvalid argument %s' % arg) 475 476 return mode, opt
477
478 - def check_decay_events(self,args):
479 """Check the argument for decay_events command 480 syntax is "decay_events [NAME]" 481 Note that other option are already remove at this point 482 """ 483 484 opts = [] 485 if '-from_cards' in args: 486 args.remove('-from_cards') 487 opts.append('-from_cards') 488 489 if any(t.startswith('--plugin=') for t in args): 490 plugin = [t for t in args if t.startswith('--plugin')][0] 491 args.remove(plugin) 492 opts.append(plugin) 493 494 495 if len(args) == 0: 496 if self.run_name: 497 args.insert(0, self.run_name) 498 elif self.results.lastrun: 499 args.insert(0, self.results.lastrun) 500 else: 501 raise self.InvalidCmd('No run name currently defined. Please add this information.') 502 return 503 504 if args[0] != self.run_name: 505 self.set_run_name(args[0]) 506 507 args[0] = self.get_events_path(args[0]) 508 509 args += opts
510 511
512 - def check_check_events(self,args):
513 """Check the argument for decay_events command 514 syntax is "decay_events [NAME]" 515 Note that other option are already remove at this point 516 """ 517 518 if len(args) == 0: 519 if self.run_name: 520 args.insert(0, self.run_name) 521 elif self.results.lastrun: 522 args.insert(0, self.results.lastrun) 523 else: 524 raise self.InvalidCmd('No run name currently defined. Please add this information.') 525 return 526 527 if args[0] and os.path.isfile(args[0]): 528 pass 529 else: 530 if args[0] != self.run_name: 531 self.set_run_name(args[0], allow_new_tag=False) 532 533 args[0] = self.get_events_path(args[0])
534 535
536 - def get_events_path(self, run_name):
537 """return the path to the output events 538 """ 539 540 if self.mode == 'madevent': 541 possible_path = [ 542 pjoin(self.me_dir,'Events', run_name, 'unweighted_events.lhe.gz'), 543 pjoin(self.me_dir,'Events', run_name, 'unweighted_events.lhe')] 544 else: 545 possible_path = [ 546 pjoin(self.me_dir,'Events', run_name, 'events.lhe.gz'), 547 pjoin(self.me_dir,'Events', run_name, 'events.lhe')] 548 549 for path in possible_path: 550 if os.path.exists(path): 551 correct_path = path 552 break 553 else: 554 if os.path.exists(run_name): 555 correct_path = run_name 556 else: 557 raise self.InvalidCmd('No events file corresponding to %s run. ' % run_name) 558 return correct_path
559
560 561 562 -class MadEventAlreadyRunning(InvalidCmd):
563 pass
564 -class AlreadyRunning(MadEventAlreadyRunning):
565 pass
566
567 -class ZeroResult(Exception): pass
568
569 #=============================================================================== 570 # CommonRunCmd 571 #=============================================================================== 572 -class CommonRunCmd(HelpToCmd, CheckValidForCmd, cmd.Cmd):
573 574 575 debug_output = 'ME5_debug' 576 helporder = ['Main Commands', 'Documented commands', 'Require MG5 directory', 577 'Advanced commands'] 578 sleep_for_error = True 579 580 # The three options categories are treated on a different footage when a 581 # set/save configuration occur. current value are kept in self.options 582 options_configuration = {'pythia8_path': './pythia8', 583 'hwpp_path': './herwigPP', 584 'thepeg_path': './thepeg', 585 'hepmc_path': './hepmc', 586 'madanalysis_path': './MadAnalysis', 587 'madanalysis5_path': './HEPTools/madanalysis5', 588 'pythia-pgs_path':'./pythia-pgs', 589 'td_path':'./td', 590 'delphes_path':'./Delphes', 591 'exrootanalysis_path':'./ExRootAnalysis', 592 'syscalc_path': './SysCalc', 593 'lhapdf': 'lhapdf-config', 594 'timeout': 60, 595 'f2py_compiler':None, 596 'web_browser':None, 597 'eps_viewer':None, 598 'text_editor':None, 599 'fortran_compiler':None, 600 'cpp_compiler': None, 601 'auto_update':7, 602 'cluster_type': 'condor', 603 'cluster_status_update': (600, 30), 604 'cluster_nb_retry':1, 605 'cluster_local_path': None, 606 'cluster_retry_wait':300} 607 608 options_madgraph= {'stdout_level':None} 609 610 options_madevent = {'automatic_html_opening':True, 611 'notification_center':True, 612 'run_mode':2, 613 'cluster_queue':None, 614 'cluster_time':None, 615 'cluster_size':100, 616 'cluster_memory':None, 617 'nb_core': None, 618 'cluster_temp_path':None} 619 620
621 - def __init__(self, me_dir, options, *args, **opts):
622 """common""" 623 624 self.force_run = False # this flag force the run even if RunWeb is present 625 self.stop_for_runweb = False # this flag indicates if we stop this run because of RunWeb. 626 if 'force_run' in opts and opts['force_run']: 627 self.force_run = True 628 del opts['force_run'] 629 630 cmd.Cmd.__init__(self, *args, **opts) 631 # Define current MadEvent directory 632 if me_dir is None and MADEVENT: 633 me_dir = root_path 634 635 if os.path.isabs(me_dir): 636 self.me_dir = me_dir 637 else: 638 self.me_dir = pjoin(os.getcwd(),me_dir) 639 640 self.options = options 641 642 self.param_card_iterator = [] #an placeholder containing a generator of paramcard for scanning 643 644 # usefull shortcut 645 self.status = pjoin(self.me_dir, 'status') 646 self.error = pjoin(self.me_dir, 'error') 647 self.dirbin = pjoin(self.me_dir, 'bin', 'internal') 648 649 # Check that the directory is not currently running_in_idle 650 if not self.force_run: 651 if os.path.exists(pjoin(me_dir,'RunWeb')): 652 message = '''Another instance of the program is currently running. 653 (for this exact same directory) Please wait that this is instance is 654 closed. If no instance is running, you can delete the file 655 %s and try again.''' % pjoin(me_dir,'RunWeb') 656 self.stop_for_runweb = True 657 raise AlreadyRunning, message 658 else: 659 self.write_RunWeb(me_dir) 660 661 self.to_store = [] 662 self.run_name = None 663 self.run_tag = None 664 self.banner = None 665 # Load the configuration file 666 self.set_configuration() 667 668 669 # Define self.proc_characteristics 670 self.get_characteristics() 671 672 if not self.proc_characteristics['ninitial']: 673 # Get number of initial states 674 nexternal = open(pjoin(self.me_dir,'Source','nexternal.inc')).read() 675 found = re.search("PARAMETER\s*\(NINCOMING=(\d)\)", nexternal) 676 self.ninitial = int(found.group(1)) 677 else: 678 self.ninitial = self.proc_characteristics['ninitial']
679
680 - def make_make_all_html_results(self, folder_names = [], jobs=[]):
681 return sum_html.make_all_html_results(self, folder_names, jobs)
682 683
684 - def write_RunWeb(self, me_dir):
685 self.writeRunWeb(me_dir) 686 self.gen_card_html()
687 688 @staticmethod
689 - def writeRunWeb(me_dir):
690 pid = os.getpid() 691 fsock = open(pjoin(me_dir,'RunWeb'),'w') 692 fsock.write(`pid`) 693 fsock.close()
694
695 - class RunWebHandling(object):
696
697 - def __init__(self, me_dir, crashifpresent=True, warnifpresent=True):
698 """raise error if RunWeb already exists 699 me_dir is the directory where the write RunWeb""" 700 701 self.remove_run_web = True 702 self.me_dir = me_dir 703 704 if crashifpresent or warnifpresent: 705 if os.path.exists(pjoin(me_dir, 'RunWeb')): 706 pid = open(pjoin(me_dir, 'RunWeb')).read() 707 try: 708 pid = int(pid) 709 except Exception: 710 pid = "unknown" 711 712 if pid == 'unknown' or misc.pid_exists(pid): 713 # bad situation 714 if crashifpresent: 715 if isinstance(crashifpresent, Exception): 716 raise crashifpresent 717 else: 718 message = '''Another instance of the program is currently running (pid = %s). 719 (for this exact same directory). Please wait that this is instance is 720 closed. If no instance is running, you can delete the file 721 %s and try again.''' % (pid, pjoin(me_dir, 'RunWeb')) 722 raise AlreadyRunning, message 723 elif warnifpresent: 724 if isinstance( warnifpresent, bool): 725 logger.warning("%s/RunWeb is present. Please check that only one run is running in that directory.") 726 else: 727 logger.log(warnifpresent, "%s/RunWeb is present. Please check that only one run is running in that directory.") 728 self.remove_run_web = False 729 else: 730 logger.debug('RunWeb exists but no associated process. Will Ignore it!') 731 return 732 733 # write RunWeb 734 735 CommonRunCmd.writeRunWeb(me_dir)
736
737 - def __enter__(self):
738 return
739
740 - def __exit__(self,exc_type, exc_value, traceback):
741 742 if self.remove_run_web: 743 try: 744 os.remove(pjoin(self.me_dir,'RunWeb')) 745 except Exception: 746 if os.path.exists(pjoin(self.me_dir,'RunWeb')): 747 logger.warning('fail to remove: %s' % pjoin(self.me_dir,'RunWeb')) 748 return
749
750 - def __call__(self, f):
751 """allow to use this as decorator as well""" 752 def wrapper(*args, **kw): 753 with self: 754 return f(*args, **kw)
755 return wrapper
756 757 758 759 760 761 ############################################################################
762 - def split_arg(self, line, error=False):
763 """split argument and remove run_options""" 764 765 args = cmd.Cmd.split_arg(line) 766 for arg in args[:]: 767 if not arg.startswith('-'): 768 continue 769 elif arg == '-c': 770 self.configure_run_mode(1) 771 elif arg == '-m': 772 self.configure_run_mode(2) 773 elif arg == '-f': 774 self.force = True 775 elif not arg.startswith('--'): 776 if error: 777 raise self.InvalidCmd('%s argument cannot start with - symbol' % arg) 778 else: 779 continue 780 elif arg.startswith('--cluster'): 781 self.configure_run_mode(1) 782 elif arg.startswith('--multicore'): 783 self.configure_run_mode(2) 784 elif arg.startswith('--nb_core'): 785 self.options['nb_core'] = int(arg.split('=',1)[1]) 786 self.configure_run_mode(2) 787 elif arg.startswith('--web'): 788 self.pass_in_web_mode() 789 self.configure_run_mode(1) 790 else: 791 continue 792 args.remove(arg) 793 794 return args
795 796 797 @misc.multiple_try(nb_try=5, sleep=2)
798 - def load_results_db(self):
799 """load the current results status""" 800 801 # load the current status of the directory 802 if os.path.exists(pjoin(self.me_dir,'HTML','results.pkl')): 803 try: 804 self.results = save_load_object.load_from_file(pjoin(self.me_dir,'HTML','results.pkl')) 805 except Exception: 806 #the pickle fail -> need to recreate the library 807 model = self.find_model_name() 808 process = self.process # define in find_model_name 809 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir) 810 self.results.resetall(self.me_dir) 811 else: 812 try: 813 self.results.resetall(self.me_dir) 814 except Exception, error: 815 logger.debug(error) 816 # Maybe the format was updated -> try fresh 817 model = self.find_model_name() 818 process = self.process # define in find_model_name 819 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir) 820 self.results.resetall(self.me_dir) 821 self.last_mode = '' 822 try: 823 self.last_mode = self.results[self.results.lastrun][-1]['run_mode'] 824 except: 825 self.results.resetall(self.me_dir) 826 self.last_mode = '' 827 828 else: 829 model = self.find_model_name() 830 process = self.process # define in find_model_name 831 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir) 832 self.results.resetall(self.me_dir) 833 self.last_mode='' 834 835 return self.results
836 837 ############################################################################
838 - def do_treatcards(self, line, amcatnlo=False):
839 """Advanced commands: create .inc files from param_card.dat/run_card.dat""" 840 841 842 #ensure that the cluster/card are consistent 843 if hasattr(self, 'run_card'): 844 self.cluster.modify_interface(self) 845 else: 846 try: 847 self.cluster.modify_interface(self) 848 except Exception, error: 849 misc.sprint(str(error)) 850 851 keepwidth = False 852 if '--keepwidth' in line: 853 keepwidth = True 854 line = line.replace('--keepwidth', '') 855 args = self.split_arg(line) 856 mode, opt = self.check_treatcards(args) 857 858 if mode in ['run', 'all']: 859 if not hasattr(self, 'run_card'): 860 run_card = banner_mod.RunCard(opt['run_card']) 861 else: 862 run_card = self.run_card 863 864 # add the conversion from the lhaid to the pdf set names 865 if amcatnlo and run_card['pdlabel']=='lhapdf': 866 pdfsetsdir=self.get_lhapdf_pdfsetsdir() 867 pdfsets=self.get_lhapdf_pdfsets_list(pdfsetsdir) 868 lhapdfsetname=[] 869 for lhaid in run_card['lhaid']: 870 if lhaid in pdfsets: 871 lhapdfsetname.append(pdfsets[lhaid]['filename']) 872 else: 873 raise MadGraph5Error("lhaid %s is not a valid PDF identification number. This can be due to the use of an outdated version of LHAPDF, or %s is not a LHAGlue number corresponding to a central PDF set (but rather one of the error sets)." % (lhaid,lhaid)) 874 run_card['lhapdfsetname']=lhapdfsetname 875 run_card.write_include_file(opt['output_dir']) 876 877 if mode in ['MadLoop', 'all']: 878 if os.path.exists(pjoin(self.me_dir, 'Cards', 'MadLoopParams.dat')): 879 self.MadLoopparam = banner_mod.MadLoopParam(pjoin(self.me_dir, 880 'Cards', 'MadLoopParams.dat')) 881 # write the output file 882 self.MadLoopparam.write(pjoin(self.me_dir,"SubProcesses", 883 "MadLoopParams.dat")) 884 885 if mode in ['param', 'all']: 886 if os.path.exists(pjoin(self.me_dir, 'Source', 'MODEL', 'mp_coupl.inc')): 887 param_card = param_card_mod.ParamCardMP(opt['param_card']) 888 else: 889 param_card = param_card_mod.ParamCard(opt['param_card']) 890 outfile = pjoin(opt['output_dir'], 'param_card.inc') 891 ident_card = pjoin(self.me_dir,'Cards','ident_card.dat') 892 if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')): 893 default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat') 894 elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')): 895 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat') 896 elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')): 897 fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w') 898 fsock.write(' ') 899 fsock.close() 900 return 901 else: 902 subprocess.call(['python', 'write_param_card.py'], 903 cwd=pjoin(self.me_dir,'bin','internal','ufomodel')) 904 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat') 905 906 907 if amcatnlo and not keepwidth: 908 # force particle in final states to have zero width 909 pids = self.get_pid_final_initial_states() 910 # check those which are charged under qcd 911 if not MADEVENT and pjoin(self.me_dir,'bin','internal') not in sys.path: 912 sys.path.insert(0,pjoin(self.me_dir,'bin','internal')) 913 914 #Ensure that the model that we are going to load is the current 915 #one. 916 to_del = [name for name in sys.modules.keys() 917 if name.startswith('internal.ufomodel') 918 or name.startswith('ufomodel')] 919 for name in to_del: 920 del(sys.modules[name]) 921 922 import ufomodel as ufomodel 923 zero = ufomodel.parameters.ZERO 924 no_width = [p for p in ufomodel.all_particles 925 if (str(p.pdg_code) in pids or str(-p.pdg_code) in pids) 926 and p.color != 1 and p.width != zero] 927 done = [] 928 for part in no_width: 929 if abs(part.pdg_code) in done: 930 continue 931 done.append(abs(part.pdg_code)) 932 param = param_card['decay'].get((part.pdg_code,)) 933 934 if param.value != 0: 935 logger.info('''For gauge cancellation, the width of \'%s\' has been set to zero.'''\ 936 % part.name,'$MG:BOLD') 937 param.value = 0 938 939 param_card.write_inc_file(outfile, ident_card, default)
940
941 - def get_model(self):
942 """return the model related to this process""" 943 944 if self.options['mg5_path']: 945 sys.path.append(self.options['mg5_path']) 946 import models.import_ufo as import_ufo 947 complexmass = self.proc_characteristics['complex_mass_scheme'] 948 with misc.MuteLogger(['madgraph.model'],[50]): 949 out= import_ufo.import_model(pjoin(self.me_dir,'bin','internal','ufomodel'), 950 complex_mass_scheme=complexmass) 951 return out 952 #elif self.mother: 953 # misc.sprint('Hum this is dangerous....') 954 # return self.mother._curr_model 955 else: 956 return None
957
958 - def ask_edit_cards(self, cards, mode='fixed', plot=True, first_cmd=None, from_banner=None, 959 banner=None):
960 """ """ 961 if not self.options['madanalysis_path']: 962 plot = False 963 964 self.ask_edit_card_static(cards, mode, plot, self.options['timeout'], 965 self.ask, first_cmd=first_cmd, from_banner=from_banner, 966 banner=banner) 967 968 for c in cards: 969 if not os.path.isabs(c): 970 c = pjoin(self.me_dir, c) 971 if not os.path.exists(c): 972 default = c.replace('dat', '_default.dat') 973 if os.path.exists(default): 974 files.cp(default, c)
975 976 977 978 @staticmethod
979 - def ask_edit_card_static(cards, mode='fixed', plot=True, 980 timeout=0, ask=None, **opt):
981 if not ask: 982 ask = CommonRunCmd.ask 983 984 def path2name(path): 985 if '_card' in path: 986 return path.split('_card')[0] 987 elif path == 'delphes_trigger.dat': 988 return 'trigger' 989 elif path == 'input.lhco': 990 return 'lhco' 991 elif path == 'MadLoopParams.dat': 992 return 'MadLoopParams' 993 else: 994 raise Exception, 'Unknow cards name %s' % path
995 996 # Ask the user if he wants to edit any of the files 997 #First create the asking text 998 question = """Do you want to edit a card (press enter to bypass editing)?\n""" 999 possible_answer = ['0', 'done'] 1000 card = {0:'done'} 1001 1002 indent = max(len(path2name(card_name)) for card_name in cards) 1003 question += '/'+'-'*60+'\\\n' 1004 for i, card_name in enumerate(cards): 1005 imode = path2name(card_name) 1006 possible_answer.append(i+1) 1007 possible_answer.append(imode) 1008 question += '| %-77s|\n'%((' \x1b[31m%%s\x1b[0m. %%-%ds : \x1b[32m%%s\x1b[0m'%indent)%(i+1, imode, card_name)) 1009 card[i+1] = imode 1010 1011 if plot and not 'plot_card.dat' in cards: 1012 question += '| %-77s|\n'%((' \x1b[31m9\x1b[0m. %%-%ds : \x1b[32mplot_card.dat\x1b[0m'%indent) % 'plot') 1013 possible_answer.append(9) 1014 possible_answer.append('plot') 1015 card[9] = 'plot' 1016 1017 question += '\\'+'-'*60+'/\n' 1018 1019 if 'param_card.dat' in cards: 1020 # Add the path options 1021 question += ' you can also\n' 1022 question += ' - enter the path to a valid card or banner.\n' 1023 question += ' - use the \'set\' command to modify a parameter directly.\n' 1024 question += ' The set option works only for param_card and run_card.\n' 1025 question += ' Type \'help set\' for more information on this command.\n' 1026 question += ' - call an external program (ASperGE/MadWidth/...).\n' 1027 question += ' Type \'help\' for the list of available command\n' 1028 else: 1029 question += ' you can also\n' 1030 question += ' - enter the path to a valid card.\n' 1031 if 'transfer_card.dat' in cards: 1032 question += ' - use the \'change_tf\' command to set a transfer functions.\n' 1033 1034 out = 'to_run' 1035 while out not in ['0', 'done']: 1036 out = ask(question, '0', possible_answer, timeout=int(1.5*timeout), 1037 path_msg='enter path', ask_class = AskforEditCard, 1038 cards=cards, mode=mode, **opt) 1039 1040 1041 @staticmethod
1042 - def detect_card_type(path):
1043 """detect the type of the card. Return value are 1044 banner 1045 param_card.dat 1046 run_card.dat 1047 pythia_card.dat 1048 pythia8_card.dat 1049 plot_card.dat 1050 pgs_card.dat 1051 delphes_card.dat 1052 delphes_trigger.dat 1053 shower_card.dat [aMCatNLO] 1054 FO_analyse_card.dat [aMCatNLO] 1055 madspin_card.dat [MS] 1056 transfer_card.dat [MW] 1057 madweight_card.dat [MW] 1058 madanalysis5_hadron_card.dat 1059 madanalysis5_parton_card.dat 1060 1061 Please update the unit-test: test_card_type_recognition when adding 1062 cards. 1063 """ 1064 1065 fulltext = open(path).read(50000) 1066 if fulltext == '': 1067 logger.warning('File %s is empty' % path) 1068 return 'unknown' 1069 1070 to_search = ['<MGVersion>', # banner 1071 '<mg5proccard>' 1072 'ParticlePropagator', # Delphes 1073 'ExecutionPath', 1074 'Treewriter', 1075 'CEN_max_tracker', 1076 '#TRIGGER CARD', # delphes_trigger.dat 1077 'parameter set name', # pgs_card 1078 'muon eta coverage', 1079 'req_acc_FO', 1080 'MSTP', 1081 'b_stable', 1082 'FO_ANALYSIS_FORMAT', 1083 'MSTU', 1084 'Begin Minpts', 1085 'gridpack', 1086 'ebeam1', 1087 'block\s+mw_run', 1088 'BLOCK', 1089 'DECAY', 1090 'launch', 1091 'madspin', 1092 'transfer_card\.dat', 1093 'set', 1094 'main:numberofevents', # pythia8, 1095 '@MG5aMC skip_analysis', #MA5 --both-- 1096 '@MG5aMC\s*inputs\s*=\s*\*\.(?:hepmc|lhe)', #MA5 --both-- 1097 '@MG5aMC\s*reconstruction_name', # MA5 hadronique 1098 '@MG5aMC' # MA5 hadronique 1099 ] 1100 1101 1102 text = re.findall('(%s)' % '|'.join(to_search), fulltext, re.I) 1103 text = [t.lower() for t in text] 1104 if '<mgversion>' in text or '<mg5proccard>' in text: 1105 return 'banner' 1106 elif 'particlepropagator' in text or 'executionpath' in text or 'treewriter' in text: 1107 return 'delphes_card.dat' 1108 elif 'cen_max_tracker' in text: 1109 return 'delphes_card.dat' 1110 elif '@mg5amc' in text: 1111 ma5_flag = [f[7:].strip() for f in text if f.startswith('@mg5amc')] 1112 if any(f.startswith('reconstruction_name') for f in ma5_flag): 1113 return 'madanalysis5_hadron_card.dat' 1114 ma5_flag = [f.split('*.')[1] for f in ma5_flag if '*.' in f] 1115 if any(f.startswith('lhe') for f in ma5_flag): 1116 return 'madanalysis5_parton_card.dat' 1117 if any(f.startswith(('hepmc','hep','stdhep','lhco')) for f in ma5_flag): 1118 return 'madanalysis5_hadron_card.dat' 1119 else: 1120 return 'unknown' 1121 elif '#trigger card' in text: 1122 return 'delphes_trigger.dat' 1123 elif 'parameter set name' in text: 1124 return 'pgs_card.dat' 1125 elif 'muon eta coverage' in text: 1126 return 'pgs_card.dat' 1127 elif 'mstp' in text and not 'b_stable' in text: 1128 return 'pythia_card.dat' 1129 elif 'begin minpts' in text: 1130 return 'plot_card.dat' 1131 elif ('gridpack' in text and 'ebeam1' in text) or \ 1132 ('req_acc_fo' in text and 'ebeam1' in text): 1133 return 'run_card.dat' 1134 elif any(t.endswith('mw_run') for t in text): 1135 return 'madweight_card.dat' 1136 elif 'transfer_card.dat' in text: 1137 return 'transfer_card.dat' 1138 elif 'block' in text and 'decay' in text: 1139 return 'param_card.dat' 1140 elif 'b_stable' in text: 1141 return 'shower_card.dat' 1142 elif 'fo_analysis_format' in text: 1143 return 'FO_analyse_card.dat' 1144 elif 'main:numberofevents' in text: 1145 return 'pythia8_card.dat' 1146 elif 'launch' in text: 1147 # need to separate madspin/reweight. 1148 # decay/set can be in both... 1149 if 'madspin' in text: 1150 return 'madspin_card.dat' 1151 if 'decay' in text: 1152 # need to check if this a line like "decay w+" or "set decay" 1153 if re.search("(^|;)\s*decay", fulltext): 1154 return 'madspin_card.dat' 1155 else: 1156 return 'reweight_card.dat' 1157 else: 1158 return 'reweight_card.dat' 1159 else: 1160 return 'unknown'
1161 1162 1163 ############################################################################
1164 - def get_available_tag(self):
1165 """create automatically a tag""" 1166 1167 used_tags = [r['tag'] for r in self.results[self.run_name]] 1168 i=0 1169 while 1: 1170 i+=1 1171 if 'tag_%s' %i not in used_tags: 1172 return 'tag_%s' % i
1173 1174 1175 ############################################################################ 1176 @misc.mute_logger(names=['madgraph.various.histograms', 1177 'internal.histograms'],levels=[20,20])
1178 - def generate_Pythia8_HwU_plots(self, plot_root_path, 1179 merging_scale_name, observable_name, 1180 data_path):
1181 """Generated the HwU plots from Pythia8 driver output for a specific 1182 observable.""" 1183 1184 try: 1185 import madgraph 1186 except ImportError: 1187 import internal.histograms as histograms 1188 else: 1189 import madgraph.various.histograms as histograms 1190 1191 # Make sure that the file is present 1192 if not os.path.isfile(data_path): 1193 return False 1194 1195 # Load the HwU file. 1196 histos = histograms.HwUList(data_path, consider_reweights='ALL',run_id=0) 1197 if len(histos)==0: 1198 return False 1199 1200 # Now also plot the max vs min merging scale 1201 merging_scales_available = [label[1] for label in \ 1202 histos[0].bins.weight_labels if 1203 histograms.HwU.get_HwU_wgt_label_type(label)=='merging_scale'] 1204 if len(merging_scales_available)>=2: 1205 min_merging_scale = min(merging_scales_available) 1206 max_merging_scale = max(merging_scales_available) 1207 else: 1208 min_merging_scale = None 1209 max_merging_scale = None 1210 1211 # jet_samples_to_keep = None means that all jet_samples are kept 1212 histo_output_options = { 1213 'format':'gnuplot', 1214 'uncertainties':['scale','pdf','statistical', 1215 'merging_scale','alpsfact'], 1216 'ratio_correlations':True, 1217 'arg_string':'Automatic plotting from MG5aMC', 1218 'jet_samples_to_keep':None, 1219 'use_band':['merging_scale','alpsfact'], 1220 'auto_open':False 1221 } 1222 # alpsfact variation only applies to MLM 1223 if not (int(self.run_card['ickkw'])==1): 1224 histo_output_options['uncertainties'].pop( 1225 histo_output_options['uncertainties'].index('alpsfact')) 1226 histo_output_options['use_band'].pop( 1227 histo_output_options['use_band'].index('alpsfact')) 1228 1229 histos.output(pjoin(plot_root_path, 1230 'central_%s_%s_plots'%(merging_scale_name,observable_name)), 1231 **histo_output_options) 1232 1233 for scale in merging_scales_available: 1234 that_scale_histos = histograms.HwUList( 1235 data_path, run_id=0, merging_scale=scale) 1236 that_scale_histos.output(pjoin(plot_root_path, 1237 '%s_%.3g_%s_plots'%(merging_scale_name,scale,observable_name)), 1238 **histo_output_options) 1239 1240 # If several merging scales were specified, then it is interesting 1241 # to compare the summed jet samples for the maximum and minimum 1242 # merging scale available. 1243 if not min_merging_scale is None: 1244 min_scale_histos = histograms.HwUList(data_path, 1245 consider_reweights=[], run_id=0, 1246 merging_scale=min_merging_scale) 1247 max_scale_histos = histograms.HwUList(data_path, 1248 consider_reweights=[], run_id=0, 1249 merging_scale=max_merging_scale) 1250 1251 # Give the histos types so that the plot labels look good 1252 for histo in min_scale_histos: 1253 if histo.type is None: 1254 histo.type = '%s=%.4g'%(merging_scale_name, min_merging_scale) 1255 else: 1256 histo.type += '|%s=%.4g'%(merging_scale_name, min_merging_scale) 1257 for histo in max_scale_histos: 1258 if histo.type is None: 1259 histo.type = '%s=%.4g'%(merging_scale_name, max_merging_scale) 1260 else: 1261 histo.type += '|%s=%.4g'%(merging_scale_name, max_merging_scale) 1262 1263 # Now plot and compare against oneanother the shape for the the two scales 1264 histograms.HwUList(min_scale_histos+max_scale_histos).output( 1265 pjoin(plot_root_path,'min_max_%s_%s_comparison' 1266 %(merging_scale_name,observable_name)), 1267 format='gnuplot', 1268 uncertainties=[], 1269 ratio_correlations=True, 1270 arg_string='Automatic plotting from MG5aMC', 1271 jet_samples_to_keep=None, 1272 use_band=[], 1273 auto_open=False) 1274 return True
1275
1276 - def gen_card_html(self):
1277 """ """ 1278 devnull = open(os.devnull, 'w') 1279 try: 1280 misc.call(['./bin/internal/gen_cardhtml-pl'], cwd=self.me_dir, 1281 stdout=devnull, stderr=devnull) 1282 except Exception: 1283 pass 1284 devnull.close()
1285 1286
1287 - def create_plot(self, mode='parton', event_path=None, output=None, tag=None):
1288 """create the plot""" 1289 1290 if not tag: 1291 tag = self.run_card['run_tag'] 1292 1293 if mode != 'Pythia8': 1294 madir = self.options['madanalysis_path'] 1295 td = self.options['td_path'] 1296 1297 if not madir or not td or \ 1298 not os.path.exists(pjoin(self.me_dir, 'Cards', 'plot_card.dat')): 1299 return False 1300 else: 1301 PY8_plots_root_path = pjoin(self.me_dir,'HTML', 1302 self.run_name,'%s_PY8_plots'%tag) 1303 1304 if 'ickkw' in self.run_card: 1305 if int(self.run_card['ickkw']) and mode == 'Pythia': 1306 self.update_status('Create matching plots for Pythia', level='pythia') 1307 # recover old data if none newly created 1308 if not os.path.exists(pjoin(self.me_dir,'Events','events.tree')): 1309 misc.gunzip(pjoin(self.me_dir,'Events', 1310 self.run_name, '%s_pythia_events.tree.gz' % tag), keep=True, 1311 stdout=pjoin(self.me_dir,'Events','events.tree')) 1312 files.mv(pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree'), 1313 pjoin(self.me_dir,'Events','xsecs.tree')) 1314 1315 # Generate the matching plots 1316 misc.call([self.dirbin+'/create_matching_plots.sh', 1317 self.run_name, tag, madir], 1318 stdout = os.open(os.devnull, os.O_RDWR), 1319 cwd=pjoin(self.me_dir,'Events')) 1320 1321 #Clean output 1322 misc.gzip(pjoin(self.me_dir,"Events","events.tree"), 1323 stdout=pjoin(self.me_dir,'Events',self.run_name, tag + '_pythia_events.tree.gz')) 1324 files.mv(pjoin(self.me_dir,'Events','xsecs.tree'), 1325 pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree')) 1326 1327 elif mode == 'Pythia8' and (int(self.run_card['ickkw'])==1 or \ 1328 self.run_card['ktdurham']>0.0 or self.run_card['ptlund']>0.0): 1329 1330 self.update_status('Create matching plots for Pythia8', 1331 level='pythia8') 1332 1333 # Create the directory if not existing at this stage 1334 if not os.path.isdir(PY8_plots_root_path): 1335 os.makedirs(PY8_plots_root_path) 1336 1337 merging_scale_name = 'qCut' if int(self.run_card['ickkw'])==1 \ 1338 else 'TMS' 1339 1340 djr_path = pjoin(self.me_dir,'Events', 1341 self.run_name, '%s_djrs.dat' % tag) 1342 pt_path = pjoin(self.me_dir,'Events', 1343 self.run_name, '%s_pts.dat' % tag) 1344 for observable_name, data_path in [('djr',djr_path), 1345 ('pt',pt_path)]: 1346 if not self.generate_Pythia8_HwU_plots( 1347 PY8_plots_root_path, merging_scale_name, 1348 observable_name,data_path): 1349 return False 1350 1351 if mode == 'Pythia8': 1352 plot_files = glob.glob(pjoin(PY8_plots_root_path,'*.gnuplot')) 1353 if not misc.which('gnuplot'): 1354 logger.warning("Install gnuplot to be able to view the plots"+\ 1355 " generated at :\n "+\ 1356 '\n '.join('%s.gnuplot'%p for p in plot_files)) 1357 return True 1358 for plot in plot_files: 1359 command = ['gnuplot',plot] 1360 try: 1361 subprocess.call(command,cwd=PY8_plots_root_path,stderr=subprocess.PIPE) 1362 except Exception as e: 1363 logger.warning("Automatic processing of the Pythia8 "+\ 1364 "merging plots with gnuplot failed. Try the"+\ 1365 " following command by hand:\n %s"%(' '.join(command))+\ 1366 "\nException was: %s"%str(e)) 1367 return False 1368 1369 plot_files = glob.glob(pjoin(PY8_plots_root_path,'*.pdf')) 1370 if len(plot_files)>0: 1371 # Add an html page 1372 html = "<html>\n<head>\n<TITLE>PLOT FOR PYTHIA8</TITLE>" 1373 html+= '<link rel=stylesheet href="../../mgstyle.css" type="text/css">\n</head>\n<body>\n' 1374 html += "<h2> Plot for Pythia8 </h2>\n" 1375 html += '<a href=../../../crossx.html>return to summary</a><br>' 1376 html += "<table>\n<tr> <td> <b>Obs.</b> </td> <td> <b>Type of plot</b> </td> <td><b> PDF</b> </td> <td><b> input file</b> </td> </tr>\n" 1377 def sorted_plots(elem): 1378 name = os.path.basename(elem[1]) 1379 if 'central' in name: 1380 return -100 1381 if 'min_max' in name: 1382 return -10 1383 merging_re = re.match(r'^.*_(\d+)_.*$',name) 1384 if not merging_re is None: 1385 return int(merging_re.group(1)) 1386 else: 1387 return 1e10
1388 djr_plot_files = sorted( 1389 (('DJR',p) for p in plot_files if '_djr_' in p), 1390 key = sorted_plots) 1391 pt_plot_files = sorted( 1392 (('Pt',p) for p in plot_files if '_pt_' in p), 1393 key = sorted_plots) 1394 last_obs = None 1395 for obs, one_plot in djr_plot_files+pt_plot_files: 1396 if obs!=last_obs: 1397 # Add a line between observables 1398 html += "<tr><td></td></tr>" 1399 last_obs = obs 1400 name = os.path.basename(one_plot).replace('.pdf','') 1401 short_name = name 1402 for dummy in ['_plots','_djr','_pt']: 1403 short_name = short_name.replace(dummy,'') 1404 short_name = short_name.replace('_',' ') 1405 if 'min max' in short_name: 1406 short_name = "%s comparison with min/max merging scale"%obs 1407 if 'central' in short_name: 1408 short_name = "Merging uncertainty band around central scale" 1409 html += "<tr><td>%(obs)s</td><td>%(sn)s</td><td> <a href=./%(n)s.pdf>PDF</a> </td><td> <a href=./%(n)s.HwU>HwU</a> <a href=./%(n)s.gnuplot>GNUPLOT</a> </td></tr>\n" %\ 1410 {'obs':obs, 'sn': short_name, 'n': name} 1411 html += '</table>\n' 1412 html += '<a href=../../../bin/internal/plot_djrs.py> Example of code to plot the above with matplotlib </a><br><br>' 1413 html+='</body>\n</html>' 1414 ff=open(pjoin(PY8_plots_root_path, 'index.html'),'w') 1415 ff.write(html) 1416 return True 1417 1418 if not event_path: 1419 if mode == 'parton': 1420 possibilities=[ 1421 pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), 1422 pjoin(self.me_dir, 'Events', 'unweighted_events.lhe.gz'), 1423 pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe'), 1424 pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')] 1425 for event_path in possibilities: 1426 if os.path.exists(event_path): 1427 break 1428 output = pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html') 1429 1430 elif mode == 'Pythia': 1431 event_path = pjoin(self.me_dir, 'Events','pythia_events.lhe') 1432 output = pjoin(self.me_dir, 'HTML',self.run_name, 1433 'plots_pythia_%s.html' % tag) 1434 elif mode == 'PGS': 1435 event_path = pjoin(self.me_dir, 'Events', self.run_name, 1436 '%s_pgs_events.lhco' % tag) 1437 output = pjoin(self.me_dir, 'HTML',self.run_name, 1438 'plots_pgs_%s.html' % tag) 1439 elif mode == 'Delphes': 1440 event_path = pjoin(self.me_dir, 'Events', self.run_name,'%s_delphes_events.lhco' % tag) 1441 output = pjoin(self.me_dir, 'HTML',self.run_name, 1442 'plots_delphes_%s.html' % tag) 1443 elif mode == "shower": 1444 event_path = pjoin(self.me_dir, 'Events','pythia_events.lhe') 1445 output = pjoin(self.me_dir, 'HTML',self.run_name, 1446 'plots_shower_%s.html' % tag) 1447 if not self.options['pythia-pgs_path']: 1448 return 1449 else: 1450 raise self.InvalidCmd, 'Invalid mode %s' % mode 1451 elif mode == 'reweight' and not output: 1452 output = pjoin(self.me_dir, 'HTML',self.run_name, 1453 'plots_%s.html' % tag) 1454 1455 if not os.path.exists(event_path): 1456 if os.path.exists(event_path+'.gz'): 1457 misc.gunzip('%s.gz' % event_path) 1458 else: 1459 raise self.InvalidCmd, 'Events file %s does not exist' % event_path 1460 elif event_path.endswith(".gz"): 1461 misc.gunzip(event_path) 1462 event_path = event_path[:-3] 1463 1464 1465 self.update_status('Creating Plots for %s level' % mode, level = mode.lower()) 1466 1467 mode = mode.lower() 1468 if mode not in ['parton', 'reweight']: 1469 plot_dir = pjoin(self.me_dir, 'HTML', self.run_name,'plots_%s_%s' % (mode.lower(),tag)) 1470 elif mode == 'parton': 1471 plot_dir = pjoin(self.me_dir, 'HTML', self.run_name,'plots_parton') 1472 else: 1473 plot_dir =pjoin(self.me_dir, 'HTML', self.run_name,'plots_%s' % (tag)) 1474 1475 if not os.path.isdir(plot_dir): 1476 os.makedirs(plot_dir) 1477 1478 files.ln(pjoin(self.me_dir, 'Cards','plot_card.dat'), plot_dir, 'ma_card.dat') 1479 1480 try: 1481 proc = misc.Popen([os.path.join(madir, 'plot_events')], 1482 stdout = open(pjoin(plot_dir, 'plot.log'),'w'), 1483 stderr = subprocess.STDOUT, 1484 stdin=subprocess.PIPE, 1485 cwd=plot_dir) 1486 proc.communicate('%s\n' % event_path) 1487 del proc 1488 #proc.wait() 1489 misc.call(['%s/plot' % self.dirbin, madir, td], 1490 stdout = open(pjoin(plot_dir, 'plot.log'),'a'), 1491 stderr = subprocess.STDOUT, 1492 cwd=plot_dir) 1493 1494 misc.call(['%s/plot_page-pl' % self.dirbin, 1495 os.path.basename(plot_dir), 1496 mode], 1497 stdout = open(pjoin(plot_dir, 'plot.log'),'a'), 1498 stderr = subprocess.STDOUT, 1499 cwd=pjoin(self.me_dir, 'HTML', self.run_name)) 1500 1501 shutil.move(pjoin(self.me_dir, 'HTML',self.run_name ,'plots.html'), 1502 output) 1503 1504 logger.info("Plots for %s level generated, see %s" % \ 1505 (mode, output)) 1506 except OSError, error: 1507 logger.error('fail to create plot: %s. Please check that MadAnalysis is correctly installed.' % error) 1508 1509 self.update_status('End Plots for %s level' % mode, level = mode.lower(), 1510 makehtml=False) 1511 1512 return True 1513
1514 - def run_hep2lhe(self, banner_path = None):
1515 """Run hep2lhe on the file Events/pythia_events.hep""" 1516 1517 if not self.options['pythia-pgs_path']: 1518 raise self.InvalidCmd, 'No pythia-pgs path defined' 1519 1520 pydir = pjoin(self.options['pythia-pgs_path'], 'src') 1521 eradir = self.options['exrootanalysis_path'] 1522 1523 # Creating LHE file 1524 if misc.is_executable(pjoin(pydir, 'hep2lhe')): 1525 self.update_status('Creating shower LHE File (for plot)', level='pythia') 1526 # Write the banner to the LHE file 1527 out = open(pjoin(self.me_dir,'Events','pythia_events.lhe'), 'w') 1528 #out.writelines('<LesHouchesEvents version=\"1.0\">\n') 1529 out.writelines('<!--\n') 1530 out.writelines('# Warning! Never use this file for detector studies!\n') 1531 out.writelines('-->\n<!--\n') 1532 if banner_path: 1533 out.writelines(open(banner_path).read().replace('<LesHouchesEvents version="1.0">','')) 1534 out.writelines('\n-->\n') 1535 out.close() 1536 1537 self.cluster.launch_and_wait(self.dirbin+'/run_hep2lhe', 1538 argument= [pydir], 1539 cwd=pjoin(self.me_dir,'Events'), 1540 stdout=os.devnull) 1541 1542 logger.info('Warning! Never use this lhe file for detector studies!') 1543 # Creating ROOT file 1544 if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHEFConverter')): 1545 self.update_status('Creating Pythia LHE Root File', level='pythia') 1546 try: 1547 misc.call([eradir+'/ExRootLHEFConverter', 1548 'pythia_events.lhe', 1549 pjoin(self.run_name, '%s_pythia_lhe_events.root' % self.run_tag)], 1550 cwd=pjoin(self.me_dir,'Events')) 1551 except Exception, error: 1552 misc.sprint('ExRootLHEFConverter fails', str(error), 1553 log=logger) 1554 pass
1555
1556 - def store_result(self):
1557 """Dummy routine, to be overwritten by daughter classes""" 1558 1559 pass
1560 1561 ############################################################################
1562 - def help_systematics(self):
1563 """help for systematics command""" 1564 logger.info("syntax: systematics RUN_NAME [OUTPUT] [options]",'$MG:BOLD') 1565 logger.info("-- Run the systematics run on the RUN_NAME run.") 1566 logger.info(" RUN_NAME can be a path to a lhef file.") 1567 logger.info(" OUTPUT can be the path to the output lhe file, otherwise the input file will be overwritten") 1568 logger.info("") 1569 logger.info("options: (values written are the default)", '$MG:BOLD') 1570 logger.info("") 1571 logger.info(" --mur=0.5,1,2 # specify the values for renormalisation scale variation") 1572 logger.info(" --muf=0.5,1,2 # specify the values for factorisation scale variation") 1573 logger.info(" --alps=1 # specify the values for MLM emission scale variation (LO only)") 1574 logger.info(" --dyn=-1,1,2,3,4 # specify the dynamical schemes to use.") 1575 logger.info(" # -1 is the one used by the sample.") 1576 logger.info(" # > 0 correspond to options of dynamical_scale_choice of the run_card.") 1577 logger.info(" --pdf=errorset # specify the pdfs to use for pdf variation. (see below)") 1578 logger.info(" --together=mur,muf,dyn # lists the parameter that must be varied simultaneously so as to ") 1579 logger.info(" # compute the weights for all combinations of their variations.") 1580 logger.info(" --from_card # use the information from the run_card (LO only).") 1581 logger.info(" --remove_weights= # remove previously written weights matching the descriptions") 1582 logger.info(" --keep_weights= # force to keep the weight even if in the list of remove_weights") 1583 logger.info(" --start_id= # define the starting digit for the additial weight. If not specify it is determine automatically") 1584 logger.info(" --only_beam=0 # only apply the new pdf set to the beam selected.") 1585 logger.info(" --ion_scaling=True# if original sample was using rescaled PDF: apply the same rescaling for all PDF sets.") 1586 logger.info(" --weight_format=\"%(id)i\" # allow to customise the name of the weight. The resulting name SHOULD be unique.") 1587 logger.info(" --weight_info= # allow to customise the text describing the weights.") 1588 logger.info("") 1589 logger.info(" Allowed value for the pdf options:", '$MG:BOLD') 1590 logger.info(" central : Do not perform any pdf variation" ) 1591 logger.info(" errorset : runs over the all the members of the PDF set used to generate the events") 1592 logger.info(" 244800 : runs over the associated set and all its members") 1593 logger.info(" 244800@0 : runs over the central member of the associated set") 1594 # logger.info(" 244800@X : runs over the Xth set of the associated error set") 1595 logger.info(" CT10 : runs over the associated set and all its members") 1596 logger.info(" CT10@0 : runs over the central member of the associated set") 1597 logger.info(" CT10@X : runs over the Xth member of the associated PDF set") 1598 logger.info(" XX,YY,ZZ : runs over the sets for XX,YY,ZZ (those three follows above syntax)") 1599 logger.info("") 1600 logger.info(" Allowed value for the keep/remove_wgts options:", '$MG:BOLD') 1601 logger.info(" all : keep/remove all weights") 1602 logger.info(" name : keep/remove that particular weight") 1603 logger.info(" id1,id2 : keep/remove all the weights between those two values --included--") 1604 logger.info(" PATTERN : keep/remove all the weights matching the (python) regular expression.") 1605 logger.info(" note that multiple entry of those arguments are allowed") 1606 logger.info("") 1607 logger.info(" Input for weight format") 1608 logger.info(" The parameter will be interpreted by python using: https://docs.python.org/2/library/stdtypes.html#string-formatting") 1609 logger.info(" The allowed parameters are 'muf','mur','pdf','dyn','alps','id'")
1610 - def complete_systematics(self, text, line, begidx, endidx):
1611 """auto completion for the systematics command""" 1612 1613 args = self.split_arg(line[0:begidx], error=False) 1614 options = ['--mur=', '--muf=', '--pdf=', '--dyn=','--alps=', 1615 '--together=','--from_card ','--remove_wgts=', 1616 '--keep_wgts=','--start_id='] 1617 1618 if len(args) == 1 and os.path.sep not in text: 1619 #return valid run_name 1620 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events')) 1621 data = [n.rsplit('/',2)[1] for n in data] 1622 return self.list_completion(text, data, line) 1623 elif len(args)==1: 1624 #logger.warning('1args') 1625 return self.path_completion(text, 1626 os.path.join('.',*[a for a in args \ 1627 if a.endswith(os.path.sep)])) 1628 elif len(args)==2 and os.path.sep in args[1]: 1629 #logger.warning('2args %s', args[1]) 1630 return self.path_completion(text, '.') 1631 1632 elif not line.endswith(tuple(options)): 1633 return self.list_completion(text, options)
1634 1635 1636 ############################################################################
1637 - def do_systematics(self, line):
1638 """ syntax is 'systematics [INPUT [OUTPUT]] OPTIONS' 1639 --mur=0.5,1,2 1640 --muf=0.5,1,2 1641 --alps=1 1642 --dyn=-1 1643 --together=mur,muf #can be repeated 1644 1645 #special options 1646 --from_card= 1647 """ 1648 1649 try: 1650 lhapdf_version = self.get_lhapdf_version() 1651 except Exception: 1652 logger.info('No version of lhapdf. Can not run systematics computation') 1653 return 1654 else: 1655 if lhapdf_version.startswith('5'): 1656 logger.info('can not run systematics with lhapdf 5') 1657 return 1658 1659 lhapdf = misc.import_python_lhapdf(self.options['lhapdf']) 1660 if not lhapdf: 1661 logger.info('can not run systematics since can not link python to lhapdf') 1662 return 1663 1664 1665 1666 1667 self.update_status('Running Systematics computation', level='parton') 1668 args = self.split_arg(line) 1669 #split arguments and option 1670 opts= [] 1671 args = [a for a in args if not a.startswith('-') or opts.append(a)] 1672 1673 #check sanity of options 1674 if any(not o.startswith(('--mur=', '--muf=', '--alps=','--dyn=','--together=','--from_card','--pdf=', 1675 '--remove_wgts=', '--keep_wgts','--start_id=', '--weight_format=', 1676 '--weight_info=')) 1677 for o in opts): 1678 raise self.InvalidCmd, "command systematics called with invalid option syntax. Please retry." 1679 1680 # check that we have define the input 1681 if len(args) == 0: 1682 if self.run_name: 1683 args[0] = self.run_name 1684 else: 1685 raise self.InvalidCmd, 'no default run. Please specify the run_name' 1686 1687 if args[0] != self.run_name: 1688 self.set_run_name(args[0]) 1689 1690 # always pass to a path + get the event size 1691 result_file= sys.stdout 1692 if not os.path.isfile(args[0]) and not os.path.sep in args[0]: 1693 path = [pjoin(self.me_dir, 'Events', args[0], 'unweighted_events.lhe.gz'), 1694 pjoin(self.me_dir, 'Events', args[0], 'unweighted_events.lhe'), 1695 pjoin(self.me_dir, 'Events', args[0], 'events.lhe.gz'), 1696 pjoin(self.me_dir, 'Events', args[0], 'events.lhe')] 1697 1698 for p in path: 1699 if os.path.exists(p): 1700 nb_event = self.results[args[0]].get_current_info()['nb_event'] 1701 1702 1703 if self.run_name != args[0]: 1704 tag = self.results[args[0]].tags[0] 1705 self.set_run_name(args[0], tag,'parton', False) 1706 result_file = open(pjoin(self.me_dir,'Events', self.run_name, 'parton_systematics.log'),'w') 1707 args[0] = p 1708 break 1709 else: 1710 raise self.InvalidCmd, 'Invalid run name. Please retry' 1711 elif self.options['nb_core'] != 1: 1712 lhe = lhe_parser.EventFile(args[0]) 1713 nb_event = len(lhe) 1714 lhe.close() 1715 1716 input = args[0] 1717 if len(args)>1: 1718 output = pjoin(os.getcwd(),args[1]) 1719 else: 1720 output = input 1721 1722 lhaid = [self.run_card.get_lhapdf_id()] 1723 if 'store_rwgt_info' in self.run_card and not self.run_card['store_rwgt_info']: 1724 raise self.InvalidCmd, "The events was not generated with store_rwgt_info=True. Can not evaluate systematics error on this event file." 1725 elif 'use_syst' in self.run_card: 1726 if not self.run_card['use_syst']: 1727 raise self.InvalidCmd, "The events was not generated with use_syst=True. Can not evaluate systematics error on this event file." 1728 elif self.proc_characteristics['ninitial'] ==1: 1729 if '--from_card' in opts: 1730 logger.warning('systematics not available for decay processes. Bypass it') 1731 return 1732 else: 1733 raise self.InvalidCmd, 'systematics not available for decay processes.' 1734 1735 try: 1736 pdfsets_dir = self.get_lhapdf_pdfsetsdir() 1737 except Exception, error: 1738 logger.debug(str(error)) 1739 logger.warning('Systematic computation requires lhapdf to run. Bypass Systematics') 1740 return 1741 1742 if '--from_card' in opts: 1743 opts.remove('--from_card') 1744 opts.append('--from_card=internal') 1745 1746 # Check that all pdfset are correctly installed 1747 if 'systematics_arguments' in self.run_card.user_set: 1748 pdf = [a[6:] for a in self.run_card['systematics_arguments'] 1749 if a.startswith('--pdf=')] 1750 lhaid += [t.split('@')[0] for p in pdf for t in p.split(',') 1751 if t not in ['errorset', 'central']] 1752 elif 'sys_pdf' in self.run_card.user_set: 1753 if '&&' in self.run_card['sys_pdf']: 1754 if isinstance(self.run_card['sys_pdf'], list): 1755 line = ' '.join(self.run_card['sys_pdf']) 1756 else: 1757 line = self.run_card['sys_pdf'] 1758 sys_pdf = line.split('&&') 1759 lhaid += [l.split()[0] for l in sys_pdf] 1760 else: 1761 lhaid += [l for l in self.run_card['sys_pdf'].split() if not l.isdigit() or int(l) > 500] 1762 1763 else: 1764 #check that all p 1765 pdf = [a[6:] for a in opts if a.startswith('--pdf=')] 1766 lhaid += [t.split('@')[0] for p in pdf for t in p.split(',') 1767 if t not in ['errorset', 'central']] 1768 1769 # Copy all the relevant PDF sets 1770 try: 1771 [self.copy_lhapdf_set([onelha], pdfsets_dir, require_local=False) for onelha in lhaid] 1772 except Exception, error: 1773 logger.debug(str(error)) 1774 logger.warning('impossible to download all the pdfsets. Bypass systematics') 1775 return 1776 1777 if self.options['run_mode'] ==2 and self.options['nb_core'] != 1: 1778 nb_submit = min(self.options['nb_core'], nb_event//2500) 1779 elif self.options['run_mode'] ==1: 1780 nb_submit = min(self.options['cluster_size'], nb_event//25000) 1781 else: 1782 nb_submit =1 1783 1784 if MADEVENT: 1785 import internal.systematics as systematics 1786 else: 1787 import madgraph.various.systematics as systematics 1788 1789 #one core: 1790 if nb_submit in [0,1]: 1791 systematics.call_systematics([input, output] + opts, 1792 log=lambda x: logger.info(str(x)), 1793 result=result_file 1794 ) 1795 1796 elif self.options['run_mode'] in [1,2]: 1797 event_per_job = nb_event // nb_submit 1798 nb_job_with_plus_one = nb_event % nb_submit 1799 start_event, stop_event = 0,0 1800 if sys.version_info[1] == 6 and sys.version_info[0] == 2: 1801 if input.endswith('.gz'): 1802 misc.gunzip(input) 1803 input = input[:-3] 1804 1805 for i in range(nb_submit): 1806 #computing start/stop event 1807 event_requested = event_per_job 1808 if i < nb_job_with_plus_one: 1809 event_requested += 1 1810 start_event = stop_event 1811 stop_event = start_event + event_requested 1812 1813 prog = sys.executable 1814 input_files = [os.path.basename(input)] 1815 output_files = ['./tmp_%s_%s' % (i, os.path.basename(output)), 1816 './log_sys_%s.txt' % (i)] 1817 argument = [] 1818 if not __debug__: 1819 argument.append('-O') 1820 argument += [pjoin(self.me_dir, 'bin', 'internal', 'systematics.py'), 1821 input_files[0], output_files[0]] + opts +\ 1822 ['--start_event=%i' % start_event, 1823 '--stop_event=%i' %stop_event, 1824 '--result=./log_sys_%s.txt' %i, 1825 '--lhapdf_config=%s' % self.options['lhapdf']] 1826 required_output = output_files 1827 self.cluster.cluster_submit(prog, argument, 1828 input_files=input_files, 1829 output_files=output_files, 1830 cwd=os.path.dirname(output), 1831 required_output=required_output, 1832 stdout='/dev/null' 1833 ) 1834 starttime = time.time() 1835 update_status = lambda idle, run, finish: \ 1836 self.update_status((idle, run, finish, 'running systematics'), level=None, 1837 force=False, starttime=starttime) 1838 1839 try: 1840 self.cluster.wait(os.path.dirname(output), update_status, update_first=update_status) 1841 except Exception: 1842 self.cluster.remove() 1843 old_run_mode = self.options['run_mode'] 1844 self.options['run_mode'] =0 1845 try: 1846 out = self.do_systematics(line) 1847 finally: 1848 self.options['run_mode'] = old_run_mode 1849 #collect the data 1850 all_cross = [] 1851 for i in range(nb_submit): 1852 pos=0 1853 for line in open(pjoin(os.path.dirname(output), 'log_sys_%s.txt'%i)): 1854 if line.startswith('#'): 1855 continue 1856 split = line.split() 1857 if len(split) in [0,1]: 1858 continue 1859 key = tuple(float(x) for x in split[:-1]) 1860 cross= float(split[-1]) 1861 if 'event_norm' in self.run_card and \ 1862 self.run_card['event_norm'] in ['average', 'unity', 'bias']: 1863 cross *= (event_per_job+1 if i <nb_job_with_plus_one else event_per_job) 1864 if len(all_cross) > pos: 1865 all_cross[pos] += cross 1866 else: 1867 all_cross.append(cross) 1868 pos+=1 1869 1870 if 'event_norm' in self.run_card and \ 1871 self.run_card['event_norm'] in ['unity']: 1872 all_cross= [cross/nb_event for cross in all_cross] 1873 1874 sys_obj = systematics.call_systematics([input, None] + opts, 1875 log=lambda x: logger.info(str(x)), 1876 result=result_file, 1877 running=False 1878 ) 1879 sys_obj.print_cross_sections(all_cross, nb_event, result_file) 1880 1881 #concatenate the output file 1882 subprocess.call(['cat']+\ 1883 ['./tmp_%s_%s' % (i, os.path.basename(output)) for i in range(nb_submit)], 1884 stdout=open(output,'w'), 1885 cwd=os.path.dirname(output)) 1886 for i in range(nb_submit): 1887 os.remove('%s/tmp_%s_%s' %(os.path.dirname(output),i,os.path.basename(output))) 1888 # os.remove('%s/log_sys_%s.txt' % (os.path.dirname(output),i)) 1889 1890 1891 1892 1893 1894 self.update_status('End of systematics computation', level='parton', makehtml=False)
1895 1896 1897 ############################################################################
1898 - def do_reweight(self, line):
1899 """ syntax is "reweight RUN_NAME" 1900 Allow to reweight the events generated with a new choices of model 1901 parameter. Description of the methods are available here 1902 cp3.irmp.ucl.ac.be/projects/madgraph/wiki/Reweight 1903 """ 1904 1905 1906 #### Utility function 1907 def check_multicore(self): 1908 """ determine if the cards are save for multicore use""" 1909 card = pjoin(self.me_dir, 'Cards', 'reweight_card.dat') 1910 1911 multicore = True 1912 if self.options['run_mode'] in [0,1]: 1913 multicore = False 1914 1915 lines = [l.strip() for l in open(card) if not l.strip().startswith('#')] 1916 while lines and not lines[0].startswith('launch'): 1917 line = lines.pop(0) 1918 # if not standard output mode forbid multicore mode 1919 if line.startswith('change') and line[6:].strip().startswith('output'): 1920 return False 1921 if line.startswith('change') and line[6:].strip().startswith('multicore'): 1922 split_line = line.split() 1923 if len(split_line) > 2: 1924 multicore = bool(split_line[2]) 1925 # we have reached the first launch in the card ensure that no output change 1926 #are done after that point. 1927 lines = [line[6:].strip() for line in lines if line.startswith('change')] 1928 for line in lines: 1929 if line.startswith(('process','model','output', 'rwgt_dir')): 1930 return False 1931 elif line.startswith('multicore'): 1932 split_line = line.split() 1933 if len(split_line) > 1: 1934 multicore = bool(split_line[1]) 1935 1936 return multicore
1937 1938 1939 1940 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'reweight_card.dat')): 1941 return 1942 # option for multicore to avoid that all of them create the same directory 1943 if '--multicore=create' in line: 1944 multicore='create' 1945 elif '--multicore=wait' in line: 1946 multicore='wait' 1947 else: 1948 multicore=False 1949 1950 # plugin option 1951 plugin = False 1952 if '--plugin=' in line: 1953 plugin = [l.split('=',1)[1] for l in line.split() if '--plugin=' in l][0] 1954 elif hasattr(self, 'switch') and self.switch['reweight'] not in ['ON','OFF']: 1955 plugin=self.switch['reweight'] 1956 1957 1958 1959 # Check that MG5 directory is present . 1960 if MADEVENT and not self.options['mg5_path']: 1961 raise self.InvalidCmd, '''The module reweight requires that MG5 is installed on the system. 1962 You can install it and set its path in ./Cards/me5_configuration.txt''' 1963 elif MADEVENT: 1964 sys.path.append(self.options['mg5_path']) 1965 try: 1966 import madgraph.interface.reweight_interface as reweight_interface 1967 except ImportError: 1968 raise self.ConfigurationError, '''Can\'t load Reweight module. 1969 The variable mg5_path might not be correctly configured.''' 1970 1971 1972 1973 if not '-from_cards' in line: 1974 self.keep_cards(['reweight_card.dat'], ignore=['*']) 1975 self.ask_edit_cards(['reweight_card.dat'], 'fixed', plot=False) 1976 1977 # load the name of the event file 1978 args = self.split_arg(line) 1979 if plugin and '--plugin=' not in line: 1980 args.append('--plugin=%s' % plugin) 1981 1982 1983 if not self.force_run: 1984 # forbid this function to create an empty item in results. 1985 if self.run_name and self.results.current and self.results.current['cross'] == 0: 1986 self.results.delete_run(self.run_name, self.run_tag) 1987 self.results.save() 1988 # ensure that the run_card is present 1989 if not hasattr(self, 'run_card'): 1990 self.run_card = banner_mod.RunCard(pjoin(self.me_dir, 'Cards', 'run_card.dat')) 1991 1992 # we want to run this in a separate shell to avoid hard f2py crash 1993 command = [sys.executable] 1994 if os.path.exists(pjoin(self.me_dir, 'bin', 'madevent')): 1995 command.append(pjoin(self.me_dir, 'bin', 'internal','madevent_interface.py')) 1996 else: 1997 command.append(pjoin(self.me_dir, 'bin', 'internal', 'amcatnlo_run_interface.py')) 1998 if not isinstance(self, cmd.CmdShell): 1999 command.append('--web') 2000 command.append('reweight') 2001 2002 ######### START SINGLE CORE MODE ############ 2003 if self.options['nb_core']==1 or self.run_card['nevents'] < 101 or not check_multicore(self): 2004 if self.run_name: 2005 command.append(self.run_name) 2006 else: 2007 command += args 2008 if '-from_cards' not in command: 2009 command.append('-from_cards') 2010 p = misc.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, cwd=os.getcwd()) 2011 while p.poll() is None: 2012 line = p.stdout.readline() 2013 if any(t in line for t in ['INFO:', 'WARNING:', 'CRITICAL:', 'ERROR:', 'root:','KEEP:']) and \ 2014 not '***********' in line: 2015 print line[:-1].replace('INFO', 'REWEIGHT').replace('KEEP:','') 2016 elif __debug__ and line: 2017 logger.debug(line[:-1]) 2018 if p.returncode !=0: 2019 logger.error("Reweighting failed") 2020 return 2021 self.results = self.load_results_db() 2022 # forbid this function to create an empty item in results. 2023 try: 2024 if self.results[self.run_name][-2]['cross']==0: 2025 self.results.delete_run(self.run_name,self.results[self.run_name][-2]['tag']) 2026 except: 2027 pass 2028 try: 2029 if self.results.current['cross'] == 0 and self.run_name: 2030 self.results.delete_run(self.run_name, self.run_tag) 2031 except: 2032 pass 2033 # re-define current run 2034 try: 2035 self.results.def_current(self.run_name, self.run_tag) 2036 except Exception: 2037 pass 2038 return 2039 ########## END SINGLE CORE HANDLING ############# 2040 else: 2041 ########## START MULTI-CORE HANDLING ############# 2042 if not isinstance(self.cluster, cluster.MultiCore): 2043 mycluster = cluster.MultiCore(nb_core=self.options['nb_core']) 2044 else: 2045 mycluster = self.cluster 2046 2047 new_args=list(args) 2048 self.check_decay_events(new_args) 2049 try: 2050 os.remove(pjoin(self.me_dir,'rw_me','rwgt.pkl')) 2051 except Exception, error: 2052 pass 2053 # prepare multi-core job: 2054 import madgraph.various.lhe_parser as lhe_parser 2055 # args now alway content the path to the valid files 2056 if 'nevt_job' in self.run_card and self.run_card['nevt_job'] !=-1: 2057 nevt_job = self.run_card['nevt_job'] 2058 else: 2059 nevt_job = max(2500, self.run_card['nevents']/self.options['nb_core']) 2060 logger.info("split the event file in bunch of %s events" % nevt_job) 2061 nb_file = lhe_parser.EventFile(new_args[0]).split(nevt_job) 2062 starttime = time.time() 2063 update_status = lambda idle, run, finish: \ 2064 self.update_status((idle, run, finish, 'reweight'), level=None, 2065 force=False, starttime=starttime) 2066 2067 all_lhe = [] 2068 #check for the pyton2.6 bug with s 2069 to_zip=True 2070 if not os.path.exists(new_args[0]) and new_args[0].endswith('.gz') and\ 2071 os.path.exists(new_args[0][:-3]): 2072 to_zip = False 2073 devnull= open(os.devnull) 2074 2075 for i in range(nb_file): 2076 new_command = list(command) 2077 if to_zip: 2078 new_command.append('%s_%s.lhe' % (new_args[0],i)) 2079 all_lhe.append('%s_%s.lhe' % (new_args[0],i)) 2080 else: 2081 new_command.append('%s_%s.lhe' % (new_args[0][:-3],i)) 2082 all_lhe.append('%s_%s.lhe' % (new_args[0][:-3],i)) 2083 2084 if '-from_cards' not in command: 2085 new_command.append('-from_cards') 2086 if plugin: 2087 new_command.append('--plugin=%s' % plugin) 2088 if i==0: 2089 if __debug__: 2090 stdout = None 2091 else: 2092 stdout = open(pjoin(self.me_dir,'Events', self.run_name, 'reweight.log'),'w') 2093 new_command.append('--multicore=create') 2094 else: 2095 stdout = devnull 2096 #stdout = open(pjoin(self.me_dir,'Events', self.run_name, 'reweight%s.log' % i),'w') 2097 new_command.append('--multicore=wait') 2098 mycluster.submit(prog=command[0], argument=new_command[1:], stdout=stdout, cwd=os.getcwd()) 2099 mycluster.wait(self.me_dir,update_status) 2100 devnull.close() 2101 logger.info("Collect and combine the various output file.") 2102 2103 lhe = lhe_parser.MultiEventFile(all_lhe, parse=False) 2104 nb_event, cross_sections = lhe.write(new_args[0], get_info=True) 2105 if any(os.path.exists('%s_%s_debug.log' % (f, self.run_tag)) for f in all_lhe): 2106 for f in all_lhe: 2107 if os.path.exists('%s_%s_debug.log' % (f, self.run_tag)): 2108 raise Exception, "Some of the run failed: Please read %s_%s_debug.log" % (f, self.run_tag) 2109 2110 2111 if 'event_norm' in self.run_card and self.run_card['event_norm'] in ['average','bias']: 2112 for key, value in cross_sections.items(): 2113 cross_sections[key] = value / (nb_event+1) 2114 lhe.remove() 2115 for key in cross_sections: 2116 if key == 'orig' or key.isdigit(): 2117 continue 2118 logger.info('%s : %s pb' % (key, cross_sections[key])) 2119 return 2120 ########## END MULTI-CORE HANDLING ############# 2121 2122 2123 self.to_store.append('event') 2124 # forbid this function to create an empty item in results. 2125 if not self.force_run and self.results.current['cross'] == 0 and self.run_name: 2126 self.results.delete_run(self.run_name, self.run_tag) 2127 2128 self.check_decay_events(args) 2129 # args now alway content the path to the valid files 2130 rwgt_interface = reweight_interface.ReweightInterface 2131 if plugin: 2132 rwgt_interface = misc.from_plugin_import(self.plugin_path, 'new_reweight', 2133 plugin, warning=False, 2134 info="Will use re-weighting from pluging %(plug)s") 2135 2136 reweight_cmd = rwgt_interface(args[0], mother=self) 2137 #reweight_cmd.use_rawinput = False 2138 #reweight_cmd.mother = self 2139 wgt_names = reweight_cmd.get_weight_names() 2140 if wgt_names == [''] and reweight_cmd.has_nlo: 2141 self.update_status('Running Reweighting (LO approximate)', level='madspin') 2142 else: 2143 self.update_status('Running Reweighting', level='madspin') 2144 2145 path = pjoin(self.me_dir, 'Cards', 'reweight_card.dat') 2146 reweight_cmd.raw_input=False 2147 reweight_cmd.me_dir = self.me_dir 2148 reweight_cmd.multicore = multicore #allow the directory creation or not 2149 reweight_cmd.import_command_file(path) 2150 reweight_cmd.do_quit('') 2151 2152 logger.info("quit rwgt") 2153 2154 2155 2156 # re-define current run 2157 try: 2158 self.results.def_current(self.run_name, self.run_tag) 2159 except Exception: 2160 pass 2161 2162 ############################################################################
2163 - def do_pgs(self, line):
2164 """launch pgs""" 2165 2166 args = self.split_arg(line) 2167 # Check argument's validity 2168 if '--no_default' in args: 2169 no_default = True 2170 args.remove('--no_default') 2171 else: 2172 no_default = False 2173 2174 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')): 2175 logger.info('No pgs_card detected, so not run pgs') 2176 return 2177 2178 # Check all arguments 2179 # This might launch a gunzip in another thread. After the question 2180 # This thread need to be wait for completion. (This allow to have the 2181 # question right away and have the computer working in the same time) 2182 # if lock is define this a locker for the completion of the thread 2183 lock = self.check_pgs(args, no_default=no_default) 2184 2185 # Check that the pgs_card exists. If not copy the default 2186 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')): 2187 files.cp(pjoin(self.me_dir, 'Cards', 'pgs_card_default.dat'), 2188 pjoin(self.me_dir, 'Cards', 'pgs_card.dat')) 2189 logger.info('No pgs card found. Take the default one.') 2190 2191 if not (no_default or self.force): 2192 self.ask_edit_cards(['pgs_card.dat']) 2193 2194 self.update_status('prepare PGS run', level=None) 2195 2196 pgsdir = pjoin(self.options['pythia-pgs_path'], 'src') 2197 eradir = self.options['exrootanalysis_path'] 2198 madir = self.options['madanalysis_path'] 2199 td = self.options['td_path'] 2200 2201 # Compile pgs if not there 2202 if not misc.is_executable(pjoin(pgsdir, 'pgs')): 2203 logger.info('No PGS executable -- running make') 2204 misc.compile(cwd=pgsdir) 2205 2206 self.update_status('Running PGS', level='pgs') 2207 2208 tag = self.run_tag 2209 # Update the banner with the pgs card 2210 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, self.run_tag)) 2211 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')): 2212 self.banner.add(pjoin(self.me_dir, 'Cards','pgs_card.dat')) 2213 self.banner.write(banner_path) 2214 else: 2215 open(banner_path, 'w').close() 2216 2217 ######################################################################## 2218 # now pass the event to a detector simulator and reconstruct objects 2219 ######################################################################## 2220 if lock: 2221 lock.wait() 2222 # Prepare the output file with the banner 2223 ff = open(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'), 'w') 2224 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')): 2225 text = open(banner_path).read() 2226 text = '#%s' % text.replace('\n','\n#') 2227 dico = self.results[self.run_name].get_current_info() 2228 text +='\n## Integrated weight (pb) : %.4g' % dico['cross'] 2229 text +='\n## Number of Event : %s\n' % dico['nb_event'] 2230 ff.writelines(text) 2231 ff.close() 2232 2233 try: 2234 os.remove(pjoin(self.me_dir, 'Events', 'pgs.done')) 2235 except Exception: 2236 pass 2237 2238 pgs_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_pgs.log" % tag) 2239 self.cluster.launch_and_wait('../bin/internal/run_pgs', 2240 argument=[pgsdir], cwd=pjoin(self.me_dir,'Events'), 2241 stdout=pgs_log, stderr=subprocess.STDOUT) 2242 2243 if not os.path.exists(pjoin(self.me_dir, 'Events', 'pgs.done')): 2244 logger.error('Fail to create LHCO events') 2245 return 2246 else: 2247 os.remove(pjoin(self.me_dir, 'Events', 'pgs.done')) 2248 2249 if os.path.getsize(banner_path) == os.path.getsize(pjoin(self.me_dir, 'Events','pgs_events.lhco')): 2250 misc.call(['cat pgs_uncleaned_events.lhco >> pgs_events.lhco'], 2251 cwd=pjoin(self.me_dir, 'Events')) 2252 os.remove(pjoin(self.me_dir, 'Events', 'pgs_uncleaned_events.lhco ')) 2253 2254 # Creating Root file 2255 if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHCOlympicsConverter')): 2256 self.update_status('Creating PGS Root File', level='pgs') 2257 try: 2258 misc.call([eradir+'/ExRootLHCOlympicsConverter', 2259 'pgs_events.lhco',pjoin('%s/%s_pgs_events.root' % (self.run_name, tag))], 2260 cwd=pjoin(self.me_dir, 'Events')) 2261 except Exception: 2262 logger.warning('fail to produce Root output [problem with ExRootAnalysis') 2263 if os.path.exists(pjoin(self.me_dir, 'Events', 'pgs_events.lhco')): 2264 # Creating plots 2265 files.mv(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'), 2266 pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag)) 2267 self.create_plot('PGS') 2268 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag)) 2269 2270 self.update_status('finish', level='pgs', makehtml=False)
2271 2272 ############################################################################
2273 - def do_compute_widths(self, line):
2274 """Require MG5 directory: Compute automatically the widths of a set 2275 of particles""" 2276 2277 args = self.split_arg(line) 2278 opts = self.check_compute_widths(args) 2279 2280 from madgraph.interface.master_interface import MasterCmd 2281 cmd = MasterCmd() 2282 self.define_child_cmd_interface(cmd, interface=False) 2283 cmd.options.update(self.options) 2284 cmd.exec_cmd('set automatic_html_opening False --no_save') 2285 if not opts['path']: 2286 opts['path'] = pjoin(self.me_dir, 'Cards', 'param_card.dat') 2287 if not opts['force'] : 2288 self.ask_edit_cards(['param_card.dat'],[], plot=False) 2289 2290 2291 line = 'compute_widths %s %s' % \ 2292 (' '.join([str(i) for i in opts['particles']]), 2293 ' '.join('--%s=%s' % (key,value) for (key,value) in opts.items() 2294 if key not in ['model', 'force', 'particles'] and value)) 2295 out = cmd.exec_cmd(line, model=opts['model']) 2296 2297 2298 self.child = None 2299 del cmd 2300 return out
2301 2302 2303 2304 ############################################################################
2305 - def do_print_results(self, line):
2306 """Not in help:Print the cross-section/ number of events for a given run""" 2307 2308 args = self.split_arg(line) 2309 options={'path':None, 'mode':'w', 'format':'full'} 2310 for arg in list(args): 2311 if arg.startswith('--') and '=' in arg: 2312 name,value=arg.split('=',1) 2313 name = name [2:] 2314 options[name] = value 2315 args.remove(arg) 2316 2317 2318 if len(args) > 0: 2319 run_name = args[0] 2320 else: 2321 for i, run_name in enumerate(self.results.order): 2322 for j, one_result in enumerate(self.results[run_name]): 2323 if i or j: 2324 options['mode'] = "a" 2325 if options['path']: 2326 self.print_results_in_file(one_result, options['path'], options['mode'], options['format']) 2327 else: 2328 self.print_results_in_shell(one_result) 2329 return 2330 2331 if run_name not in self.results: 2332 raise self.InvalidCmd('%s is not a valid run_name or it doesn\'t have any information' \ 2333 % run_name) 2334 2335 2336 if len(args) == 2: 2337 tag = args[1] 2338 if tag.isdigit(): 2339 tag = int(tag) - 1 2340 if len(self.results[run_name]) < tag: 2341 raise self.InvalidCmd('Only %s different tag available' % \ 2342 len(self.results[run_name])) 2343 data = self.results[run_name][tag] 2344 else: 2345 data = self.results[run_name].return_tag(tag) 2346 else: 2347 data = self.results[run_name].return_tag(None) # return the last 2348 2349 if options['path']: 2350 self.print_results_in_file(data, options['path'], options['mode'], options['format']) 2351 else: 2352 self.print_results_in_shell(data)
2353
2354 - def configure_directory(self, *args, **opts):
2355 """ All action require before any type of run. Typically overloaded by 2356 daughters if need be.""" 2357 pass
2358 2359 ############################################################################ 2360 # Start of MadAnalysis5 related function 2361 ############################################################################ 2362 2363 @staticmethod
2364 - def runMA5(MA5_interpreter, MA5_cmds, MA5_runtag, logfile_path, advertise_log=True):
2365 """ Run MA5 in a controlled environnment.""" 2366 successfull_MA5_run = True 2367 2368 try: 2369 # Predefine MA5_logger as None in case we don't manage to retrieve it. 2370 MA5_logger = None 2371 MA5_logger = logging.getLogger('MA5') 2372 BackUp_MA5_handlers = MA5_logger.handlers 2373 for handler in BackUp_MA5_handlers: 2374 MA5_logger.removeHandler(handler) 2375 file_handler = logging.FileHandler(logfile_path) 2376 MA5_logger.addHandler(file_handler) 2377 if advertise_log: 2378 logger.info("Follow Madanalysis5 run with the following command in a separate terminal:") 2379 logger.info(' tail -f %s'%logfile_path) 2380 # Now the magic, finally call MA5. 2381 with misc.stdchannel_redirected(sys.stdout, os.devnull): 2382 with misc.stdchannel_redirected(sys.stderr, os.devnull): 2383 MA5_interpreter.print_banner() 2384 MA5_interpreter.load(MA5_cmds) 2385 except Exception as e: 2386 logger.warning("MadAnalysis5 failed to run the commands for task "+ 2387 "'%s'. Madanalys5 analysis will be skipped."%MA5_runtag) 2388 error=StringIO.StringIO() 2389 traceback.print_exc(file=error) 2390 logger.debug('MadAnalysis5 error was:') 2391 logger.debug('-'*60) 2392 logger.debug(error.getvalue()[:-1]) 2393 logger.debug('-'*60) 2394 successfull_MA5_run = False 2395 finally: 2396 if not MA5_logger is None: 2397 for handler in MA5_logger.handlers: 2398 MA5_logger.removeHandler(handler) 2399 for handler in BackUp_MA5_handlers: 2400 MA5_logger.addHandler(handler) 2401 2402 return successfull_MA5_run
2403 2404 #=============================================================================== 2405 # Return a Main instance of MadAnlysis5, provided its path 2406 #=============================================================================== 2407 @staticmethod
2408 - def get_MadAnalysis5_interpreter(mg5_path, ma5_path, mg5_interface=None, 2409 logstream = sys.stdout, loglevel =logging.INFO, forced = True, 2410 compilation=False):
2411 """ Makes sure to correctly setup paths and constructs and return an MA5 path""" 2412 2413 MA5path = os.path.normpath(pjoin(mg5_path,ma5_path)) 2414 2415 if MA5path is None or not os.path.isfile(pjoin(MA5path,'bin','ma5')): 2416 return None 2417 if MA5path not in sys.path: 2418 sys.path.insert(0, MA5path) 2419 2420 try: 2421 # We must backup the readline module attributes because they get modified 2422 # when MA5 imports root and that supersedes MG5 autocompletion 2423 import readline 2424 old_completer = readline.get_completer() 2425 old_delims = readline.get_completer_delims() 2426 old_history = [readline.get_history_item(i) for i in range(1,readline.get_current_history_length()+1)] 2427 except ImportError: 2428 old_completer, old_delims, old_history = None, None, None 2429 try: 2430 from madanalysis.interpreter.ma5_interpreter import MA5Interpreter 2431 with misc.stdchannel_redirected(sys.stdout, os.devnull): 2432 with misc.stdchannel_redirected(sys.stderr, os.devnull): 2433 MA5_interpreter = MA5Interpreter(MA5path, LoggerLevel=loglevel, 2434 LoggerStream=logstream,forced=forced, 2435 no_compilation=not compilation) 2436 except Exception as e: 2437 logger.warning('MadAnalysis5 failed to start so that MA5 analysis will be skipped.') 2438 error=StringIO.StringIO() 2439 traceback.print_exc(file=error) 2440 logger.debug('MadAnalysis5 error was:') 2441 logger.debug('-'*60) 2442 logger.debug(error.getvalue()[:-1]) 2443 logger.debug('-'*60) 2444 MA5_interpreter = None 2445 finally: 2446 # Now restore the readline MG5 state 2447 if not old_history is None: 2448 readline.clear_history() 2449 for line in old_history: 2450 readline.add_history(line) 2451 if not old_completer is None: 2452 readline.set_completer(old_completer) 2453 if not old_delims is None: 2454 readline.set_completer_delims(old_delims) 2455 # Also restore the completion_display_matches_hook if an mg5 interface 2456 # is specified as it could also have been potentially modified 2457 if not mg5_interface is None and any(not elem is None for elem in [old_completer, old_delims, old_history]): 2458 mg5_interface.set_readline_completion_display_matches_hook() 2459 2460 return MA5_interpreter
2461
2462 - def check_madanalysis5(self, args, mode='parton'):
2463 """Check the argument for the madanalysis5 command 2464 syntax: madanalysis5_parton [NAME] 2465 """ 2466 2467 MA5_options = {'MA5_stdout_lvl':'default'} 2468 2469 stdout_level_tags = [a for a in args if a.startswith('--MA5_stdout_lvl=')] 2470 for slt in stdout_level_tags: 2471 lvl = slt.split('=')[1].strip() 2472 try: 2473 # It is likely an int 2474 MA5_options['MA5_stdout_lvl']=int(lvl) 2475 except ValueError: 2476 if lvl.startswith('logging.'): 2477 lvl = lvl[8:] 2478 try: 2479 MA5_options['MA5_stdout_lvl'] = getattr(logging, lvl) 2480 except: 2481 raise InvalidCmd("MA5 output level specification"+\ 2482 " '%s' is incorrect." % str(lvl)) 2483 args.remove(slt) 2484 2485 if mode=='parton': 2486 # We will attempt to run MA5 on the parton level output 2487 # found in the last run if not specified. 2488 MA5_options['inputs'] = '*.lhe' 2489 elif mode=='hadron': 2490 # We will run MA5 on all sources of post-partonic output we 2491 # can find if not specified. PY8 is a keyword indicating shower 2492 # piped to MA5. 2493 MA5_options['inputs'] = ['fromCard'] 2494 else: 2495 raise MadGraph5Error('Mode %s not reckognized'%mode+ 2496 ' in function check_madanalysis5.') 2497 # If not madanalysis5 path 2498 if not self.options['madanalysis5_path']: 2499 logger.info('Now trying to read the configuration file again'+ 2500 ' to find MadAnalysis5 path') 2501 self.set_configuration() 2502 2503 if not self.options['madanalysis5_path'] or not \ 2504 os.path.exists(pjoin(self.options['madanalysis5_path'],'bin','ma5')): 2505 error_msg = 'No valid MadAnalysis5 path set.\n' 2506 error_msg += 'Please use the set command to define the path and retry.\n' 2507 error_msg += 'You can also define it in the configuration file.\n' 2508 error_msg += 'Finally, it can be installed automatically using the' 2509 error_msg += ' install command.\n' 2510 raise self.InvalidCmd(error_msg) 2511 2512 # Now make sure that the corresponding default card exists 2513 if not os.path.isfile(pjoin(self.me_dir, 2514 'Cards','madanalysis5_%s_card.dat'%mode)): 2515 raise self.InvalidCmd('Your installed version of MadAnalysis5 and/or'+\ 2516 ' MadGraph5_aMCatNLO does not seem to support analysis at'+ 2517 '%s level.'%mode) 2518 2519 tag = [a for a in args if a.startswith('--tag=')] 2520 if tag: 2521 args.remove(tag[0]) 2522 tag = tag[0][6:] 2523 2524 if len(args) == 0 and not self.run_name: 2525 if self.results.lastrun: 2526 args.insert(0, self.results.lastrun) 2527 else: 2528 raise self.InvalidCmd('No run name currently defined. '+ 2529 'Please add this information.') 2530 2531 if len(args) >= 1: 2532 if mode=='parton' and args[0] != self.run_name and \ 2533 not os.path.exists(pjoin(self.me_dir,'Events',args[0], 2534 'unweighted_events.lhe.gz')) and not os.path.exists( 2535 pjoin(self.me_dir,'Events',args[0])): 2536 raise self.InvalidCmd('No events file in the %s run.'%args[0]) 2537 self.set_run_name(args[0], tag, level='madanalysis5_%s'%mode) 2538 else: 2539 if tag: 2540 self.run_card['run_tag'] = args[0] 2541 self.set_run_name(self.run_name, tag, level='madanalysis5_%s'%mode) 2542 2543 if mode=='parton': 2544 if any(t for t in args if t.startswith('--input=')): 2545 raise InvalidCmd('The option --input=<input_file> is not'+ 2546 ' available when running partonic MadAnalysis5 analysis. The'+ 2547 ' .lhe output of the selected run is used automatically.') 2548 input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe') 2549 MA5_options['inputs'] = '%s.gz'%input_file 2550 if not os.path.exists('%s.gz'%input_file): 2551 if os.path.exists(input_file): 2552 misc.gzip(input_file, stdout='%s.gz' % input_file) 2553 else: 2554 logger.warning("LHE event file not found in \n%s\ns"%input_file+ 2555 "Parton-level MA5 analysis will be skipped.") 2556 2557 if mode=='hadron': 2558 # Make sure to store current results (like Pythia8 hep files) 2559 # so that can be found here 2560 self.store_result() 2561 2562 hadron_tag = [t for t in args if t.startswith('--input=')] 2563 if hadron_tag and hadron_tag[0][8:]: 2564 hadron_inputs = hadron_tag[0][8:].split(',') 2565 2566 # If not set above, then we must read it from the card 2567 elif MA5_options['inputs'] == ['fromCard']: 2568 hadron_inputs = banner_mod.MadAnalysis5Card(pjoin(self.me_dir, 2569 'Cards','madanalysis5_hadron_card.dat'),mode='hadron')['inputs'] 2570 2571 # Make sure the corresponding input files are present and unfold 2572 # potential wildcard while making their path absolute as well. 2573 MA5_options['inputs'] = [] 2574 special_source_tags = [] 2575 for htag in hadron_inputs: 2576 # Possible pecial tag for MA5 run inputs 2577 if htag in special_source_tags: 2578 # Special check/actions 2579 continue 2580 # Check if the specified file exists and is not a wildcard 2581 if os.path.isfile(htag) or (os.path.exists(htag) and 2582 stat.S_ISFIFO(os.stat(htag).st_mode)): 2583 MA5_options['inputs'].append(htag) 2584 continue 2585 2586 # Now select one source per tag, giving priority to unzipped 2587 # files with 'events' in their name (case-insensitive). 2588 file_candidates = misc.glob(htag, pjoin(self.me_dir,'Events',self.run_name))+\ 2589 misc.glob('%s.gz'%htag, pjoin(self.me_dir,'Events',self.run_name)) 2590 priority_files = [f for f in file_candidates if 2591 self.run_card['run_tag'] in os.path.basename(f)] 2592 priority_files = [f for f in priority_files if 2593 'EVENTS' in os.path.basename(f).upper()] 2594 # Make sure to always prefer the original partonic event file 2595 for f in file_candidates: 2596 if os.path.basename(f).startswith('unweighted_events.lhe'): 2597 priority_files.append(f) 2598 if priority_files: 2599 MA5_options['inputs'].append(priority_files[-1]) 2600 continue 2601 if file_candidates: 2602 MA5_options['inputs'].append(file_candidates[-1]) 2603 continue 2604 2605 return MA5_options
2606
2607 - def ask_madanalysis5_run_configuration(self, runtype='parton',mode=None):
2608 """Ask the question when launching madanalysis5. 2609 In the future we can ask here further question about the MA5 run, but 2610 for now we just edit the cards""" 2611 2612 cards = ['madanalysis5_%s_card.dat'%runtype] 2613 self.keep_cards(cards) 2614 2615 if self.force: 2616 return runtype 2617 2618 # This heavy-looking structure of auto is just to mimick what is done 2619 # for ask_pythia_configuration 2620 auto=False 2621 if mode=='auto': 2622 auto=True 2623 if auto: 2624 self.ask_edit_cards(cards, mode='auto', plot=False) 2625 else: 2626 self.ask_edit_cards(cards, plot=False) 2627 2628 # For now, we don't pass any further information and simply return the 2629 # input mode asked for 2630 mode = runtype 2631 return mode
2632
2633 - def complete_madanalysis5_hadron(self,text, line, begidx, endidx):
2634 "Complete the madanalysis5 command" 2635 args = self.split_arg(line[0:begidx], error=False) 2636 if len(args) == 1: 2637 #return valid run_name 2638 data = [] 2639 for name in banner_mod.MadAnalysis5Card._default_hadron_inputs: 2640 data += misc.glob(pjoin('*','%s'%name), pjoin(self.me_dir, 'Events')) 2641 data += misc.glob(pjoin('*','%s.gz'%name), pjoin(self.me_dir, 'Events')) 2642 data = [n.rsplit('/',2)[1] for n in data] 2643 tmp1 = self.list_completion(text, data) 2644 if not self.run_name: 2645 return tmp1 2646 else: 2647 tmp2 = self.list_completion(text, ['-f', 2648 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line) 2649 return tmp1 + tmp2 2650 2651 elif '--MA5_stdout_lvl=' in line and not any(arg.startswith( 2652 '--MA5_stdout_lvl=') for arg in args): 2653 return self.list_completion(text, 2654 ['--MA5_stdout_lvl=%s'%opt for opt in 2655 ['logging.INFO','logging.DEBUG','logging.WARNING', 2656 'logging.CRITICAL','90']], line) 2657 elif '--input=' in line and not any(arg.startswith( 2658 '--input=') for arg in args): 2659 return self.list_completion(text, ['--input=%s'%opt for opt in 2660 (banner_mod.MadAnalysis5Card._default_hadron_inputs +['path'])], line) 2661 else: 2662 return self.list_completion(text, ['-f', 2663 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line)
2664
2665 - def do_madanalysis5_hadron(self, line):
2666 """launch MadAnalysis5 at the hadron level.""" 2667 return self.run_madanalysis5(line,mode='hadron')
2668
2669 - def run_madanalysis5(self, line, mode='parton'):
2670 """launch MadAnalysis5 at the parton level or at the hadron level with 2671 a specific command line.""" 2672 2673 # Check argument's validity 2674 args = self.split_arg(line) 2675 2676 if '--no_default' in args: 2677 no_default = True 2678 args.remove('--no_default') 2679 else: 2680 no_default = False 2681 2682 if no_default: 2683 # Called issued by MG5aMC itself during a generate_event action 2684 if mode=='parton' and not os.path.exists(pjoin(self.me_dir, 'Cards', 2685 'madanalysis5_parton_card.dat')): 2686 return 2687 if mode=='hadron' and not os.path.exists(pjoin(self.me_dir, 'Cards', 2688 'madanalysis5_hadron_card.dat')): 2689 return 2690 else: 2691 # Called issued by the user itself and only MA5 will be run. 2692 # we must therefore ask wheter the user wants to edit the card 2693 self.ask_madanalysis5_run_configuration(runtype=mode) 2694 2695 if not self.options['madanalysis5_path'] or \ 2696 all(not os.path.exists(pjoin(self.me_dir, 'Cards',card)) for card in 2697 ['madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat']): 2698 if no_default: 2699 return 2700 else: 2701 raise InvalidCmd('You must have MadAnalysis5 available to run'+ 2702 " this command. Consider installing it with the 'install' function.") 2703 2704 if not self.run_name: 2705 MA5_opts = self.check_madanalysis5(args, mode=mode) 2706 self.configure_directory(html_opening =False) 2707 else: 2708 # initialize / remove lhapdf mode 2709 self.configure_directory(html_opening =False) 2710 MA5_opts = self.check_madanalysis5(args, mode=mode) 2711 2712 # Now check that there is at least one input to run 2713 if MA5_opts['inputs']==[]: 2714 if no_default: 2715 logger.warning('No hadron level input found to run MadAnalysis5 on.'+ 2716 ' Skipping its hadron-level analysis.') 2717 return 2718 else: 2719 raise self.InvalidCmd('\nNo input files specified or availabled for'+ 2720 ' this MadAnalysis5 hadron-level run.\nPlease double-check the options of this'+ 2721 ' MA5 command (or card) and which output files\nare currently in the chosen'+ 2722 " run directory '%s'."%self.run_name) 2723 2724 MA5_card = banner_mod.MadAnalysis5Card(pjoin(self.me_dir, 'Cards', 2725 'madanalysis5_%s_card.dat'%mode), mode=mode) 2726 2727 if MA5_card._skip_analysis: 2728 logger.info('Madanalysis5 %s-level analysis was skipped following user request.'%mode) 2729 logger.info("To run the analysis, remove or comment the tag '%s skip_analysis' " 2730 %banner_mod.MadAnalysis5Card._MG5aMC_escape_tag+ 2731 "in\n '%s'."%pjoin(self.me_dir, 'Cards','madanalysis5_%s_card.dat'%mode)) 2732 return 2733 2734 MA5_cmds_list = MA5_card.get_MA5_cmds(MA5_opts['inputs'], 2735 pjoin(self.me_dir,'MA5_%s_ANALYSIS'%mode.upper()), 2736 run_dir_path = pjoin(self.me_dir,'Events', self.run_name), 2737 UFO_model_path=pjoin(self.me_dir,'bin','internal','ufomodel'), 2738 run_tag = self.run_tag) 2739 2740 # Here's how to print the MA5 commands generated by MG5aMC 2741 # for MA5_runtag, MA5_cmds in MA5_cmds_list: 2742 # misc.sprint('****************************************') 2743 # misc.sprint('* Commands for MA5 runtag %s:'%MA5_runtag) 2744 # misc.sprint('\n'+('\n'.join('* %s'%cmd for cmd in MA5_cmds))) 2745 # misc.sprint('****************************************') 2746 2747 self.update_status('\033[92mRunning MadAnalysis5 [arXiv:1206.1599]\033[0m', 2748 level='madanalysis5_%s'%mode) 2749 if mode=='hadron': 2750 logger.info('Hadron input files considered:') 2751 for input in MA5_opts['inputs']: 2752 logger.info(' --> %s'%input) 2753 elif mode=='parton': 2754 logger.info('Parton input file considered:') 2755 logger.info(' --> %s'%MA5_opts['inputs']) 2756 2757 # Obtain a main MA5 interpreter 2758 # Ideally we would like to do it all with a single interpreter 2759 # but we'd need a way to reset it for this. 2760 if MA5_opts['MA5_stdout_lvl']=='default': 2761 if MA5_card['stdout_lvl'] is None: 2762 MA5_lvl = self.options['stdout_level'] 2763 else: 2764 MA5_lvl = MA5_card['stdout_lvl'] 2765 else: 2766 MA5_lvl = MA5_opts['MA5_stdout_lvl'] 2767 2768 # Bypass initialization information 2769 MA5_interpreter = CommonRunCmd.get_MadAnalysis5_interpreter( 2770 self.options['mg5_path'], 2771 self.options['madanalysis5_path'], 2772 logstream=sys.stdout, 2773 loglevel=100, 2774 forced=True, 2775 compilation=True) 2776 2777 2778 # If failed to start MA5, then just leave 2779 if MA5_interpreter is None: 2780 return 2781 2782 # Make sure to only run over one analysis over each fifo. 2783 used_up_fifos = [] 2784 # Now loop over the different MA5_runs 2785 for MA5_run_number, (MA5_runtag, MA5_cmds) in enumerate(MA5_cmds_list): 2786 2787 # Since we place every MA5 run in a fresh new folder, the MA5_run_number 2788 # is always zero. 2789 MA5_run_number = 0 2790 # Bypass the banner. 2791 MA5_interpreter.setLogLevel(100) 2792 # Make sure to properly initialize MA5 interpreter 2793 if mode=='hadron': 2794 MA5_interpreter.init_reco() 2795 else: 2796 MA5_interpreter.init_parton() 2797 MA5_interpreter.setLogLevel(MA5_lvl) 2798 2799 if MA5_runtag!='default': 2800 if MA5_runtag.startswith('_reco_'): 2801 logger.info("MadAnalysis5 now running the reconstruction '%s'..."% 2802 MA5_runtag[6:],'$MG:color:GREEN') 2803 elif MA5_runtag=='Recasting': 2804 logger.info("MadAnalysis5 now running the recasting...", 2805 '$MG:color:GREEN') 2806 else: 2807 logger.info("MadAnalysis5 now running the '%s' analysis..."% 2808 MA5_runtag,'$MG:color:GREEN') 2809 2810 2811 # Now the magic, let's call MA5 2812 if not CommonRunCmd.runMA5(MA5_interpreter, MA5_cmds, MA5_runtag, 2813 pjoin(self.me_dir,'Events',self.run_name,'%s_MA5_%s.log'%(self.run_tag,MA5_runtag))): 2814 # Unsuccessful MA5 run, we therefore stop here. 2815 return 2816 2817 if MA5_runtag.startswith('_reco_'): 2818 # When doing a reconstruction we must first link the event file 2819 # created with MA5 reconstruction and then directly proceed to the 2820 # next batch of instructions. There can be several output directory 2821 # if there were several input files. 2822 links_created=[] 2823 for i, input in enumerate(MA5_opts['inputs']): 2824 # Make sure it is not an lhco or root input, which would not 2825 # undergo any reconstruction of course. 2826 if not banner_mod.MadAnalysis5Card.events_can_be_reconstructed(input): 2827 continue 2828 2829 if input.endswith('.fifo'): 2830 if input in used_up_fifos: 2831 # Only run once on each fifo 2832 continue 2833 else: 2834 used_up_fifos.append(input) 2835 2836 reco_output = pjoin(self.me_dir, 2837 'MA5_%s_ANALYSIS%s_%d'%(mode.upper(),MA5_runtag,i+1)) 2838 # Look for either a root or .lhe.gz output 2839 reco_event_file = misc.glob('*.lhe.gz',pjoin(reco_output,'Output','_reco_events','lheEvents0_%d'%MA5_run_number))+\ 2840 misc.glob('*.root',pjoin(reco_output,'Output','_reco_events', 'RecoEvents0_%d'%MA5_run_number)) 2841 if len(reco_event_file)==0: 2842 raise MadGraph5Error, "MadAnalysis5 failed to produce the "+\ 2843 "reconstructed event file for reconstruction '%s'."%MA5_runtag[6:] 2844 reco_event_file = reco_event_file[0] 2845 # move the reconstruction output to the HTML directory 2846 shutil.move(reco_output,pjoin(self.me_dir,'HTML', 2847 self.run_name,'%s_MA5_%s_ANALYSIS%s_%d'% 2848 (self.run_tag,mode.upper(),MA5_runtag,i+1))) 2849 2850 # link the reconstructed event file to the run directory 2851 links_created.append(os.path.basename(reco_event_file)) 2852 parent_dir_name = os.path.basename(os.path.dirname(reco_event_file)) 2853 files.ln(pjoin(self.me_dir,'HTML',self.run_name, 2854 '%s_MA5_%s_ANALYSIS%s_%d'%(self.run_tag,mode.upper(), 2855 MA5_runtag,i+1),'Output','_reco_events',parent_dir_name,links_created[-1]), 2856 pjoin(self.me_dir,'Events',self.run_name)) 2857 2858 logger.info("MadAnalysis5 successfully completed the reconstruction "+ 2859 "'%s'. Links to the reconstructed event files are:"%MA5_runtag[6:]) 2860 for link in links_created: 2861 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,link)) 2862 continue 2863 2864 if MA5_runtag.upper()=='RECASTING': 2865 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\ 2866 %(mode.upper(),MA5_runtag),'Output','CLs_output_summary.dat') 2867 else: 2868 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\ 2869 %(mode.upper(),MA5_runtag),'Output','PDF','MadAnalysis5job_%d'%MA5_run_number,'main.pdf') 2870 has_pdf = True 2871 if not os.path.isfile(target): 2872 has_pdf = False 2873 2874 # Copy the PDF report or CLs in the Events/run directory. 2875 if MA5_runtag.upper()=='RECASTING': 2876 carboncopy_name = '%s_MA5_CLs.dat'%(self.run_tag) 2877 else: 2878 carboncopy_name = '%s_MA5_%s_analysis_%s.pdf'%( 2879 self.run_tag,mode,MA5_runtag) 2880 if has_pdf: 2881 shutil.copy(target, pjoin(self.me_dir,'Events',self.run_name,carboncopy_name)) 2882 else: 2883 logger.error('MadAnalysis5 failed to create PDF output') 2884 if MA5_runtag!='default': 2885 logger.info("MadAnalysis5 successfully completed the "+ 2886 "%s. Reported results are placed in:"%("analysis '%s'"%MA5_runtag 2887 if MA5_runtag.upper()!='RECASTING' else "recasting")) 2888 else: 2889 logger.info("MadAnalysis5 successfully completed the analysis."+ 2890 " Reported results are placed in:") 2891 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,carboncopy_name)) 2892 2893 anal_dir = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s' %(mode.upper(),MA5_runtag)) 2894 if not os.path.exists(anal_dir): 2895 logger.error('MadAnalysis5 failed to completed succesfully') 2896 return 2897 # Copy the entire analysis in the HTML directory 2898 shutil.move(anal_dir, pjoin(self.me_dir,'HTML',self.run_name, 2899 '%s_MA5_%s_ANALYSIS_%s'%(self.run_tag,mode.upper(),MA5_runtag))) 2900 2901 # Set the number of events and cross-section to the last one 2902 # (maybe do something smarter later) 2903 new_details={} 2904 for detail in ['nb_event','cross','error']: 2905 new_details[detail] = \ 2906 self.results[self.run_name].get_current_info()[detail] 2907 for detail in new_details: 2908 self.results.add_detail(detail,new_details[detail]) 2909 2910 self.update_status('Finished MA5 analyses.', level='madanalysis5_%s'%mode, 2911 makehtml=False) 2912 2913 #Update the banner 2914 self.banner.add(pjoin(self.me_dir, 'Cards', 2915 'madanalysis5_%s_card.dat'%mode)) 2916 banner_path = pjoin(self.me_dir,'Events', self.run_name, 2917 '%s_%s_banner.txt'%(self.run_name, self.run_tag)) 2918 self.banner.write(banner_path) 2919 2920 if not no_default: 2921 logger.info('Find more information about this run on the HTML local page') 2922 logger.info(' --> %s'%pjoin(self.me_dir,'index.html'))
2923 2924 ############################################################################ 2925 # End of MadAnalysis5 related function 2926 ############################################################################ 2927
2928 - def do_delphes(self, line):
2929 """ run delphes and make associate root file/plot """ 2930 2931 args = self.split_arg(line) 2932 # Check argument's validity 2933 if '--no_default' in args: 2934 no_default = True 2935 args.remove('--no_default') 2936 else: 2937 no_default = False 2938 2939 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')): 2940 logger.info('No delphes_card detected, so not run Delphes') 2941 return 2942 2943 # Check all arguments 2944 filepath = self.check_delphes(args, nodefault=no_default) 2945 if no_default and not filepath: 2946 return # no output file but nothing to do either. 2947 2948 self.update_status('prepare delphes run', level=None) 2949 2950 if os.path.exists(pjoin(self.options['delphes_path'], 'data')): 2951 delphes3 = False 2952 prog = '../bin/internal/run_delphes' 2953 if filepath and '.hepmc' in filepath[:-10]: 2954 raise self.InvalidCmd, 'delphes2 do not support hepmc' 2955 else: 2956 delphes3 = True 2957 prog = '../bin/internal/run_delphes3' 2958 2959 # Check that the delphes_card exists. If not copy the default and 2960 # ask for edition of the card. 2961 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')): 2962 if no_default: 2963 logger.info('No delphes_card detected, so not running Delphes') 2964 return 2965 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_card_default.dat'), 2966 pjoin(self.me_dir, 'Cards', 'delphes_card.dat')) 2967 logger.info('No delphes card found. Take the default one.') 2968 if not delphes3 and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')): 2969 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_trigger_default.dat'), 2970 pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')) 2971 if not (no_default or self.force): 2972 if delphes3: 2973 self.ask_edit_cards(['delphes_card.dat'], args) 2974 else: 2975 self.ask_edit_cards(['delphes_card.dat', 'delphes_trigger.dat'], args) 2976 2977 self.update_status('Running Delphes', level=None) 2978 2979 delphes_dir = self.options['delphes_path'] 2980 tag = self.run_tag 2981 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')): 2982 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_card.dat')) 2983 if not delphes3: 2984 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_trigger.dat')) 2985 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag))) 2986 2987 cross = self.results[self.run_name].get_current_info()['cross'] 2988 2989 delphes_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_delphes.log" % tag) 2990 if not self.cluster: 2991 clus = cluster.onecore 2992 else: 2993 clus = self.cluster 2994 clus.launch_and_wait(prog, 2995 argument= [delphes_dir, self.run_name, tag, str(cross), filepath], 2996 stdout=delphes_log, stderr=subprocess.STDOUT, 2997 cwd=pjoin(self.me_dir,'Events')) 2998 2999 if not os.path.exists(pjoin(self.me_dir, 'Events', 3000 self.run_name, '%s_delphes_events.lhco.gz' % tag))\ 3001 and not os.path.exists(pjoin(self.me_dir, 'Events', 3002 self.run_name, '%s_delphes_events.lhco' % tag)): 3003 logger.info('If you are interested in lhco output. please run root2lhco converter.') 3004 logger.info(' or edit bin/internal/run_delphes3 to run the converter automatically.') 3005 3006 3007 #eradir = self.options['exrootanalysis_path'] 3008 madir = self.options['madanalysis_path'] 3009 td = self.options['td_path'] 3010 3011 if os.path.exists(pjoin(self.me_dir, 'Events', 3012 self.run_name, '%s_delphes_events.lhco' % tag)): 3013 # Creating plots 3014 self.create_plot('Delphes') 3015 3016 if os.path.exists(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)): 3017 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)) 3018 3019 self.update_status('delphes done', level='delphes', makehtml=False)
3020 3021 3022 ############################################################################
3023 - def get_pid_final_initial_states(self):
3024 """Find the pid of all particles in the final and initial states""" 3025 pids = set() 3026 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 3027 'subproc.mg'))] 3028 nb_init = self.ninitial 3029 pat = re.compile(r'''DATA \(IDUP\(I,\d+\),I=1,\d+\)/([\+\-\d,\s]*)/''', re.I) 3030 for Pdir in subproc: 3031 text = open(pjoin(self.me_dir, 'SubProcesses', Pdir, 'born_leshouche.inc')).read() 3032 group = pat.findall(text) 3033 for particles in group: 3034 particles = particles.split(',') 3035 pids.update(set(particles)) 3036 3037 return pids
3038 3039 ############################################################################
3040 - def get_pdf_input_filename(self):
3041 """return the name of the file which is used by the pdfset""" 3042 3043 if self.options["cluster_local_path"] and \ 3044 os.path.exists(self.options["cluster_local_path"]) and \ 3045 self.options['run_mode'] ==1: 3046 # no need to transfer the pdf. 3047 return '' 3048 3049 def check_cluster(path): 3050 if not self.options["cluster_local_path"] or \ 3051 os.path.exists(self.options["cluster_local_path"]) or\ 3052 self.options['run_mode'] !=1: 3053 return path 3054 main = self.options["cluster_local_path"] 3055 if os.path.isfile(path): 3056 filename = os.path.basename(path) 3057 possible_path = [pjoin(main, filename), 3058 pjoin(main, "lhadpf", filename), 3059 pjoin(main, "Pdfdata", filename)] 3060 if any(os.path.exists(p) for p in possible_path): 3061 return " " 3062 else: 3063 return path
3064 3065 3066 if hasattr(self, 'pdffile') and self.pdffile: 3067 return self.pdffile 3068 else: 3069 for line in open(pjoin(self.me_dir,'Source','PDF','pdf_list.txt')): 3070 data = line.split() 3071 if len(data) < 4: 3072 continue 3073 if data[1].lower() == self.run_card['pdlabel'].lower(): 3074 self.pdffile = check_cluster(pjoin(self.me_dir, 'lib', 'Pdfdata', data[2])) 3075 return self.pdffile 3076 else: 3077 # possible when using lhapdf 3078 path = pjoin(self.me_dir, 'lib', 'PDFsets') 3079 if os.path.exists(path): 3080 self.pdffile = path 3081 else: 3082 self.pdffile = " " 3083 return self.pdffile 3084 3085 ############################################################################
3086 - def do_open(self, line):
3087 """Open a text file/ eps file / html file""" 3088 3089 args = self.split_arg(line) 3090 # Check Argument validity and modify argument to be the real path 3091 self.check_open(args) 3092 file_path = args[0] 3093 3094 misc.open_file(file_path)
3095 3096 ############################################################################
3097 - def do_set(self, line, log=True):
3098 """Set an option, which will be default for coming generations/outputs 3099 """ 3100 # cmd calls automaticaly post_set after this command. 3101 3102 3103 args = self.split_arg(line) 3104 # Check the validity of the arguments 3105 self.check_set(args) 3106 # Check if we need to save this in the option file 3107 if args[0] in self.options_configuration and '--no_save' not in args: 3108 self.do_save('options --auto') 3109 3110 if args[0] == "stdout_level": 3111 if args[1].isdigit(): 3112 logging.root.setLevel(int(args[1])) 3113 logging.getLogger('madgraph').setLevel(int(args[1])) 3114 else: 3115 logging.root.setLevel(eval('logging.' + args[1])) 3116 logging.getLogger('madgraph').setLevel(eval('logging.' + args[1])) 3117 if log: logger.info('set output information to level: %s' % args[1]) 3118 elif args[0] == "fortran_compiler": 3119 if args[1] == 'None': 3120 args[1] = None 3121 self.options['fortran_compiler'] = args[1] 3122 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'fortran') 3123 if current != args[1] and args[1] != None: 3124 misc.mod_compilator(self.me_dir, args[1], current, 'gfortran') 3125 elif args[0] == "cpp_compiler": 3126 if args[1] == 'None': 3127 args[1] = None 3128 self.options['cpp_compiler'] = args[1] 3129 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'cpp') 3130 if current != args[1] and args[1] != None: 3131 misc.mod_compilator(self.me_dir, args[1], current, 'cpp') 3132 elif args[0] == "run_mode": 3133 if not args[1] in [0,1,2,'0','1','2']: 3134 raise self.InvalidCmd, 'run_mode should be 0, 1 or 2.' 3135 self.cluster_mode = int(args[1]) 3136 self.options['run_mode'] = self.cluster_mode 3137 elif args[0] in ['cluster_type', 'cluster_queue', 'cluster_temp_path']: 3138 if args[1] == 'None': 3139 args[1] = None 3140 self.options[args[0]] = args[1] 3141 # cluster (re)-initialization done later 3142 # self.cluster update at the end of the routine 3143 elif args[0] in ['cluster_nb_retry', 'cluster_retry_wait', 'cluster_size']: 3144 self.options[args[0]] = int(args[1]) 3145 # self.cluster update at the end of the routine 3146 elif args[0] == 'nb_core': 3147 if args[1] == 'None': 3148 import multiprocessing 3149 self.nb_core = multiprocessing.cpu_count() 3150 self.options['nb_core'] = self.nb_core 3151 return 3152 if not args[1].isdigit(): 3153 raise self.InvalidCmd('nb_core should be a positive number') 3154 self.nb_core = int(args[1]) 3155 self.options['nb_core'] = self.nb_core 3156 elif args[0] == 'timeout': 3157 self.options[args[0]] = int(args[1]) 3158 elif args[0] == 'cluster_status_update': 3159 if '(' in args[1]: 3160 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 3161 data = data.replace('(','').replace(')','').replace(',',' ').split() 3162 first, second = data[:2] 3163 else: 3164 first, second = args[1:3] 3165 3166 self.options[args[0]] = (int(first), int(second)) 3167 elif args[0] == 'notification_center': 3168 if args[1] in ['None','True','False']: 3169 self.allow_notification_center = eval(args[1]) 3170 self.options[args[0]] = eval(args[1]) 3171 else: 3172 raise self.InvalidCmd('Not a valid value for notification_center') 3173 # True/False formatting 3174 elif args[0] in ['crash_on_error']: 3175 try: 3176 tmp = banner_mod.ConfigFile.format_variable(args[1], bool, 'crash_on_error') 3177 except: 3178 if args[1].lower() in ['never']: 3179 tmp = args[1].lower() 3180 else: 3181 raise 3182 self.options[args[0]] = tmp 3183 elif args[0] in self.options: 3184 if args[1] in ['None','True','False']: 3185 self.options[args[0]] = ast.literal_eval(args[1]) 3186 elif args[0].endswith('path'): 3187 if os.path.exists(args[1]): 3188 self.options[args[0]] = args[1] 3189 elif os.path.exists(pjoin(self.me_dir, args[1])): 3190 self.options[args[0]] = pjoin(self.me_dir, args[1]) 3191 else: 3192 raise self.InvalidCmd('Not a valid path: keep previous value: \'%s\'' % self.options[args[0]]) 3193 else: 3194 self.options[args[0]] = args[1]
3195
3196 - def post_set(self, stop, line):
3197 """Check if we need to save this in the option file""" 3198 try: 3199 args = self.split_arg(line) 3200 if 'cluster' in args[0] or args[0] == 'run_mode': 3201 self.configure_run_mode(self.options['run_mode']) 3202 3203 3204 # Check the validity of the arguments 3205 self.check_set(args) 3206 3207 if args[0] in self.options_configuration and '--no_save' not in args: 3208 self.exec_cmd('save options %s --auto' % args[0]) 3209 elif args[0] in self.options_madevent: 3210 logger.info('This option will be the default in any output that you are going to create in this session.') 3211 logger.info('In order to keep this changes permanent please run \'save options\'') 3212 return stop 3213 except self.InvalidCmd: 3214 return stop
3215
3216 - def configure_run_mode(self, run_mode):
3217 """change the way to submit job 0: single core, 1: cluster, 2: multicore""" 3218 3219 self.cluster_mode = run_mode 3220 self.options['run_mode'] = run_mode 3221 3222 if run_mode == 2: 3223 if not self.options['nb_core']: 3224 import multiprocessing 3225 self.options['nb_core'] = multiprocessing.cpu_count() 3226 nb_core = self.options['nb_core'] 3227 elif run_mode == 0: 3228 nb_core = 1 3229 3230 3231 3232 if run_mode in [0, 2]: 3233 self.cluster = cluster.MultiCore(**self.options) 3234 self.cluster.nb_core = nb_core 3235 #cluster_temp_path=self.options['cluster_temp_path'], 3236 3237 if self.cluster_mode == 1: 3238 opt = self.options 3239 cluster_name = opt['cluster_type'] 3240 if cluster_name in cluster.from_name: 3241 self.cluster = cluster.from_name[cluster_name](**opt) 3242 print "using cluster:", cluster_name 3243 else: 3244 print "cluster_class", cluster_name 3245 print self.plugin_path 3246 # Check if a plugin define this type of cluster 3247 # check for PLUGIN format 3248 cluster_class = misc.from_plugin_import(self.plugin_path, 3249 'new_cluster', cluster_name, 3250 info = 'cluster handling will be done with PLUGIN: %(plug)s' ) 3251 print type(cluster_class) 3252 if cluster_class: 3253 self.cluster = cluster_class(**self.options) 3254 else: 3255 raise self.InvalidCmd, "%s is not recognized as a supported cluster format." % cluster_name
3256 - def check_param_card(self, path, run=True, dependent=False):
3257 """ 3258 1) Check that no scan parameter are present 3259 2) Check that all the width are define in the param_card. 3260 - If a scan parameter is define. create the iterator and recall this fonction 3261 on the first element. 3262 - If some width are set on 'Auto', call the computation tools. 3263 - Check that no width are too small (raise a warning if this is the case) 3264 3) if dependent is on True check for dependent parameter (automatic for scan)""" 3265 3266 self.static_check_param_card(path, self, run=run, dependent=dependent) 3267 3268 card = param_card_mod.ParamCard(path) 3269 for param in card['decay']: 3270 width = param.value 3271 if width == 0: 3272 continue 3273 try: 3274 mass = card['mass'].get(param.lhacode).value 3275 except Exception: 3276 continue
3277 3278 3279 3280 @staticmethod
3281 - def static_check_param_card(path, interface, run=True, dependent=False, 3282 iterator_class=param_card_mod.ParamCardIterator):
3283 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M) 3284 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I) 3285 text = open(path).read() 3286 3287 if pattern_scan.search(text): 3288 if not isinstance(interface, cmd.CmdShell): 3289 # we are in web mode => forbid scan due to security risk 3290 raise Exception, "Scan are not allowed in web mode" 3291 # at least one scan parameter found. create an iterator to go trough the cards 3292 main_card = iterator_class(text) 3293 interface.param_card_iterator = main_card 3294 first_card = main_card.next(autostart=True) 3295 first_card.write(path) 3296 return CommonRunCmd.static_check_param_card(path, interface, run, dependent=True) 3297 3298 pdg_info = pattern_width.findall(text) 3299 if pdg_info: 3300 if run: 3301 logger.info('Computing the width set on auto in the param_card.dat') 3302 has_nlo = any(nlo.lower()=="@nlo" for _,nlo in pdg_info) 3303 pdg = [pdg for pdg,nlo in pdg_info] 3304 if not has_nlo: 3305 line = '%s' % (' '.join(pdg)) 3306 else: 3307 line = '%s --nlo' % (' '.join(pdg)) 3308 CommonRunCmd.static_compute_widths(line, interface, path) 3309 else: 3310 logger.info('''Some width are on Auto in the card. 3311 Those will be computed as soon as you have finish the edition of the cards. 3312 If you want to force the computation right now and being able to re-edit 3313 the cards afterwards, you can type \"compute_wdiths\".''') 3314 3315 card = param_card_mod.ParamCard(path) 3316 if dependent: 3317 AskforEditCard.update_dependent(interface, interface.me_dir, card, path, timer=20) 3318 3319 for param in card['decay']: 3320 width = param.value 3321 if width == 0: 3322 continue 3323 try: 3324 mass = card['mass'].get(param.lhacode).value 3325 except Exception: 3326 logger.warning('Missing mass in the lhef file (%s) . Please fix this (use the "update missing" command if needed)', param.lhacode[0]) 3327 continue 3328 if mass and abs(width/mass) < 1e-12: 3329 if hasattr(interface, 'run_card') and isinstance(interface.run_card, banner_mod.RunCardLO): 3330 if interface.run_card['small_width_treatment'] < 1e-12: 3331 logger.error('The width of particle %s is too small for an s-channel resonance (%s) and the small_width_paramer is too small to prevent numerical issues. If you have this particle in an s-channel, this is likely to create numerical instabilities .', param.lhacode[0], width) 3332 else: 3333 logger.error('The width of particle %s is too small for an s-channel resonance (%s). If you have this particle in an s-channel, this is likely to create numerical instabilities .', param.lhacode[0], width) 3334 if CommonRunCmd.sleep_for_error: 3335 time.sleep(5) 3336 CommonRunCmd.sleep_for_error = False 3337 elif not mass and width: 3338 logger.error('The width of particle %s is different of zero for a massless particle.', param.lhacode[0]) 3339 if CommonRunCmd.sleep_for_error: 3340 time.sleep(5) 3341 CommonRunCmd.sleep_for_error = False 3342 return
3343 3344 @staticmethod
3345 - def static_compute_widths(line, interface, path=None):
3346 """ factory to try to find a way to call the static method""" 3347 3348 handled = True 3349 if isinstance(interface, CommonRunCmd): 3350 if path: 3351 line = '%s %s' % (line, path) 3352 interface.do_compute_widths(line) 3353 else: 3354 handled = False 3355 3356 if handled: 3357 return 3358 3359 if hasattr(interface, 'do_compute_width'): 3360 interface.do_compute_widths('%s --path=%s' % (line, path)) 3361 elif hasattr(interface, 'mother') and interface.mother and isinstance(interface, CommonRunCmd): 3362 return CommonRunCmd.static_compute_width(line, interface.mother, path) 3363 elif not MADEVENT: 3364 from madgraph.interface.master_interface import MasterCmd 3365 cmd = MasterCmd() 3366 interface.define_child_cmd_interface(cmd, interface=False) 3367 if hasattr(interface, 'options'): 3368 cmd.options.update(interface.options) 3369 try: 3370 cmd.exec_cmd('set automatic_html_opening False --no_save') 3371 except Exception: 3372 pass 3373 3374 model = interface.get_model() 3375 3376 3377 line = 'compute_widths %s --path=%s' % (line, path) 3378 cmd.exec_cmd(line, model=model) 3379 interface.child = None 3380 del cmd 3381 return 3382 3383 3384 3385 raise Exception, 'fail to find a way to handle Auto width'
3386 3387
3388 - def store_scan_result(self):
3389 """return the information that need to be kept for the scan summary. 3390 Auto-width are automatically added.""" 3391 3392 return {'cross': self.results.current['cross']}
3393 3394
3395 - def add_error_log_in_html(self, errortype=None):
3396 """If a ME run is currently running add a link in the html output""" 3397 3398 # Be very carefull to not raise any error here (the traceback 3399 #will be modify in that case.) 3400 if hasattr(self, 'results') and hasattr(self.results, 'current') and\ 3401 self.results.current and 'run_name' in self.results.current and \ 3402 hasattr(self, 'me_dir'): 3403 name = self.results.current['run_name'] 3404 tag = self.results.current['tag'] 3405 self.debug_output = pjoin(self.me_dir, '%s_%s_debug.log' % (name,tag)) 3406 if errortype: 3407 self.results.current.debug = errortype 3408 else: 3409 self.results.current.debug = self.debug_output 3410 3411 else: 3412 #Force class default 3413 self.debug_output = CommonRunCmd.debug_output 3414 if os.path.exists('ME5_debug') and not 'ME5_debug' in self.debug_output: 3415 try: 3416 os.remove('ME5_debug') 3417 except Exception: 3418 pass 3419 if not 'ME5_debug' in self.debug_output: 3420 os.system('ln -s %s ME5_debug &> /dev/null' % self.debug_output)
3421 3422
3423 - def do_quit(self, line):
3424 """Not in help: exit """ 3425 3426 if not self.force_run: 3427 try: 3428 os.remove(pjoin(self.me_dir,'RunWeb')) 3429 except Exception: 3430 pass 3431 3432 try: 3433 self.store_result() 3434 except Exception: 3435 # If nothing runs they they are no result to update 3436 pass 3437 3438 try: 3439 self.update_status('', level=None) 3440 except Exception, error: 3441 pass 3442 3443 self.gen_card_html() 3444 return super(CommonRunCmd, self).do_quit(line)
3445 3446 # Aliases 3447 do_EOF = do_quit 3448 do_exit = do_quit 3449
3450 - def __del__(self):
3451 """try to remove RunWeb?""" 3452 3453 if not self.stop_for_runweb and not self.force_run: 3454 try: 3455 os.remove(pjoin(self.me_dir,'RunWeb')) 3456 except Exception: 3457 pass
3458 3459
3460 - def update_status(self, status, level, makehtml=True, force=True, 3461 error=False, starttime = None, update_results=True, 3462 print_log=True):
3463 """ update the index status """ 3464 3465 if makehtml and not force: 3466 if hasattr(self, 'next_update') and time.time() < self.next_update: 3467 return 3468 else: 3469 self.next_update = time.time() + 3 3470 3471 if print_log: 3472 if isinstance(status, str): 3473 if '<br>' not in status: 3474 logger.info(status) 3475 elif starttime: 3476 running_time = misc.format_timer(time.time()-starttime) 3477 logger.info(' Idle: %s, Running: %s, Completed: %s [ %s ]' % \ 3478 (status[0], status[1], status[2], running_time)) 3479 else: 3480 logger.info(' Idle: %s, Running: %s, Completed: %s' % status[:3]) 3481 3482 if isinstance(status, str) and status.startswith('\x1b['): 3483 status = status[status.index('m')+1:-7] 3484 if 'arXiv' in status: 3485 if '[' in status: 3486 status = status.split('[',1)[0] 3487 else: 3488 status = status.split('arXiv',1)[0] 3489 3490 if update_results: 3491 self.results.update(status, level, makehtml=makehtml, error=error)
3492 3493 ############################################################################
3494 - def keep_cards(self, need_card=[], ignore=[]):
3495 """Ask the question when launching generate_events/multi_run""" 3496 3497 check_card = ['pythia_card.dat', 'pgs_card.dat','delphes_card.dat', 3498 'delphes_trigger.dat', 'madspin_card.dat', 'shower_card.dat', 3499 'reweight_card.dat','pythia8_card.dat', 3500 'madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat', 3501 'plot_card.dat'] 3502 3503 cards_path = pjoin(self.me_dir,'Cards') 3504 for card in check_card: 3505 if card in ignore or (ignore == ['*'] and card not in need_card): 3506 continue 3507 if card not in need_card: 3508 if os.path.exists(pjoin(cards_path, card)): 3509 files.mv(pjoin(cards_path, card), pjoin(cards_path, '.%s' % card)) 3510 else: 3511 if not os.path.exists(pjoin(cards_path, card)): 3512 if os.path.exists(pjoin(cards_path, '.%s' % card)): 3513 files.mv(pjoin(cards_path, '.%s' % card), pjoin(cards_path, card)) 3514 else: 3515 default = card.replace('.dat', '_default.dat') 3516 files.cp(pjoin(cards_path, default),pjoin(cards_path, card))
3517 3518 ############################################################################
3519 - def set_configuration(self, config_path=None, final=True, initdir=None, amcatnlo=False):
3520 """ assign all configuration variable from file 3521 ./Cards/mg5_configuration.txt. assign to default if not define """ 3522 3523 if not hasattr(self, 'options') or not self.options: 3524 self.options = dict(self.options_configuration) 3525 self.options.update(self.options_madgraph) 3526 self.options.update(self.options_madevent) 3527 3528 if not config_path: 3529 if os.environ.has_key('MADGRAPH_BASE'): 3530 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 3531 self.set_configuration(config_path=config_path, final=False) 3532 if 'HOME' in os.environ: 3533 config_path = pjoin(os.environ['HOME'],'.mg5', 3534 'mg5_configuration.txt') 3535 if os.path.exists(config_path): 3536 self.set_configuration(config_path=config_path, final=False) 3537 if amcatnlo: 3538 me5_config = pjoin(self.me_dir, 'Cards', 'amcatnlo_configuration.txt') 3539 else: 3540 me5_config = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 3541 self.set_configuration(config_path=me5_config, final=False, initdir=self.me_dir) 3542 3543 if self.options.has_key('mg5_path') and self.options['mg5_path']: 3544 MG5DIR = self.options['mg5_path'] 3545 config_file = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 3546 self.set_configuration(config_path=config_file, final=False,initdir=MG5DIR) 3547 else: 3548 self.options['mg5_path'] = None 3549 return self.set_configuration(config_path=me5_config, final=final,initdir=self.me_dir) 3550 3551 config_file = open(config_path) 3552 3553 # read the file and extract information 3554 logger.info('load configuration from %s ' % config_file.name) 3555 for line in config_file: 3556 3557 if '#' in line: 3558 line = line.split('#',1)[0] 3559 line = line.replace('\n','').replace('\r\n','') 3560 try: 3561 name, value = line.split('=') 3562 except ValueError: 3563 pass 3564 else: 3565 name = name.strip() 3566 value = value.strip() 3567 if name.endswith('_path') and not name.startswith('cluster'): 3568 path = value 3569 if os.path.isdir(path): 3570 self.options[name] = os.path.realpath(path) 3571 continue 3572 if not initdir: 3573 continue 3574 path = pjoin(initdir, value) 3575 if os.path.isdir(path): 3576 self.options[name] = os.path.realpath(path) 3577 continue 3578 else: 3579 self.options[name] = value 3580 if value.lower() == "none": 3581 self.options[name] = None 3582 3583 if not final: 3584 return self.options # the return is usefull for unittest 3585 3586 # Treat each expected input 3587 # delphes/pythia/... path 3588 for key in self.options: 3589 # Final cross check for the path 3590 if key.endswith('path') and not key.startswith("cluster"): 3591 path = self.options[key] 3592 if path is None: 3593 continue 3594 if os.path.isdir(path): 3595 self.options[key] = os.path.realpath(path) 3596 continue 3597 path = pjoin(self.me_dir, self.options[key]) 3598 if os.path.isdir(path): 3599 self.options[key] = os.path.realpath(path) 3600 continue 3601 elif self.options.has_key('mg5_path') and self.options['mg5_path']: 3602 path = pjoin(self.options['mg5_path'], self.options[key]) 3603 if os.path.isdir(path): 3604 self.options[key] = os.path.realpath(path) 3605 continue 3606 self.options[key] = None 3607 elif key.startswith('cluster') and key != 'cluster_status_update': 3608 if key in ('cluster_nb_retry','cluster_wait_retry'): 3609 self.options[key] = int(self.options[key]) 3610 if hasattr(self,'cluster'): 3611 del self.cluster 3612 pass 3613 elif key == 'automatic_html_opening': 3614 if self.options[key] in ['False', 'True']: 3615 self.options[key] =ast.literal_eval(self.options[key]) 3616 elif key == "notification_center": 3617 if self.options[key] in ['False', 'True']: 3618 self.allow_notification_center =ast.literal_eval(self.options[key]) 3619 self.options[key] =ast.literal_eval(self.options[key]) 3620 elif key not in ['text_editor','eps_viewer','web_browser','stdout_level', 3621 'complex_mass_scheme', 'gauge', 'group_subprocesses']: 3622 # Default: try to set parameter 3623 try: 3624 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 3625 except self.InvalidCmd: 3626 logger.warning("Option %s from config file not understood" \ 3627 % key) 3628 3629 # Configure the way to open a file: 3630 misc.open_file.configure(self.options) 3631 3632 # update the path to the PLUGIN directory of MG% 3633 if MADEVENT and 'mg5_path' in self.options and self.options['mg5_path']: 3634 mg5dir = self.options['mg5_path'] 3635 if mg5dir not in sys.path: 3636 sys.path.append(mg5dir) 3637 if pjoin(mg5dir, 'PLUGIN') not in self.plugin_path: 3638 self.plugin_path.append(pjoin(mg5dir,'PLUGIN')) 3639 3640 self.configure_run_mode(self.options['run_mode']) 3641 return self.options
3642 3643 @staticmethod
3644 - def find_available_run_name(me_dir):
3645 """ find a valid run_name for the current job """ 3646 3647 name = 'run_%02d' 3648 data = [int(s[4:j]) for s in os.listdir(pjoin(me_dir,'Events')) for 3649 j in range(4,len(s)+1) if \ 3650 s.startswith('run_') and s[4:j].isdigit()] 3651 return name % (max(data+[0])+1)
3652 3653 3654 ############################################################################
3655 - def do_decay_events(self,line):
3656 """Require MG5 directory: decay events with spin correlations 3657 """ 3658 3659 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')): 3660 return 3661 3662 # First need to load MadSpin 3663 # Check that MG5 directory is present . 3664 if MADEVENT and not self.options['mg5_path']: 3665 raise self.InvalidCmd, '''The module decay_events requires that MG5 is installed on the system. 3666 You can install it and set its path in ./Cards/me5_configuration.txt''' 3667 elif MADEVENT: 3668 sys.path.append(self.options['mg5_path']) 3669 try: 3670 import MadSpin.decay as decay 3671 import MadSpin.interface_madspin as interface_madspin 3672 except ImportError: 3673 if __debug__: 3674 raise 3675 else: 3676 raise self.ConfigurationError, '''Can\'t load MadSpin 3677 The variable mg5_path might not be correctly configured.''' 3678 3679 self.update_status('Running MadSpin', level='madspin') 3680 if not '-from_cards' in line and '-f' not in line: 3681 self.keep_cards(['madspin_card.dat'], ignore=['*']) 3682 self.ask_edit_cards(['madspin_card.dat'], 'fixed', plot=False) 3683 self.help_decay_events(skip_syntax=True) 3684 3685 # load the name of the event file 3686 args = self.split_arg(line) 3687 self.check_decay_events(args) 3688 # args now alway content the path to the valid files 3689 madspin_cmd = interface_madspin.MadSpinInterface(args[0]) 3690 # pass current options to the interface 3691 madspin_cmd.mg5cmd.options.update(self.options) 3692 for key, value in self.options.items(): 3693 if isinstance(value, str): 3694 madspin_cmd.mg5cmd.exec_cmd( 'set %s %s --no_save' %(key,value), errorhandling=False, printcmd=False, precmd=False, postcmd=True) 3695 madspin_cmd.cluster = self.cluster 3696 3697 madspin_cmd.update_status = lambda *x,**opt: self.update_status(*x, level='madspin',**opt) 3698 3699 path = pjoin(self.me_dir, 'Cards', 'madspin_card.dat') 3700 3701 madspin_cmd.import_command_file(path) 3702 3703 # create a new run_name directory for this output 3704 i = 1 3705 while os.path.exists(pjoin(self.me_dir,'Events', '%s_decayed_%i' % (self.run_name,i))): 3706 i+=1 3707 new_run = '%s_decayed_%i' % (self.run_name,i) 3708 evt_dir = pjoin(self.me_dir, 'Events') 3709 3710 os.mkdir(pjoin(evt_dir, new_run)) 3711 current_file = args[0].replace('.lhe', '_decayed.lhe') 3712 new_file = pjoin(evt_dir, new_run, os.path.basename(args[0])) 3713 if not os.path.exists(current_file): 3714 if os.path.exists(current_file+'.gz'): 3715 current_file += '.gz' 3716 new_file += '.gz' 3717 elif current_file.endswith('.gz') and os.path.exists(current_file[:-3]): 3718 current_file = current_file[:-3] 3719 new_file = new_file[:-3] 3720 else: 3721 logger.error('MadSpin fails to create any decayed file.') 3722 return 3723 3724 files.mv(current_file, new_file) 3725 logger.info("The decayed event file has been moved to the following location: ") 3726 logger.info(new_file) 3727 3728 if hasattr(self, 'results'): 3729 current = self.results.current 3730 nb_event = self.results.current['nb_event'] 3731 if not nb_event: 3732 current = self.results[self.run_name][0] 3733 nb_event = current['nb_event'] 3734 3735 cross = current['cross'] 3736 error = current['error'] 3737 self.results.add_run( new_run, self.run_card) 3738 self.results.add_detail('nb_event', int(nb_event*madspin_cmd.efficiency)) 3739 self.results.add_detail('cross', madspin_cmd.cross)#cross * madspin_cmd.branching_ratio) 3740 self.results.add_detail('error', madspin_cmd.error+ cross * madspin_cmd.err_branching_ratio) 3741 self.results.add_detail('run_mode', current['run_mode']) 3742 self.to_store.append("event") 3743 3744 self.run_name = new_run 3745 self.banner = madspin_cmd.banner 3746 self.banner.add(path) 3747 self.banner.write(pjoin(self.me_dir,'Events',self.run_name, '%s_%s_banner.txt' % 3748 (self.run_name, self.run_tag))) 3749 self.update_status('MadSpin Done', level='parton', makehtml=False) 3750 if 'unweighted' in os.path.basename(args[0]): 3751 self.create_plot('parton')
3752
3753 - def complete_decay_events(self, text, line, begidx, endidx):
3754 args = self.split_arg(line[0:begidx], error=False) 3755 if len(args) == 1: 3756 return self.complete_plot(text, line, begidx, endidx) 3757 else: 3758 return
3759
3760 - def complete_print_results(self,text, line, begidx, endidx):
3761 "Complete the print results command" 3762 args = self.split_arg(line[0:begidx], error=False) 3763 if len(args) == 1: 3764 #return valid run_name 3765 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'), 3766 pjoin(self.me_dir, 'Events')) 3767 3768 data = [n.rsplit('/',2)[1] for n in data] 3769 tmp1 = self.list_completion(text, data) 3770 return tmp1 3771 else: 3772 data = misc.glob('*_pythia_events.hep.gz', pjoin(self.me_dir, 'Events', args[0])) 3773 data = [os.path.basename(p).rsplit('_',1)[0] for p in data] 3774 data += ["--mode=a", "--mode=w", "--path=", "--format=short"] 3775 tmp1 = self.list_completion(text, data) 3776 return tmp1
3777
3778 - def help_print_result(self):
3779 logger.info("syntax: print_result [RUN] [TAG] [options]") 3780 logger.info("-- show in text format the status of the run (cross-section/nb-event/...)") 3781 logger.info("--path= defines the path of the output file.") 3782 logger.info("--mode=a allow to add the information at the end of the file.") 3783 logger.info("--format=short (only if --path is define)") 3784 logger.info(" allows to have a multi-column output easy to parse")
3785 3786 3787 ############################################################################
3788 - def find_model_name(self):
3789 """ return the model name """ 3790 if hasattr(self, 'model_name'): 3791 return self.model_name 3792 3793 def join_line(old, to_add): 3794 if old.endswith('\\'): 3795 newline = old[:-1] + to_add 3796 else: 3797 newline = old + line 3798 return newline
3799 3800 3801 3802 model = 'sm' 3803 proc = [] 3804 continuation_line = None 3805 for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')): 3806 line = line.split('#')[0] 3807 if continuation_line: 3808 line = line.strip() 3809 if continuation_line == 'model': 3810 model = join_line(model, line) 3811 elif continuation_line == 'proc': 3812 proc = join_line(proc, line) 3813 if not line.endswith('\\'): 3814 continuation_line = None 3815 continue 3816 #line = line.split('=')[0] 3817 if line.startswith('import') and 'model' in line: 3818 model = line.split()[2] 3819 proc = [] 3820 if model.endswith('\\'): 3821 continuation_line = 'model' 3822 elif line.startswith('generate'): 3823 proc.append(line.split(None,1)[1]) 3824 if proc[-1].endswith('\\'): 3825 continuation_line = 'proc' 3826 elif line.startswith('add process'): 3827 proc.append(line.split(None,2)[2]) 3828 if proc[-1].endswith('\\'): 3829 continuation_line = 'proc' 3830 self.model = model 3831 self.process = proc 3832 return model 3833 3834 3835 ############################################################################
3836 - def do_check_events(self, line):
3837 """ Run some sanity check on the generated events.""" 3838 3839 # Check that MG5 directory is present . 3840 if MADEVENT and not self.options['mg5_path']: 3841 raise self.InvalidCmd, '''The module reweight requires that MG5 is installed on the system. 3842 You can install it and set its path in ./Cards/me5_configuration.txt''' 3843 elif MADEVENT: 3844 sys.path.append(self.options['mg5_path']) 3845 try: 3846 import madgraph.interface.reweight_interface as reweight_interface 3847 except ImportError: 3848 raise self.ConfigurationError, '''Can\'t load Reweight module. 3849 The variable mg5_path might not be correctly configured.''' 3850 3851 3852 # load the name of the event file 3853 args = self.split_arg(line) 3854 self.check_check_events(args) 3855 # args now alway content the path to the valid files 3856 reweight_cmd = reweight_interface.ReweightInterface(args[0], allow_madspin=True) 3857 reweight_cmd.mother = self 3858 self.update_status('Running check on events', level='check') 3859 3860 reweight_cmd.check_events()
3861 3862 ############################################################################
3863 - def complete_check_events(self, text, line, begidx, endidx):
3864 args = self.split_arg(line[0:begidx], error=False) 3865 3866 if len(args) == 1 and os.path.sep not in text: 3867 #return valid run_name 3868 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events')) 3869 data = [n.rsplit('/',2)[1] for n in data] 3870 return self.list_completion(text, data, line) 3871 else: 3872 return self.path_completion(text, 3873 os.path.join('.',*[a for a in args \ 3874 if a.endswith(os.path.sep)]))
3875
3876 - def complete_reweight(self,text, line, begidx, endidx):
3877 "Complete the pythia command" 3878 args = self.split_arg(line[0:begidx], error=False) 3879 3880 #return valid run_name 3881 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events')) 3882 data = list(set([n.rsplit('/',2)[1] for n in data])) 3883 if not '-f' in args: 3884 data.append('-f') 3885 tmp1 = self.list_completion(text, data) 3886 return tmp1
3887 3888 3889
3890 - def complete_compute_widths(self, text, line, begidx, endidx, formatting=True):
3891 "Complete the compute_widths command" 3892 3893 args = self.split_arg(line[0:begidx]) 3894 3895 if args[-1] in ['--path=', '--output=']: 3896 completion = {'path': self.path_completion(text)} 3897 elif line[begidx-1] == os.path.sep: 3898 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)]) 3899 if current_dir.startswith('--path='): 3900 current_dir = current_dir[7:] 3901 if current_dir.startswith('--output='): 3902 current_dir = current_dir[9:] 3903 completion = {'path': self.path_completion(text, current_dir)} 3904 else: 3905 completion = {} 3906 completion['options'] = self.list_completion(text, 3907 ['--path=', '--output=', '--min_br=0.\$', '--nlo', 3908 '--precision_channel=0.\$', '--body_decay=']) 3909 3910 return self.deal_multiple_categories(completion, formatting)
3911 3912
3913 - def update_make_opts(self):
3914 """update the make_opts file writing the environmental variables 3915 stored in make_opts_var""" 3916 make_opts = os.path.join(self.me_dir, 'Source', 'make_opts') 3917 3918 # Set some environment variables common to all interfaces 3919 if not hasattr(self,'options') or not 'pythia8_path' in self.options or \ 3920 not self.options['pythia8_path'] or \ 3921 not os.path.isfile(pjoin(self.options['pythia8_path'],'bin','pythia8-config')): 3922 self.make_opts_var['PYTHIA8_PATH']='NotInstalled' 3923 else: 3924 self.make_opts_var['PYTHIA8_PATH']=self.options['pythia8_path'] 3925 3926 self.make_opts_var['MG5AMC_VERSION'] = misc.get_pkg_info()['version'] 3927 3928 return self.update_make_opts_full(make_opts, self.make_opts_var)
3929 3930 @staticmethod
3931 - def update_make_opts_full(path, def_variables, keep_old=True):
3932 """update the make_opts file writing the environmental variables 3933 of def_variables. 3934 if a value of the dictionary is None then it is not written. 3935 """ 3936 make_opts = path 3937 pattern = re.compile(r'^(\w+)\s*=\s*(.*)$',re.DOTALL) 3938 diff = False # set to True if one varible need to be updated 3939 #if on False the file is not modify 3940 3941 tag = '#end_of_make_opts_variables\n' 3942 make_opts_variable = True # flag to say if we are in edition area or not 3943 content = [] 3944 variables = dict(def_variables) 3945 need_keys = variables.keys() 3946 for line in open(make_opts): 3947 line = line.strip() 3948 if make_opts_variable: 3949 if line.startswith('#') or not line: 3950 if line.startswith('#end_of_make_opts_variables'): 3951 make_opts_variable = False 3952 continue 3953 elif pattern.search(line): 3954 key, value = pattern.search(line).groups() 3955 if key not in variables: 3956 variables[key] = value 3957 elif value != variables[key]: 3958 diff=True 3959 else: 3960 need_keys.remove(key) 3961 else: 3962 make_opts_variable = False 3963 content.append(line) 3964 else: 3965 content.append(line) 3966 3967 if need_keys: 3968 diff=True #This means that new definition are added to the file. 3969 3970 content_variables = '\n'.join('%s=%s' % (k,v) for k, v in variables.items() if v is not None) 3971 content_variables += '\n%s' % tag 3972 3973 if diff: 3974 with open(make_opts, 'w') as fsock: 3975 fsock.write(content_variables + '\n'.join(content)) 3976 return
3977 3978 3979 # lhapdf-related functions 4009 4010
4011 - def get_characteristics(self, path=None):
4012 """reads the proc_characteristics file and initialises the correspondant 4013 dictionary""" 4014 4015 if not path: 4016 path = os.path.join(self.me_dir, 'SubProcesses', 'proc_characteristics') 4017 4018 self.proc_characteristics = banner_mod.ProcCharacteristic(path) 4019 return self.proc_characteristics
4020 4021
4022 - def copy_lhapdf_set(self, lhaid_list, pdfsets_dir, require_local=True):
4023 """copy (if needed) the lhapdf set corresponding to the lhaid in lhaid_list 4024 into lib/PDFsets. 4025 if require_local is False, just ensure that the pdf is in pdfsets_dir 4026 """ 4027 4028 if not hasattr(self, 'lhapdf_pdfsets'): 4029 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsets_dir) 4030 4031 pdfsetname=set() 4032 for lhaid in lhaid_list: 4033 if isinstance(lhaid, str) and lhaid.isdigit(): 4034 lhaid = int(lhaid) 4035 if isinstance(lhaid, (int,float)): 4036 try: 4037 if lhaid in self.lhapdf_pdfsets: 4038 pdfsetname.add(self.lhapdf_pdfsets[lhaid]['filename']) 4039 else: 4040 raise MadGraph5Error('lhaid %s not valid input number for the current lhapdf' % lhaid ) 4041 except KeyError: 4042 if self.lhapdf_version.startswith('5'): 4043 raise MadGraph5Error(\ 4044 ('invalid lhaid set in th run_card: %d .\nPlease note that some sets' % lhaid) + \ 4045 '(eg MSTW 90%CL error sets) \nare not available in aMC@NLO + LHAPDF 5.x.x') 4046 else: 4047 logger.debug('%d not found in pdfsets.index' % lhaid) 4048 else: 4049 pdfsetname.add(lhaid) 4050 4051 # check if the file exists, otherwise install it: 4052 # also check that the PDFsets dir exists, otherwise create it. 4053 # if fails, install the lhapdfset into lib/PDFsets 4054 if not os.path.isdir(pdfsets_dir): 4055 try: 4056 os.mkdir(pdfsets_dir) 4057 except OSError: 4058 pdfsets_dir = pjoin(self.me_dir, 'lib', 'PDFsets') 4059 elif os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets')): 4060 #clean previous set of pdf used 4061 for name in os.listdir(pjoin(self.me_dir, 'lib', 'PDFsets')): 4062 if name not in pdfsetname: 4063 try: 4064 if os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', name)): 4065 shutil.rmtree(pjoin(self.me_dir, 'lib', 'PDFsets', name)) 4066 else: 4067 os.remove(pjoin(self.me_dir, 'lib', 'PDFsets', name)) 4068 except Exception, error: 4069 logger.debug('%s', error) 4070 4071 if self.options["cluster_local_path"]: 4072 lhapdf_cluster_possibilities = [self.options["cluster_local_path"], 4073 pjoin(self.options["cluster_local_path"], "lhapdf"), 4074 pjoin(self.options["cluster_local_path"], "lhapdf", "pdfsets"), 4075 pjoin(self.options["cluster_local_path"], "..", "lhapdf"), 4076 pjoin(self.options["cluster_local_path"], "..", "lhapdf", "pdfsets"), 4077 pjoin(self.options["cluster_local_path"], "..", "lhapdf","pdfsets", "6.1") 4078 ] 4079 else: 4080 lhapdf_cluster_possibilities = [] 4081 4082 for pdfset in pdfsetname: 4083 # Check if we need to copy the pdf 4084 if self.options["cluster_local_path"] and self.options["run_mode"] == 1 and \ 4085 any((os.path.exists(pjoin(d, pdfset)) for d in lhapdf_cluster_possibilities)): 4086 4087 os.environ["LHAPATH"] = [d for d in lhapdf_cluster_possibilities if os.path.exists(pjoin(d, pdfset))][0] 4088 os.environ["CLUSTER_LHAPATH"] = os.environ["LHAPATH"] 4089 # no need to copy it 4090 if os.path.exists(pjoin(pdfsets_dir, pdfset)): 4091 try: 4092 if os.path.isdir(pjoin(pdfsets_dir, name)): 4093 shutil.rmtree(pjoin(pdfsets_dir, name)) 4094 else: 4095 os.remove(pjoin(pdfsets_dir, name)) 4096 except Exception, error: 4097 logger.debug('%s', error) 4098 if not require_local and (os.path.exists(pjoin(pdfsets_dir, pdfset)) or \ 4099 os.path.isdir(pjoin(pdfsets_dir, pdfset))): 4100 continue 4101 #check that the pdfset is not already there 4102 elif not os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)) and \ 4103 not os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)): 4104 4105 if pdfset and not os.path.exists(pjoin(pdfsets_dir, pdfset)): 4106 self.install_lhapdf_pdfset(pdfsets_dir, pdfset) 4107 4108 if os.path.exists(pjoin(pdfsets_dir, pdfset)): 4109 files.cp(pjoin(pdfsets_dir, pdfset), pjoin(self.me_dir, 'lib', 'PDFsets')) 4110 elif os.path.exists(pjoin(os.path.dirname(pdfsets_dir), pdfset)): 4111 files.cp(pjoin(os.path.dirname(pdfsets_dir), pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4112
4113 - def install_lhapdf_pdfset(self, pdfsets_dir, filename):
4114 """idownloads and install the pdfset filename in the pdfsets_dir""" 4115 lhapdf_version = self.get_lhapdf_version() 4116 local_path = pjoin(self.me_dir, 'lib', 'PDFsets') 4117 return self.install_lhapdf_pdfset_static(self.options['lhapdf'], 4118 pdfsets_dir, filename, 4119 lhapdf_version=lhapdf_version, 4120 alternate_path=local_path)
4121 4122 4123 @staticmethod
4124 - def install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir, filename, 4125 lhapdf_version=None, alternate_path=None):
4126 """idownloads and install the pdfset filename in the pdfsets_dir. 4127 Version which can be used independently of the class. 4128 local path is used if the global installation fails. 4129 """ 4130 4131 if not lhapdf_version: 4132 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config) 4133 4134 if not pdfsets_dir: 4135 pdfsets_dir = CommonRunCmd.get_lhapdf_pdfsetsdir_static(lhapdf_config, lhapdf_version) 4136 4137 if isinstance(filename, int): 4138 pdf_info = CommonRunCmd.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version) 4139 filename = pdf_info[filename]['filename'] 4140 4141 if os.path.exists(pjoin(pdfsets_dir, filename)): 4142 logger.debug('%s is already present in %s', filename, pdfsets_dir) 4143 return 4144 4145 logger.info('Trying to download %s' % filename) 4146 4147 4148 if lhapdf_version.startswith('5.'): 4149 4150 # use the lhapdf-getdata command, which is in the same path as 4151 # lhapdf-config 4152 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf-getdata')) 4153 misc.call([getdata, filename], cwd = pdfsets_dir) 4154 4155 elif lhapdf_version.startswith('6.'): 4156 # use the "lhapdf install xxx" command, which is in the same path as 4157 # lhapdf-config 4158 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf')) 4159 4160 if lhapdf_version.startswith('6.1'): 4161 misc.call([getdata, 'install', filename], cwd = pdfsets_dir) 4162 else: 4163 #for python 6.2.1, import lhapdf should be working to download pdf 4164 lhapdf = misc.import_python_lhapdf(lhapdf_config) 4165 if lhapdf: 4166 if 'PYTHONPATH' in os.environ: 4167 os.environ['PYTHONPATH']+= ':' + os.path.dirname(lhapdf.__file__) 4168 else: 4169 os.environ['PYTHONPATH'] = ':'.join(sys.path) + ':' + os.path.dirname(lhapdf.__file__) 4170 else: 4171 logger.warning('lhapdf 6.2.1 requires python integration in order to download pdf set. Trying anyway') 4172 misc.call([getdata, 'install', filename], cwd = pdfsets_dir) 4173 4174 else: 4175 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version) 4176 4177 # check taht the file has been installed in the global dir 4178 if os.path.exists(pjoin(pdfsets_dir, filename)) or \ 4179 os.path.isdir(pjoin(pdfsets_dir, filename)): 4180 logger.info('%s successfully downloaded and stored in %s' \ 4181 % (filename, pdfsets_dir)) 4182 4183 #otherwise (if v5) save it locally 4184 elif lhapdf_version.startswith('5.'): 4185 logger.warning('Could not download %s into %s. Trying to save it locally' \ 4186 % (filename, pdfsets_dir)) 4187 CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, alternate_path, filename, 4188 lhapdf_version=lhapdf_version) 4189 elif lhapdf_version.startswith('6.') and '.LHgrid' in filename: 4190 logger.info('Could not download %s: Try %s', filename, filename.replace('.LHgrid','')) 4191 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir, 4192 filename.replace('.LHgrid',''), 4193 lhapdf_version, alternate_path) 4194 elif lhapdf_version.startswith('6.'): 4195 # try to do a simple wget 4196 wwwpath = "http://www.hepforge.org/archive/lhapdf/pdfsets/%s/%s.tar.gz" 4197 wwwpath %= ('.'.join(lhapdf_version.split('.')[:2]), filename) 4198 misc.wget(wwwpath, pjoin(pdfsets_dir, '%s.tar.gz' %filename)) 4199 misc.call(['tar', '-xzpvf', '%s.tar.gz' %filename], 4200 cwd=pdfsets_dir) 4201 if os.path.exists(pjoin(pdfsets_dir, filename)) or \ 4202 os.path.isdir(pjoin(pdfsets_dir, filename)): 4203 logger.info('%s successfully downloaded and stored in %s' \ 4204 % (filename, pdfsets_dir)) 4205 elif 'LHAPDF_DATA_PATH' in os.environ and os.environ['LHAPDF_DATA_PATH']: 4206 4207 if pdfsets_dir in os.environ['LHAPDF_DATA_PATH'].split(':'): 4208 lhapath = os.environ['LHAPDF_DATA_PATH'].split(':') 4209 lhapath = [p for p in lhapath if os.path.exists(p)] 4210 lhapath.remove(pdfsets_dir) 4211 os.environ['LHAPDF_DATA_PATH'] = ':'.join(lhapath) 4212 if lhapath: 4213 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4214 filename, 4215 lhapdf_version, alternate_path) 4216 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']: 4217 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4218 filename, 4219 lhapdf_version, alternate_path) 4220 else: 4221 raise MadGraph5Error, \ 4222 'Could not download %s into %s. Please try to install it manually.' \ 4223 % (filename, pdfsets_dir) 4224 else: 4225 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4226 filename, 4227 lhapdf_version, alternate_path) 4228 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']: 4229 misc.sprint(os.environ['LHAPATH'], '-> retry') 4230 if pdfsets_dir in os.environ['LHAPATH'].split(':'): 4231 lhapath = os.environ['LHAPATH'].split(':') 4232 lhapath = [p for p in lhapath if os.path.exists(p)] 4233 lhapath.remove(pdfsets_dir) 4234 os.environ['LHAPATH'] = ':'.join(lhapath) 4235 if lhapath: 4236 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4237 filename, 4238 lhapdf_version, alternate_path) 4239 else: 4240 raise MadGraph5Error, \ 4241 'Could not download %s into %s. Please try to install it manually.' \ 4242 % (filename, pdfsets_dir) 4243 else: 4244 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4245 filename, 4246 lhapdf_version, alternate_path) 4247 else: 4248 raise MadGraph5Error, \ 4249 'Could not download %s into %s. Please try to install it manually.' \ 4250 % (filename, pdfsets_dir) 4251 4252 else: 4253 raise MadGraph5Error, \ 4254 'Could not download %s into %s. Please try to install it manually.' \ 4255 % (filename, pdfsets_dir)
4256 4257 4258
4259 - def get_lhapdf_pdfsets_list(self, pdfsets_dir):
4260 """read the PDFsets.index file, which should be located in the same 4261 place as pdfsets_dir, and return a list of dictionaries with the information 4262 about each pdf set""" 4263 lhapdf_version = self.get_lhapdf_version() 4264 return self.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4265 4266 @staticmethod
4267 - def get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version):
4268 4269 if lhapdf_version.startswith('5.'): 4270 if os.path.exists('%s.index' % pdfsets_dir): 4271 indexfile = '%s.index' % pdfsets_dir 4272 else: 4273 raise MadGraph5Error, 'index of lhapdf file not found' 4274 pdfsets_lines = \ 4275 [l for l in open(indexfile).read().split('\n') if l.strip() and \ 4276 not '90cl' in l] 4277 lhapdf_pdfsets = dict( (int(l.split()[0]), {'lhaid': int(l.split()[0]), 4278 'pdflib_ntype': int(l.split()[1]), 4279 'pdflib_ngroup': int(l.split()[2]), 4280 'pdflib_nset': int(l.split()[3]), 4281 'filename': l.split()[4], 4282 'lhapdf_nmem': int(l.split()[5]), 4283 'q2min': float(l.split()[6]), 4284 'q2max': float(l.split()[7]), 4285 'xmin': float(l.split()[8]), 4286 'xmax': float(l.split()[9]), 4287 'description': l.split()[10]}) \ 4288 for l in pdfsets_lines) 4289 4290 elif lhapdf_version.startswith('6.'): 4291 pdfsets_lines = \ 4292 [l for l in open(pjoin(pdfsets_dir, 'pdfsets.index')).read().split('\n') if l.strip()] 4293 lhapdf_pdfsets = dict( (int(l.split()[0]), 4294 {'lhaid': int(l.split()[0]), 4295 'filename': l.split()[1]}) \ 4296 for l in pdfsets_lines) 4297 4298 else: 4299 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version) 4300 4301 return lhapdf_pdfsets
4302 4303 @staticmethod
4304 - def get_lhapdf_version_static(lhapdf_config):
4305 """returns the lhapdf version number""" 4306 4307 try: 4308 lhapdf_version = \ 4309 subprocess.Popen([lhapdf_config, '--version'], 4310 stdout = subprocess.PIPE).stdout.read().strip() 4311 except OSError, error: 4312 if error.errno == 2: 4313 raise Exception, 'lhapdf executable (%s) is not found on your system. Please install it and/or indicate the path to the correct executable in input/mg5_configuration.txt' % self.options['lhapdf'] 4314 else: 4315 raise 4316 4317 # this will be removed once some issues in lhapdf6 will be fixed 4318 if lhapdf_version.startswith('6.0'): 4319 raise MadGraph5Error('LHAPDF 6.0.x not supported. Please use v6.1 or later') 4320 return lhapdf_version
4321 4322
4323 - def get_lhapdf_version(self):
4324 """returns the lhapdf version number""" 4325 if not hasattr(self, 'lhapdfversion'): 4326 self.lhapdf_version = self.get_lhapdf_version_static(self.options['lhapdf']) 4327 return self.lhapdf_version
4328 4329 @staticmethod
4330 - def get_lhapdf_pdfsetsdir_static(lhapdf_config, lhapdf_version=None):
4331 """ """ 4332 if not lhapdf_version: 4333 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config) 4334 4335 # check if the LHAPDF_DATA_PATH variable is defined 4336 if 'LHAPDF_DATA_PATH' in os.environ.keys() and os.environ['LHAPDF_DATA_PATH']: 4337 datadir = os.environ['LHAPDF_DATA_PATH'] 4338 elif lhapdf_version.startswith('5.'): 4339 datadir = subprocess.Popen([lhapdf_config, '--pdfsets-path'], 4340 stdout = subprocess.PIPE).stdout.read().strip() 4341 4342 elif lhapdf_version.startswith('6.'): 4343 datadir = subprocess.Popen([lhapdf_config, '--datadir'], 4344 stdout = subprocess.PIPE).stdout.read().strip() 4345 4346 if ':' in datadir: 4347 for totry in datadir.split(':'): 4348 if os.path.exists(pjoin(totry, 'pdfsets.index')): 4349 return totry 4350 else: 4351 return None 4352 4353 return datadir
4354
4355 - def get_lhapdf_pdfsetsdir(self):
4356 4357 lhapdf_version = self.get_lhapdf_version() 4358 return self.get_lhapdf_pdfsetsdir_static(self.options['lhapdf'], lhapdf_version)
4359 4360 ############################################################################
4361 - def get_Pdir(self):
4362 """get the list of Pdirectory if not yet saved.""" 4363 4364 if hasattr(self, "Pdirs"): 4365 if self.me_dir in self.Pdirs[0]: 4366 return self.Pdirs 4367 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip()) 4368 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))] 4369 return self.Pdirs
4370
4371 - def get_lhapdf_libdir(self):
4372 4373 if 'LHAPATH' in os.environ: 4374 for d in os.environ['LHAPATH'].split(':'): 4375 if os.path.isdir(d): 4376 return d 4377 4378 4379 lhapdf_version = self.get_lhapdf_version() 4380 4381 if lhapdf_version.startswith('5.'): 4382 libdir = subprocess.Popen([self.options['lhapdf-config'], '--libdir'], 4383 stdout = subprocess.PIPE).stdout.read().strip() 4384 4385 elif lhapdf_version.startswith('6.'): 4386 libdir = subprocess.Popen([self.options['lhapdf'], '--libs'], 4387 stdout = subprocess.PIPE).stdout.read().strip() 4388 4389 return libdir
4390
4391 -class AskforEditCard(cmd.OneLinePathCompletion):
4392 """A class for asking a question where in addition you can have the 4393 set command define and modifying the param_card/run_card correctly 4394 4395 special action can be trigger via trigger_XXXX when the user start a line 4396 with XXXX. the output of such function should be new line that can be handle. 4397 (return False to repeat the question) 4398 """ 4399 4400 all_card_name = ['param_card', 'run_card', 'pythia_card', 'pythia8_card', 4401 'madweight_card', 'MadLoopParams', 'shower_card'] 4402 to_init_card = ['param', 'run', 'madweight', 'madloop', 4403 'shower', 'pythia8','delphes','madspin'] 4404 special_shortcut = {} 4405 special_shortcut_help = {} 4406 4407 integer_bias = 1 # integer corresponding to the first entry in self.cards 4408 4409 PY8Card_class = banner_mod.PY8Card 4410
4411 - def load_default(self):
4412 """ define all default variable. No load of card here. 4413 This allow to subclass this class and just change init and still have 4414 all variables defined.""" 4415 4416 if not hasattr(self, 'me_dir'): 4417 self.me_dir = None 4418 self.param_card = None 4419 self.run_card = {} 4420 self.pname2block = {} 4421 self.conflict = [] 4422 self.restricted_value = {} 4423 self.mode = '' 4424 self.cards = [] 4425 self.run_set = [] 4426 self.has_mw = False 4427 self.has_ml = False 4428 self.has_shower = False 4429 self.has_PY8 = False 4430 self.has_delphes = False 4431 self.paths = {} 4432 self.update_block = []
4433 4434
4435 - def define_paths(self, **opt):
4436 # Initiation 4437 if 'pwd' in opt: 4438 self.me_dir = opt['pwd'] 4439 elif 'mother_interface' in opt: 4440 self.mother_interface = opt['mother_interface'] 4441 if not hasattr(self, 'me_dir') or not self.me_dir: 4442 self.me_dir = self.mother_interface.me_dir 4443 4444 #define paths 4445 self.paths['param'] = pjoin(self.me_dir,'Cards','param_card.dat') 4446 self.paths['param_default'] = pjoin(self.me_dir,'Cards','param_card_default.dat') 4447 self.paths['run'] = pjoin(self.me_dir,'Cards','run_card.dat') 4448 self.paths['run_default'] = pjoin(self.me_dir,'Cards','run_card_default.dat') 4449 self.paths['transfer'] =pjoin(self.me_dir,'Cards','transfer_card.dat') 4450 self.paths['MadWeight'] =pjoin(self.me_dir,'Cards','MadWeight_card.dat') 4451 self.paths['MadWeight_default'] =pjoin(self.me_dir,'Cards','MadWeight_card_default.dat') 4452 self.paths['ML'] =pjoin(self.me_dir,'Cards','MadLoopParams.dat') 4453 self.paths['shower'] = pjoin(self.me_dir,'Cards','shower_card.dat') 4454 self.paths['shower_default'] = pjoin(self.me_dir,'Cards','shower_card_default.dat') 4455 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards','FO_analyse_card.dat') 4456 self.paths['FO_analyse_default'] = pjoin(self.me_dir,'Cards','FO_analyse_card_default.dat') 4457 self.paths['pythia'] =pjoin(self.me_dir, 'Cards','pythia_card.dat') 4458 self.paths['pythia8'] = pjoin(self.me_dir, 'Cards','pythia8_card.dat') 4459 self.paths['pythia8_default'] = pjoin(self.me_dir, 'Cards','pythia8_card_default.dat') 4460 self.paths['madspin_default'] = pjoin(self.me_dir,'Cards/madspin_card_default.dat') 4461 self.paths['madspin'] = pjoin(self.me_dir,'Cards/madspin_card.dat') 4462 self.paths['reweight'] = pjoin(self.me_dir,'Cards','reweight_card.dat') 4463 self.paths['delphes'] = pjoin(self.me_dir,'Cards','delphes_card.dat') 4464 self.paths['plot'] = pjoin(self.me_dir,'Cards','plot_card.dat') 4465 self.paths['plot_default'] = pjoin(self.me_dir,'Cards','plot_card_default.dat') 4466 self.paths['madanalysis5_parton'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card.dat') 4467 self.paths['madanalysis5_hadron'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card.dat') 4468 self.paths['madanalysis5_parton_default'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card_default.dat') 4469 self.paths['madanalysis5_hadron_default'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card_default.dat') 4470 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards', 'FO_analyse_card.dat')
4471 4472 4473 4474
4475 - def __init__(self, question, cards=[], from_banner=None, banner=None, mode='auto', *args, **opt):
4476 4477 4478 self.load_default() 4479 self.define_paths(**opt) 4480 self.last_editline_pos = 0 4481 4482 if 'allow_arg' not in opt or not opt['allow_arg']: 4483 # add some mininal content for this: 4484 opt['allow_arg'] = range(self.integer_bias, self.integer_bias+len(cards)) 4485 4486 self.param_consistency = True 4487 if 'param_consistency' in opt: 4488 self.param_consistency = opt['param_consistency'] 4489 4490 cmd.OneLinePathCompletion.__init__(self, question, *args, **opt) 4491 4492 self.conflict = set() 4493 self.mode = mode 4494 self.cards = cards 4495 self.all_vars = set() 4496 self.modified_card = set() #set of cards not in sync with filesystem 4497 # need to sync them before editing/leaving 4498 self.init_from_banner(from_banner, banner) 4499 4500 #update default path by custom one if specify in cards 4501 for card in cards: 4502 if os.path.exists(card) and os.path.sep in cards: 4503 card_name = CommonRunCmd.detect_card_type(card) 4504 card_name = card_name.split('_',1)[0] 4505 self.paths[card_name] = card 4506 4507 # go trough the initialisation of each card and detect conflict 4508 for name in self.to_init_card: 4509 new_vars = set(getattr(self, 'init_%s' % name)(cards)) 4510 new_conflict = self.all_vars.intersection(new_vars) 4511 self.conflict.union(new_conflict) 4512 self.all_vars.union(new_vars)
4513 4514
4515 - def init_from_banner(self, from_banner, banner):
4516 """ defined card that need to be initialized from the banner file 4517 from_banner should be a list of card to load from the banner object 4518 """ 4519 4520 if from_banner is None: 4521 self.from_banner = {} 4522 return 4523 4524 self.from_banner = {} 4525 try: 4526 for card in from_banner: 4527 self.from_banner[card] = banner.charge_card(card) 4528 except KeyError: 4529 if from_banner == ['param', 'run'] and banner.keys() == ['mgversion']: 4530 if self.mother_interface: 4531 results = self.mother_interface.results 4532 run_name = self.mother_interface.run_name 4533 run_tag = self.mother_interface.run_tag 4534 banner = banner_mod.recover_banner(results, 'parton', run_name, run_tag) 4535 self.mother_interface.banner = banner 4536 return self.init_from_banner(from_banner, banner) 4537 else: 4538 raise 4539 4540 return self.from_banner
4541 4542
4543 - def get_path(self, name, cards):
4544 """initialise the path if requested""" 4545 4546 defname = '%s_default' % name 4547 4548 if name in self.from_banner: 4549 return self.from_banner[name] 4550 4551 if isinstance(cards, list): 4552 if name in cards: 4553 return True 4554 elif '%s_card.dat' % name in cards: 4555 return True 4556 elif name in self.paths and self.paths[name] in cards: 4557 return True 4558 else: 4559 cardnames = [os.path.basename(p) for p in cards] 4560 if '%s_card.dat' % name in cardnames: 4561 return True 4562 else: 4563 return False 4564 4565 elif isinstance(cards, dict) and name in cards: 4566 self.paths[name]= cards[name] 4567 if defname in cards: 4568 self.paths[defname] = cards[defname] 4569 elif os.path.isfile(cards[name].replace('.dat', '_default.dat')): 4570 self.paths[defname] = cards[name].replace('.dat', '_default.dat') 4571 else: 4572 self.paths[defname] = self.paths[name] 4573 4574 return True 4575 else: 4576 return False
4577
4578 - def init_param(self, cards):
4579 """check if we need to load the param_card""" 4580 4581 self.pname2block = {} 4582 self.restricted_value = {} 4583 self.param_card = {} 4584 4585 is_valid_path = self.get_path('param', cards) 4586 if not is_valid_path: 4587 self.param_consistency = False 4588 return [] 4589 if isinstance(is_valid_path, param_card_mod.ParamCard): 4590 self.param_card = is_valid_path 4591 self.param_consistency = False 4592 return [] 4593 4594 try: 4595 self.param_card = param_card_mod.ParamCard(self.paths['param']) 4596 except (param_card_mod.InvalidParamCard, ValueError) as e: 4597 logger.error('Current param_card is not valid. We are going to use the default one.') 4598 logger.error('problem detected: %s' % e) 4599 files.cp(self.paths['param_default'], self.paths['param']) 4600 self.param_card = param_card_mod.ParamCard(self.paths['param']) 4601 4602 # Read the comment of the param_card_default to find name variable for 4603 # the param_card also check which value seems to be constrained in the 4604 # model. 4605 if os.path.exists(self.paths['param_default']): 4606 default_param = param_card_mod.ParamCard(self.paths['param_default']) 4607 else: 4608 default_param = param_card_mod.ParamCard(self.param_card) 4609 self.pname2block, self.restricted_value = default_param.analyze_param_card() 4610 self.param_card_default = default_param 4611 return self.pname2block.keys()
4612
4613 - def init_run(self, cards):
4614 4615 self.run_set = [] 4616 is_valid_path = self.get_path('run', cards) 4617 if not is_valid_path: 4618 return [] 4619 if isinstance(is_valid_path, banner_mod.RunCard): 4620 self.run_card = is_valid_path 4621 return [] 4622 4623 4624 try: 4625 self.run_card = banner_mod.RunCard(self.paths['run'], consistency='warning') 4626 except IOError: 4627 self.run_card = {} 4628 try: 4629 run_card_def = banner_mod.RunCard(self.paths['run_default']) 4630 except IOError: 4631 run_card_def = {} 4632 4633 4634 if run_card_def: 4635 if self.run_card: 4636 self.run_set = run_card_def.keys() + self.run_card.hidden_param 4637 else: 4638 self.run_set = run_card_def.keys() + run_card_def.hidden_param 4639 elif self.run_card: 4640 self.run_set = self.run_card.keys() 4641 else: 4642 self.run_set = [] 4643 4644 if self.run_set: 4645 self.special_shortcut.update( 4646 {'ebeam':([float],['run_card ebeam1 %(0)s', 'run_card ebeam2 %(0)s']), 4647 'lpp': ([int],['run_card lpp1 %(0)s', 'run_card lpp2 %(0)s' ]), 4648 'lhc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']), 4649 'lep': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']), 4650 'ilc': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']), 4651 'lcc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']), 4652 'fixed_scale': ([float],['run_card fixed_fac_scale T', 'run_card fixed_ren_scale T', 'run_card scale %(0)s', 'run_card dsqrt_q2fact1 %(0)s' ,'run_card dsqrt_q2fact2 %(0)s']), 4653 'no_parton_cut':([],['run_card nocut T']), 4654 'cm_velocity':([float], [lambda self :self.set_CM_velocity]), 4655 'pbp':([],['run_card lpp1 1', 'run_card lpp2 1','run_card nb_proton1 82', 'run_card nb_neutron1 126', 'run_card mass_ion1 195.0820996698','run_card nb_proton2 1', 'run_card nb_neutron2 0', 'run_card mass_ion1 -1']), 4656 'pbpb':([],['run_card lpp1 1', 'run_card lpp2 1','run_card nb_proton1 82', 'run_card nb_neutron1 126', 'run_card mass_ion1 195.0820996698', 'run_card nb_proton2 82', 'run_card nb_neutron2 126', 'run_card mass_ion2 195.0820996698' ]), 4657 'pp': ([],['run_card lpp1 1', 'run_card lpp2 1','run_card nb_proton1 1', 'run_card nb_neutron1 0', 'run_card mass_ion1 -1', 'run_card nb_proton2 1', 'run_card nb_neutron2 0', 'run_card mass_ion2 -1']), 4658 }) 4659 4660 self.special_shortcut_help.update({ 4661 'ebeam' : 'syntax: set ebeam VALUE:\n This parameter sets the energy to both beam to the value in GeV', 4662 'lpp' : 'syntax: set ebeam VALUE:\n'+\ 4663 ' Set the type of beam to a given value for both beam\n'+\ 4664 ' 0 : means no PDF\n'+\ 4665 ' 1 : means proton PDF\n'+\ 4666 ' -1 : means antiproton PDF\n'+\ 4667 ' 2 : means PDF for elastic photon emited from a proton\n'+\ 4668 ' 3 : means PDF for elastic photon emited from an electron', 4669 'lhc' : 'syntax: set lhc VALUE:\n Set for a proton-proton collision with that given center of mass energy (in TeV)', 4670 'lep' : 'syntax: set lep VALUE:\n Set for a electron-positron collision with that given center of mass energy (in GeV)', 4671 'fixed_scale' : 'syntax: set fixed_scale VALUE:\n Set all scales to the give value (in GeV)', 4672 'no_parton_cut': 'remove all cut (but BW_cutoff)', 4673 'cm_velocity': 'set sqrts to have the above velocity for the incoming particles', 4674 'pbpb': 'setup heavy ion configuration for lead-lead collision', 4675 'pbp': 'setup heavy ion configuration for lead-proton collision', 4676 'pp': 'remove setup of heavy ion configuration to set proton-proton collision', 4677 }) 4678 4679 self.update_block += [b.name for b in self.run_card.blocks] 4680 4681 return self.run_set
4682
4683 - def init_madweight(self, cards):
4684 4685 self.has_mw = False 4686 if not self.get_path('madweight', cards): 4687 return [] 4688 4689 #add special function associated to MW 4690 self.do_change_tf = self.mother_interface.do_define_transfer_fct 4691 self.complete_change_tf = self.mother_interface.complete_define_transfer_fct 4692 self.help_change_tf = self.mother_interface.help_define_transfer_fct 4693 if not os.path.exists(self.paths['transfer']): 4694 logger.warning('No transfer function currently define. Please use the change_tf command to define one.') 4695 4696 self.has_mw = True 4697 try: 4698 import madgraph.madweight.Cards as mwcards 4699 except: 4700 import internal.madweight.Cards as mwcards 4701 self.mw_card = mwcards.Card(self.paths['MadWeight']) 4702 self.mw_card = self.mw_card.info 4703 self.mw_vars = [] 4704 for key in self.mw_card: 4705 if key == 'comment': 4706 continue 4707 for key2 in self.mw_card.info[key]: 4708 if isinstance(key2, str) and not key2.isdigit(): 4709 self.mw_vars.append(key2) 4710 return self.mw_vars
4711
4712 - def init_madloop(self, cards):
4713 4714 if isinstance(cards, dict): 4715 for key in ['ML', 'madloop','MadLoop']: 4716 if key in cards: 4717 self.paths['ML'] = cards[key] 4718 4719 self.has_ml = False 4720 if os.path.isfile(self.paths['ML']): 4721 self.has_ml = True 4722 self.MLcard = banner_mod.MadLoopParam(self.paths['ML']) 4723 self.MLcardDefault = banner_mod.MadLoopParam() 4724 self.ml_vars = [k.lower() for k in self.MLcard.keys()] 4725 return self.ml_vars 4726 return []
4727
4728 - def init_shower(self, cards):
4729 4730 self.has_shower = False 4731 if not self.get_path('shower', cards): 4732 return [] 4733 self.has_shower = True 4734 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower']) 4735 self.shower_vars = self.shower_card.keys() 4736 return self.shower_vars
4737
4738 - def init_pythia8(self, cards):
4739 4740 self.has_PY8 = False 4741 if not self.get_path('pythia8', cards): 4742 return [] 4743 4744 self.has_PY8 = True 4745 self.PY8Card = self.PY8Card_class(self.paths['pythia8']) 4746 self.PY8CardDefault = self.PY8Card_class() 4747 4748 self.py8_vars = [k.lower() for k in self.PY8Card.keys()] 4749 4750 self.special_shortcut.update({ 4751 'simplepy8':([],['pythia8_card hadronlevel:all False', 4752 'pythia8_card partonlevel:mpi False', 4753 'pythia8_card BeamRemnants:primordialKT False', 4754 'pythia8_card PartonLevel:Remnants False', 4755 'pythia8_card Check:event False', 4756 'pythia8_card TimeShower:QEDshowerByQ False', 4757 'pythia8_card TimeShower:QEDshowerByL False', 4758 'pythia8_card SpaceShower:QEDshowerByQ False', 4759 'pythia8_card SpaceShower:QEDshowerByL False', 4760 'pythia8_card PartonLevel:FSRinResonances False', 4761 'pythia8_card ProcessLevel:resonanceDecays False', 4762 ]), 4763 'mpi':([bool],['pythia8_card partonlevel:mpi %(0)s']), 4764 }) 4765 self.special_shortcut_help.update({ 4766 'simplepy8' : 'Turn off non-perturbative slow features of Pythia8.', 4767 'mpi' : 'syntax: set mpi value: allow to turn mpi in Pythia8 on/off', 4768 }) 4769 return []
4770
4771 - def init_madspin(self, cards):
4772 4773 if not self.get_path('madspin', cards): 4774 return [] 4775 4776 self.special_shortcut.update({ 4777 'spinmode':([str], ['add madspin_card --before_line="launch" set spinmode %(0)s']) 4778 }) 4779 self.special_shortcut_help.update({ 4780 'spinmode' : 'full|none|onshell. Choose the mode of madspin.\n - full: spin-correlation and off-shell effect\n - onshell: only spin-correlation,]\n - none: no spin-correlation and not offshell effects.' 4781 }) 4782 return []
4783
4784 - def init_delphes(self, cards):
4785 4786 self.has_delphes = False 4787 if not self.get_path('pythia8', cards): 4788 return [] 4789 self.has_delphes = True 4790 return []
4791 4792
4793 - def set_CM_velocity(self, line):
4794 """compute sqrts from the velocity in the center of mass frame""" 4795 4796 v = banner_mod.ConfigFile.format_variable(line, float, 'velocity') 4797 # Define self.proc_characteristics 4798 self.mother_interface.get_characteristics() 4799 proc_info = self.mother_interface.proc_characteristics 4800 if 'pdg_initial1' not in proc_info: 4801 logger.warning('command not supported') 4802 4803 if len(proc_info['pdg_initial1']) == 1 == len(proc_info['pdg_initial2']) and\ 4804 abs(proc_info['pdg_initial1'][0]) == abs(proc_info['pdg_initial2'][0]): 4805 4806 m = self.param_card.get_value('mass', abs(proc_info['pdg_initial1'][0])) 4807 sqrts = 2*m/ math.sqrt(1-v**2) 4808 self.do_set('run_card ebeam1 %s' % (sqrts/2.0)) 4809 self.do_set('run_card ebeam2 %s' % (sqrts/2.0)) 4810 self.do_set('run_card lpp 0') 4811 else: 4812 logger.warning('This is only possible for a single particle in the initial state')
4813 4814 4815
4816 - def do_help(self, line, conflict_raise=False, banner=True):
4817 # TODO nicer factorization ! 4818 4819 # try: 4820 if banner: 4821 logger.info('*** HELP MESSAGE ***', '$MG:BOLD') 4822 4823 args = self.split_arg(line) 4824 # handle comand related help 4825 if len(args)==0 or (len(args) == 1 and hasattr(self, 'do_%s' % args[0])): 4826 out = cmd.BasicCmd.do_help(self, line) 4827 if len(args)==0: 4828 print 'Allowed Argument' 4829 print '================' 4830 print '\t'.join(self.allow_arg) 4831 print 4832 print 'Special shortcut: (type help <name>)' 4833 print '====================================' 4834 print ' syntax: set <name> <value>' 4835 print '\t'.join(self.special_shortcut) 4836 print 4837 if banner: 4838 logger.info('*** END HELP ***', '$MG:BOLD') 4839 return out 4840 # check for special shortcut. 4841 # special shortcut: 4842 if args[0] in self.special_shortcut: 4843 if args[0] in self.special_shortcut_help: 4844 print self.special_shortcut_help[args[0]] 4845 if banner: 4846 logger.info('*** END HELP ***', '$MG:BOLD') 4847 return 4848 4849 start = 0 4850 card = '' 4851 if args[0]+'_card' in self.all_card_name+ self.cards: 4852 args[0] += '_card' 4853 elif args[0]+'.dat' in self.all_card_name+ self.cards: 4854 args[0] += '.dat' 4855 elif args[0]+'_card.dat' in self.all_card_name+ self.cards: 4856 args[0] += '_card.dat' 4857 if args[0] in self.all_card_name + self.cards: 4858 start += 1 4859 card = args[0] 4860 if len(args) == 1: 4861 if args[0] == 'pythia8_card': 4862 args[0] = 'PY8Card' 4863 if args[0] == 'param_card': 4864 logger.info("Param_card information: ", '$MG:color:BLUE') 4865 print "File to define the various model parameter" 4866 logger.info("List of the Block defined:",'$MG:color:BLUE') 4867 print "\t".join(self.param_card.keys()) 4868 elif args[0].startswith('madanalysis5'): 4869 print 'This card allow to make plot with the madanalysis5 package' 4870 print 'An example card is provided. For more information about the ' 4871 print 'syntax please refer to: https://madanalysis.irmp.ucl.ac.be/' 4872 print 'or to the user manual [arXiv:1206.1599]' 4873 if args[0].startswith('madanalysis5_hadron'): 4874 print 4875 print 'This card also allow to make recasting analysis' 4876 print 'For more detail, see: arXiv:1407.3278' 4877 elif hasattr(self, args[0]): 4878 logger.info("%s information: " % args[0], '$MG:color:BLUE') 4879 print(eval('self.%s' % args[0]).__doc__) 4880 logger.info("List of parameter associated", '$MG:color:BLUE') 4881 print "\t".join(eval('self.%s' % args[0]).keys()) 4882 if banner: 4883 logger.info('*** END HELP ***', '$MG:BOLD') 4884 return card 4885 4886 #### RUN CARD 4887 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']: 4888 if args[start] not in self.run_set: 4889 args[start] = [l for l in self.run_set if l.lower() == args[start]][0] 4890 4891 if args[start] in self.conflict and not conflict_raise: 4892 conflict_raise = True 4893 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4894 if card == '': 4895 logger.info('** If not explicitely speficy this parameter will modif the run_card file', '$MG:BOLD') 4896 4897 self.run_card.do_help(args[start]) 4898 ### PARAM_CARD WITH BLOCK NAME ----------------------------------------- 4899 elif (args[start] in self.param_card or args[start] == 'width') \ 4900 and card in ['','param_card']: 4901 if args[start] in self.conflict and not conflict_raise: 4902 conflict_raise = True 4903 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4904 if card == '': 4905 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD') 4906 4907 if args[start] == 'width': 4908 args[start] = 'decay' 4909 4910 if len(args) == start+1: 4911 self.param_card.do_help(args[start], tuple()) 4912 key = None 4913 elif args[start+1] in self.pname2block: 4914 all_var = self.pname2block[args[start+1]] 4915 key = None 4916 for bname, lhaid in all_var: 4917 if bname == args[start]: 4918 key = lhaid 4919 break 4920 else: 4921 logger.warning('%s is not part of block "%s" but "%s". please correct.' % 4922 (args[start+1], args[start], bname)) 4923 else: 4924 try: 4925 key = tuple([int(i) for i in args[start+1:]]) 4926 except ValueError: 4927 logger.warning('Failed to identify LHA information') 4928 return card 4929 4930 if key in self.param_card[args[start]].param_dict: 4931 self.param_card.do_help(args[start], key, default=self.param_card_default) 4932 elif key: 4933 logger.warning('invalid information: %s not defined in the param_card' % (key,)) 4934 # PARAM_CARD NO BLOCK NAME --------------------------------------------- 4935 elif args[start] in self.pname2block and card in ['','param_card']: 4936 if args[start] in self.conflict and not conflict_raise: 4937 conflict_raise = True 4938 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4939 if card == '': 4940 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD') 4941 4942 all_var = self.pname2block[args[start]] 4943 for bname, lhaid in all_var: 4944 new_line = 'param_card %s %s %s' % (bname, 4945 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:])) 4946 self.do_help(new_line, conflict_raise=True, banner=False) 4947 4948 # MadLoop Parameter --------------------------------------------------- 4949 elif self.has_ml and args[start] in self.ml_vars \ 4950 and card in ['', 'MadLoop_card']: 4951 4952 if args[start] in self.conflict and not conflict_raise: 4953 conflict_raise = True 4954 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4955 if card == '': 4956 logger.info('** If not explicitely speficy this parameter will modif the madloop_card file', '$MG:BOLD') 4957 4958 self.MLcard.do_help(args[start]) 4959 4960 # Pythia8 Parameter --------------------------------------------------- 4961 elif self.has_PY8 and args[start] in self.PY8Card: 4962 if args[start] in self.conflict and not conflict_raise: 4963 conflict_raise = True 4964 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4965 if card == '': 4966 logger.info('** If not explicitely speficy this parameter will modif the pythia8_card file', '$MG:BOLD') 4967 4968 self.PY8Card.do_help(args[start]) 4969 elif card.startswith('madanalysis5'): 4970 print 'MA5' 4971 4972 4973 elif banner: 4974 print "no help available" 4975 4976 if banner: 4977 logger.info('*** END HELP ***', '$MG:BOLD') 4978 #raw_input('press enter to quit the help') 4979 return card
4980 # except Exception, error: 4981 # if __debug__: 4982 # import traceback 4983 # traceback.print_exc() 4984 # print error 4985
4986 - def complete_help(self, text, line, begidx, endidx):
4987 prev_timer = signal.alarm(0) # avoid timer if any 4988 if prev_timer: 4989 nb_back = len(line) 4990 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 4991 self.stdout.write(line) 4992 self.stdout.flush() 4993 # try: 4994 possibilities = self.complete_set(text, line, begidx, endidx,formatting=False) 4995 if line[:begidx].strip() == 'help': 4996 possibilities['Defined command'] = cmd.BasicCmd.completenames(self, text, line)#, begidx, endidx) 4997 possibilities.update(self.complete_add(text, line, begidx, endidx,formatting=False)) 4998 return self.deal_multiple_categories(possibilities)
4999 # except Exception, error: 5000 # import traceback 5001 # traceback.print_exc() 5002 # print error 5003
5004 - def complete_update(self, text, line, begidx, endidx):
5005 prev_timer = signal.alarm(0) # avoid timer if any 5006 if prev_timer: 5007 nb_back = len(line) 5008 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 5009 self.stdout.write(line) 5010 self.stdout.flush() 5011 5012 valid = ['dependent', 'missing', 'to_slha1', 'to_slha2', 'to_full'] 5013 valid += self.update_block 5014 5015 arg = line[:begidx].split() 5016 if len(arg) <=1: 5017 return self.list_completion(text, valid, line) 5018 elif arg[0] == 'to_full': 5019 return self.list_completion(text, self.cards , line)
5020
5021 - def complete_set(self, text, line, begidx, endidx, formatting=True):
5022 """ Complete the set command""" 5023 5024 prev_timer = signal.alarm(0) # avoid timer if any 5025 if prev_timer: 5026 nb_back = len(line) 5027 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 5028 self.stdout.write(line) 5029 self.stdout.flush() 5030 5031 possibilities = {} 5032 allowed = {} 5033 args = self.split_arg(line[0:begidx]) 5034 if args[-1] in ['Auto', 'default']: 5035 return 5036 5037 if len(args) == 1: 5038 allowed = {'category':'', 'run_card':'', 'block':'all', 'param_card':'','shortcut':''} 5039 if self.has_mw: 5040 allowed['madweight_card'] = '' 5041 allowed['mw_block'] = 'all' 5042 if self.has_shower: 5043 allowed['shower_card'] = '' 5044 if self.has_ml: 5045 allowed['madloop_card'] = '' 5046 if self.has_PY8: 5047 allowed['pythia8_card'] = '' 5048 if self.has_delphes: 5049 allowed['delphes_card'] = '' 5050 5051 elif len(args) == 2: 5052 if args[1] == 'run_card': 5053 allowed = {'run_card':'default'} 5054 elif args[1] == 'param_card': 5055 allowed = {'block':'all', 'param_card':'default'} 5056 elif self.param_card and args[1] in self.param_card.keys(): 5057 allowed = {'block':args[1]} 5058 elif args[1] == 'width': 5059 allowed = {'block': 'decay'} 5060 elif args[1] == 'MadWeight_card': 5061 allowed = {'madweight_card':'default', 'mw_block': 'all'} 5062 elif args[1] == 'MadLoop_card': 5063 allowed = {'madloop_card':'default'} 5064 elif args[1] == 'pythia8_card': 5065 allowed = {'pythia8_card':'default'} 5066 elif self.has_mw and args[1] in self.mw_card.keys(): 5067 allowed = {'mw_block':args[1]} 5068 elif args[1] == 'shower_card': 5069 allowed = {'shower_card':'default'} 5070 elif args[1] == 'delphes_card': 5071 allowed = {'delphes_card':'default'} 5072 else: 5073 allowed = {'value':''} 5074 5075 else: 5076 start = 1 5077 if args[1] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card', 5078 'MadLoop_card','pythia8_card','delphes_card','plot_card', 5079 'madanalysis5_parton_card','madanalysis5_hadron_card']: 5080 start = 2 5081 5082 if args[-1] in self.pname2block.keys(): 5083 allowed['value'] = 'default' 5084 elif args[start] in self.param_card.keys() or args[start] == 'width': 5085 if args[start] == 'width': 5086 args[start] = 'decay' 5087 5088 if args[start+1:]: 5089 allowed = {'block':(args[start], args[start+1:])} 5090 else: 5091 allowed = {'block':args[start]} 5092 elif self.has_mw and args[start] in self.mw_card.keys(): 5093 if args[start+1:]: 5094 allowed = {'mw_block':(args[start], args[start+1:])} 5095 else: 5096 allowed = {'mw_block':args[start]} 5097 #elif len(args) == start +1: 5098 # allowed['value'] = '' 5099 else: 5100 allowed['value'] = '' 5101 5102 if 'category' in allowed.keys(): 5103 categories = ['run_card', 'param_card'] 5104 if self.has_mw: 5105 categories.append('MadWeight_card') 5106 if self.has_shower: 5107 categories.append('shower_card') 5108 if self.has_ml: 5109 categories.append('MadLoop_card') 5110 if self.has_PY8: 5111 categories.append('pythia8_card') 5112 if self.has_delphes: 5113 categories.append('delphes_card') 5114 5115 possibilities['category of parameter (optional)'] = \ 5116 self.list_completion(text, categories) 5117 5118 if 'shortcut' in allowed.keys(): 5119 possibilities['special values'] = self.list_completion(text, self.special_shortcut.keys()+['qcut', 'showerkt']) 5120 5121 if 'run_card' in allowed.keys(): 5122 opts = self.run_set 5123 if allowed['run_card'] == 'default': 5124 opts.append('default') 5125 5126 5127 possibilities['Run Card'] = self.list_completion(text, opts) 5128 5129 if 'param_card' in allowed.keys(): 5130 opts = self.pname2block.keys() 5131 if allowed['param_card'] == 'default': 5132 opts.append('default') 5133 possibilities['Param Card'] = self.list_completion(text, opts) 5134 5135 if 'madweight_card' in allowed.keys(): 5136 opts = self.mw_vars + [k for k in self.mw_card.keys() if k !='comment'] 5137 if allowed['madweight_card'] == 'default': 5138 opts.append('default') 5139 possibilities['MadWeight Card'] = self.list_completion(text, opts) 5140 5141 if 'madloop_card' in allowed.keys(): 5142 opts = self.ml_vars 5143 if allowed['madloop_card'] == 'default': 5144 opts.append('default') 5145 possibilities['MadLoop Parameter'] = self.list_completion(text, opts) 5146 5147 if 'pythia8_card' in allowed.keys(): 5148 opts = self.py8_vars 5149 if allowed['pythia8_card'] == 'default': 5150 opts.append('default') 5151 possibilities['Pythia8 Parameter'] = self.list_completion(text, opts) 5152 5153 if 'shower_card' in allowed.keys(): 5154 opts = self.shower_vars + [k for k in self.shower_card.keys() if k !='comment'] 5155 if allowed['shower_card'] == 'default': 5156 opts.append('default') 5157 possibilities['Shower Card'] = self.list_completion(text, opts) 5158 5159 if 'delphes_card' in allowed: 5160 if allowed['delphes_card'] == 'default': 5161 opts = ['default', 'atlas', 'cms'] 5162 possibilities['Delphes Card'] = self.list_completion(text, opts) 5163 5164 if 'value' in allowed.keys(): 5165 opts = ['default'] 5166 if 'decay' in args: 5167 opts.append('Auto') 5168 opts.append('Auto@NLO') 5169 elif args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay': 5170 opts.append('Auto') 5171 opts.append('Auto@NLO') 5172 if args[-1] in self.run_set: 5173 allowed_for_run = [] 5174 if args[-1].lower() in self.run_card.allowed_value: 5175 allowed_for_run = self.run_card.allowed_value[args[-1].lower()] 5176 if '*' in allowed_for_run: 5177 allowed_for_run.remove('*') 5178 elif isinstance(self.run_card[args[-1]], bool): 5179 allowed_for_run = ['True', 'False'] 5180 opts += [str(i) for i in allowed_for_run] 5181 5182 5183 possibilities['Special Value'] = self.list_completion(text, opts) 5184 5185 if 'block' in allowed.keys() and self.param_card: 5186 if allowed['block'] == 'all' and self.param_card: 5187 allowed_block = [i for i in self.param_card.keys() if 'qnumbers' not in i] 5188 allowed_block.append('width') 5189 possibilities['Param Card Block' ] = \ 5190 self.list_completion(text, allowed_block) 5191 5192 elif isinstance(allowed['block'], basestring): 5193 block = self.param_card[allowed['block']].param_dict 5194 ids = [str(i[0]) for i in block 5195 if (allowed['block'], i) not in self.restricted_value] 5196 possibilities['Param Card id' ] = self.list_completion(text, ids) 5197 varname = [name for name, all_var in self.pname2block.items() 5198 if any((bname == allowed['block'] 5199 for bname,lhaid in all_var))] 5200 possibilities['Param card variable'] = self.list_completion(text, 5201 varname) 5202 else: 5203 block = self.param_card[allowed['block'][0]].param_dict 5204 nb = len(allowed['block'][1]) 5205 ids = [str(i[nb]) for i in block if len(i) > nb and \ 5206 [str(a) for a in i[:nb]] == allowed['block'][1]] 5207 5208 if not ids: 5209 if tuple([int(i) for i in allowed['block'][1]]) in block: 5210 opts = ['default'] 5211 if allowed['block'][0] == 'decay': 5212 opts.append('Auto') 5213 opts.append('Auto@NLO') 5214 possibilities['Special value'] = self.list_completion(text, opts) 5215 possibilities['Param Card id' ] = self.list_completion(text, ids) 5216 5217 if 'mw_block' in allowed.keys(): 5218 if allowed['mw_block'] == 'all': 5219 allowed_block = [i for i in self.mw_card.keys() if 'comment' not in i] 5220 possibilities['MadWeight Block' ] = \ 5221 self.list_completion(text, allowed_block) 5222 elif isinstance(allowed['mw_block'], basestring): 5223 block = self.mw_card[allowed['mw_block']] 5224 ids = [str(i[0]) if isinstance(i, tuple) else str(i) for i in block] 5225 possibilities['MadWeight Card id' ] = self.list_completion(text, ids) 5226 else: 5227 block = self.mw_card[allowed['mw_block'][0]] 5228 nb = len(allowed['mw_block'][1]) 5229 ids = [str(i[nb]) for i in block if isinstance(i, tuple) and\ 5230 len(i) > nb and \ 5231 [str(a) for a in i[:nb]] == allowed['mw_block'][1]] 5232 5233 if not ids: 5234 if tuple([i for i in allowed['mw_block'][1]]) in block or \ 5235 allowed['mw_block'][1][0] in block.keys(): 5236 opts = ['default'] 5237 possibilities['Special value'] = self.list_completion(text, opts) 5238 possibilities['MadWeight Card id' ] = self.list_completion(text, ids) 5239 5240 return self.deal_multiple_categories(possibilities, formatting)
5241
5242 - def do_set(self, line):
5243 """ edit the value of one parameter in the card""" 5244 5245 5246 args = self.split_arg(line) 5247 5248 5249 if len(args) == 0: 5250 logger.warning("No argument. For help type 'help set'.") 5251 # fix some formatting problem 5252 if len(args)==1 and '=' in args[-1]: 5253 arg1, arg2 = args.pop(-1).split('=',1) 5254 args += [arg1, arg2] 5255 if '=' in args: 5256 args.remove('=') 5257 5258 args[:-1] = [ a.lower() for a in args[:-1]] 5259 if len(args) == 1: #special shortcut without argument -> lowercase 5260 args = [args[0].lower()] 5261 # special shortcut: 5262 if args[0] in self.special_shortcut: 5263 targettypes , cmd = self.special_shortcut[args[0]] 5264 if len(args) != len(targettypes) +1: 5265 logger.warning('shortcut %s requires %s argument' % (args[0], len(targettypes))) 5266 if len(args) < len(targettypes) +1: 5267 return 5268 else: 5269 logger.warning('additional argument will be ignored') 5270 values ={} 5271 for i, argtype in enumerate(targettypes): 5272 try: 5273 values = {str(i): banner_mod.ConfigFile.format_variable(args[i+1], argtype, args[0])} 5274 except ValueError as e: 5275 logger.warning("Wrong argument: The entry #%s should be of type %s.", i+1, argtype) 5276 return 5277 except InvalidCmd as e: 5278 logger.warning(str(e)) 5279 return 5280 #else: 5281 # logger.warning("too many argument for this command") 5282 # return 5283 for arg in cmd: 5284 if isinstance(arg, str): 5285 try: 5286 text = arg % values 5287 except KeyError: 5288 logger.warning("This command requires one argument") 5289 return 5290 except Exception as e: 5291 logger.warning(str(e)) 5292 return 5293 else: 5294 split = text.split() 5295 if hasattr(self, 'do_%s' % split[0]): 5296 getattr(self, 'do_%s' % split[0])(' '.join(split[1:])) 5297 else: 5298 self.do_set(text) 5299 #need to call a function 5300 else: 5301 val = [values[str(i)] for i in range(len(values))] 5302 try: 5303 arg(self)(*val) 5304 except Exception, e: 5305 logger.warning(str(e)) 5306 return 5307 5308 start = 0 5309 if len(args) < 2: 5310 logger.warning('Invalid set command %s (need two arguments)' % line) 5311 return 5312 5313 # Special case for the qcut value 5314 if args[0].lower() == 'qcut': 5315 pythia_path = self.paths['pythia'] 5316 if os.path.exists(pythia_path): 5317 logger.info('add line QCUT = %s in pythia_card.dat' % args[1]) 5318 p_card = open(pythia_path,'r').read() 5319 p_card, n = re.subn('''^\s*QCUT\s*=\s*[\de\+\-\.]*\s*$''', 5320 ''' QCUT = %s ''' % args[1], \ 5321 p_card, flags=(re.M+re.I)) 5322 if n==0: 5323 p_card = '%s \n QCUT= %s' % (p_card, args[1]) 5324 with open(pythia_path, 'w') as fsock: 5325 fsock.write(p_card) 5326 return 5327 # Special case for the showerkt value 5328 if args[0].lower() == 'showerkt': 5329 pythia_path = self.paths['pythia'] 5330 if os.path.exists(pythia_path): 5331 logger.info('add line SHOWERKT = %s in pythia_card.dat' % args[1].upper()) 5332 p_card = open(pythia_path,'r').read() 5333 p_card, n = re.subn('''^\s*SHOWERKT\s*=\s*[default\de\+\-\.]*\s*$''', 5334 ''' SHOWERKT = %s ''' % args[1].upper(), \ 5335 p_card, flags=(re.M+re.I)) 5336 if n==0: 5337 p_card = '%s \n SHOWERKT= %s' % (p_card, args[1].upper()) 5338 with open(pythia_path, 'w') as fsock: 5339 fsock.write(p_card) 5340 return 5341 5342 card = '' #store which card need to be modify (for name conflict) 5343 if args[0] == 'madweight_card': 5344 if not self.mw_card: 5345 logger.warning('Invalid Command: No MadWeight card defined.') 5346 return 5347 args[0] = 'MadWeight_card' 5348 5349 if args[0] == 'shower_card': 5350 if not self.shower_card: 5351 logger.warning('Invalid Command: No Shower card defined.') 5352 return 5353 args[0] = 'shower_card' 5354 5355 if args[0] == "madloop_card": 5356 if not self.has_ml: 5357 logger.warning('Invalid Command: No MadLoopParam card defined.') 5358 return 5359 args[0] = 'MadLoop_card' 5360 5361 if args[0] == "pythia8_card": 5362 if not self.has_PY8: 5363 logger.warning('Invalid Command: No Pythia8 card defined.') 5364 return 5365 args[0] = 'pythia8_card' 5366 5367 if args[0] == 'delphes_card': 5368 if not self.has_delphes: 5369 logger.warning('Invalid Command: No Delphes card defined.') 5370 return 5371 if args[1] == 'atlas': 5372 logger.info("set default ATLAS configuration for Delphes", '$MG:BOLD') 5373 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_ATLAS.dat'), 5374 pjoin(self.me_dir,'Cards', 'delphes_card.dat')) 5375 return 5376 elif args[1] == 'cms': 5377 logger.info("set default CMS configuration for Delphes",'$MG:BOLD') 5378 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_CMS.dat'), 5379 pjoin(self.me_dir,'Cards', 'delphes_card.dat')) 5380 return 5381 5382 if args[0] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card', 5383 'delphes_card','madanalysis5_hadron_card','madanalysis5_parton_card']: 5384 5385 if args[1] == 'default': 5386 logger.info('replace %s by the default card' % args[0],'$MG:BOLD') 5387 files.cp(self.paths['%s_default' %args[0][:-5]], self.paths[args[0][:-5]]) 5388 if args[0] == 'param_card': 5389 self.param_card = param_card_mod.ParamCard(self.paths['param']) 5390 elif args[0] == 'run_card': 5391 self.run_card = banner_mod.RunCard(self.paths['run']) 5392 elif args[0] == 'shower_card': 5393 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower']) 5394 return 5395 else: 5396 card = args[0] 5397 start=1 5398 if len(args) < 3: 5399 logger.warning('Invalid set command: %s (not enough arguments)' % line) 5400 return 5401 5402 elif args[0] in ['MadLoop_card']: 5403 if args[1] == 'default': 5404 logger.info('replace MadLoopParams.dat by the default card','$MG:BOLD') 5405 self.MLcard = banner_mod.MadLoopParam(self.MLcardDefault) 5406 self.MLcard.write(self.paths['ML'], 5407 commentdefault=True) 5408 return 5409 else: 5410 card = args[0] 5411 start=1 5412 if len(args) < 3: 5413 logger.warning('Invalid set command: %s (not enough arguments)' % line) 5414 return 5415 elif args[0] in ['pythia8_card']: 5416 if args[1] == 'default': 5417 logger.info('replace pythia8_card.dat by the default card','$MG:BOLD') 5418 self.PY8Card = self.PY8Card_class(self.PY8CardDefault) 5419 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'), 5420 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 5421 print_only_visible=True) 5422 return 5423 else: 5424 card = args[0] 5425 start=1 5426 if len(args) < 3: 5427 logger.warning('Invalid set command: %s (not enough arguments)' % line) 5428 return 5429 elif args[0] in ['madspin_card']: 5430 if args[1] == 'default': 5431 logger.info('replace madspin_card.dat by the default card','$MG:BOLD') 5432 files.cp(self.paths['MS_default'], self.paths['madspin']) 5433 return 5434 else: 5435 logger.warning("""Command set not allowed for modifying the madspin_card. 5436 Check the command \"decay\" instead.""") 5437 return 5438 5439 #### RUN CARD 5440 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']: 5441 5442 if args[start] not in self.run_set: 5443 if card in self.from_banner or 'run' in self.from_banner: 5444 raise Exception, "change not allowed for this card: event already generated!" 5445 args[start] = [l for l in self.run_set if l.lower() == args[start]][0] 5446 5447 if args[start] in self.conflict and card == '': 5448 text = 'Ambiguous name (present in more than one card). Will assume it to be referred to run_card.\n' 5449 text += 'If this is not intended, please reset it in the run_card and specify the relevant card to \n' 5450 text += 'edit, in the format < set card parameter value >' 5451 logger.warning(text) 5452 5453 if args[start+1] == 'default': 5454 default = banner_mod.RunCard(self.paths['run_default']) 5455 if args[start] in default.keys(): 5456 self.setR(args[start],default[args[start]]) 5457 else: 5458 logger.info('remove information %s from the run_card' % args[start],'$MG:BOLD') 5459 del self.run_card[args[start]] 5460 else: 5461 lower_name = args[0].lower() 5462 if lower_name.startswith('sys_') or \ 5463 lower_name in self.run_card.list_parameter or \ 5464 lower_name in self.run_card.dict_parameter: 5465 val = ' '.join(args[start+1:]) 5466 val = val.split('#')[0] 5467 else: 5468 val = ' '.join(args[start+1:]) 5469 self.setR(args[start], val) 5470 self.modified_card.add('run') # delayed writing of the run_card 5471 # special mode for set run_card nocut T (generated by set no_parton_cut 5472 elif card == 'run_card' and args[start] in ['nocut', 'no_cut']: 5473 logger.info("Going to remove all cuts from the run_card", '$MG:BOLD') 5474 self.run_card.remove_all_cut() 5475 self.modified_card.add('run') # delayed writing of the run_card 5476 ### PARAM_CARD WITH BLOCK NAME ----------------------------------------- 5477 elif self.param_card and (args[start] in self.param_card or args[start] == 'width') \ 5478 and card in ['','param_card']: 5479 #special treatment for scan 5480 if any(t.startswith('scan') for t in args): 5481 index = [i for i,t in enumerate(args) if t.startswith('scan')][0] 5482 args = args[:index] + [' '.join(args[index:])] 5483 5484 if args[start] in self.conflict and card == '': 5485 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5486 text += ' in the format < set card parameter value>' 5487 logger.warning(text) 5488 return 5489 5490 if args[start] == 'width': 5491 args[start] = 'decay' 5492 5493 if args[start+1] in self.pname2block: 5494 all_var = self.pname2block[args[start+1]] 5495 key = None 5496 for bname, lhaid in all_var: 5497 if bname == args[start]: 5498 key = lhaid 5499 break 5500 else: 5501 logger.warning('%s is not part of block "%s" but "%s". please correct.' % 5502 (args[start+1], args[start], bname)) 5503 return 5504 else: 5505 try: 5506 key = tuple([int(i) for i in args[start+1:-1]]) 5507 except ValueError: 5508 if args[start] == 'decay' and args[start+1:-1] == ['all']: 5509 for key in self.param_card[args[start]].param_dict: 5510 if (args[start], key) in self.restricted_value: 5511 continue 5512 else: 5513 self.setP(args[start], key, args[-1]) 5514 self.modified_card.add('param') 5515 return 5516 logger.warning('invalid set command %s (failed to identify LHA information)' % line) 5517 return 5518 5519 if key in self.param_card[args[start]].param_dict: 5520 if (args[start], key) in self.restricted_value: 5521 text = "Note that this parameter seems to be ignore by MG.\n" 5522 text += "MG will use instead the expression: %s\n" % \ 5523 self.restricted_value[(args[start], key)] 5524 text += "You need to match this expression for external program (such pythia)." 5525 logger.warning(text) 5526 5527 if args[-1].lower() in ['default', 'auto', 'auto@nlo'] or args[-1].startswith('scan'): 5528 self.setP(args[start], key, args[-1]) 5529 else: 5530 try: 5531 value = float(args[-1]) 5532 except Exception: 5533 logger.warning('Invalid input: Expected number and not \'%s\'' \ 5534 % args[-1]) 5535 return 5536 self.setP(args[start], key, value) 5537 else: 5538 logger.warning('invalid set command %s' % line) 5539 return 5540 self.modified_card.add('param') 5541 5542 # PARAM_CARD NO BLOCK NAME --------------------------------------------- 5543 elif args[start] in self.pname2block and card in ['','param_card']: 5544 if args[start] in self.conflict and card == '': 5545 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5546 text += ' in the format < set card parameter value>' 5547 logger.warning(text) 5548 return 5549 5550 all_var = self.pname2block[args[start]] 5551 for bname, lhaid in all_var: 5552 new_line = 'param_card %s %s %s' % (bname, 5553 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:])) 5554 self.do_set(new_line) 5555 if len(all_var) > 1: 5556 logger.warning('This variable correspond to more than one parameter in the param_card.') 5557 for bname, lhaid in all_var: 5558 logger.warning(' %s %s' % (bname, ' '.join([str(i) for i in lhaid]))) 5559 logger.warning('all listed variables have been modified') 5560 5561 # MadWeight_card with block name --------------------------------------- 5562 elif self.has_mw and (args[start] in self.mw_card and args[start] != 'comment') \ 5563 and card in ['','MadWeight_card']: 5564 5565 if args[start] in self.conflict and card == '': 5566 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5567 text += ' in the format < set card parameter value>' 5568 logger.warning(text) 5569 return 5570 5571 block = args[start] 5572 name = args[start+1] 5573 value = args[start+2:] 5574 self.setM(block, name, value) 5575 self.mw_card.write(self.paths['MadWeight']) 5576 5577 # MadWeight_card NO Block name ----------------------------------------- 5578 elif self.has_mw and args[start] in self.mw_vars \ 5579 and card in ['', 'MadWeight_card']: 5580 5581 if args[start] in self.conflict and card == '': 5582 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5583 text += ' in the format < set card parameter value>' 5584 logger.warning(text) 5585 return 5586 5587 block = [b for b, data in self.mw_card.items() if args[start] in data] 5588 if len(block) > 1: 5589 logger.warning('%s is define in more than one block: %s.Please specify.' 5590 % (args[start], ','.join(block))) 5591 return 5592 5593 block = block[0] 5594 name = args[start] 5595 value = args[start+1:] 5596 self.setM(block, name, value) 5597 self.mw_card.write(self.paths['MadWeight']) 5598 5599 # MadWeight_card New Block --------------------------------------------- 5600 elif self.has_mw and args[start].startswith('mw_') and len(args[start:]) == 3\ 5601 and card == 'MadWeight_card': 5602 block = args[start] 5603 name = args[start+1] 5604 value = args[start+2] 5605 self.setM(block, name, value) 5606 self.mw_card.write(self.paths['MadWeight']) 5607 5608 #### SHOWER CARD 5609 elif self.has_shower and args[start].lower() in [l.lower() for l in \ 5610 self.shower_card.keys()] and card in ['', 'shower_card']: 5611 if args[start] not in self.shower_card: 5612 args[start] = [l for l in self.shower_card if l.lower() == args[start].lower()][0] 5613 5614 if args[start] in self.conflict and card == '': 5615 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5616 text += ' in the format < set card parameter value>' 5617 logger.warning(text) 5618 return 5619 5620 if args[start+1].lower() == 'default': 5621 default = shower_card_mod.ShowerCard(self.paths['shower_default']) 5622 if args[start] in default.keys(): 5623 self.shower_card.set_param(args[start],default[args[start]], self.paths['shower']) 5624 else: 5625 logger.info('remove information %s from the shower_card' % args[start],'$MG:BOLD') 5626 del self.shower_card[args[start]] 5627 elif args[start+1].lower() in ['t','.true.','true']: 5628 self.shower_card.set_param(args[start],'.true.',self.paths['shower']) 5629 elif args[start+1].lower() in ['f','.false.','false']: 5630 self.shower_card.set_param(args[start],'.false.',self.paths['shower']) 5631 elif args[start] in ['analyse', 'extralibs', 'extrapaths', 'includepaths'] or\ 5632 args[start].startswith('dm_'): 5633 #case sensitive parameters 5634 args = line.split() 5635 args_str = ' '.join(str(a) for a in args[start+1:len(args)]) 5636 self.shower_card.set_param(args[start],args_str,pjoin(self.me_dir,'Cards','shower_card.dat')) 5637 else: 5638 args_str = ' '.join(str(a) for a in args[start+1:len(args)]) 5639 self.shower_card.set_param(args[start],args_str,self.paths['shower']) 5640 5641 # MadLoop Parameter --------------------------------------------------- 5642 elif self.has_ml and args[start] in self.ml_vars \ 5643 and card in ['', 'MadLoop_card']: 5644 5645 if args[start] in self.conflict and card == '': 5646 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5647 logger.warning(text) 5648 return 5649 5650 if args[start+1] == 'default': 5651 value = self.MLcardDefault[args[start]] 5652 default = True 5653 else: 5654 value = args[start+1] 5655 default = False 5656 self.setML(args[start], value, default=default) 5657 self.MLcard.write(self.paths['ML'], 5658 commentdefault=True) 5659 5660 # Pythia8 Parameter --------------------------------------------------- 5661 elif self.has_PY8 and (card == 'pythia8_card' or (card == '' and \ 5662 args[start] in self.PY8Card)): 5663 5664 if args[start] in self.conflict and card == '': 5665 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5666 logger.warning(text) 5667 return 5668 5669 if args[start+1] == 'default': 5670 value = self.PY8CardDefault[args[start]] 5671 default = True 5672 else: 5673 value = ' '.join(args[start+1:]) 5674 default = False 5675 self.setPY8(args[start], value, default=default) 5676 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'), 5677 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 5678 print_only_visible=True) 5679 5680 #INVALID -------------------------------------------------------------- 5681 else: 5682 logger.warning('invalid set command %s ' % line) 5683 arg = args[start].lower() 5684 if self.has_PY8: 5685 close_opts = [name for name in self.PY8Card if name.lower().startswith(arg[:3]) or arg in name.lower()] 5686 if close_opts: 5687 logger.info('Did you mean one of the following PY8 options:\n%s' % '\t'.join(close_opts)) 5688 if self.run_card: 5689 close_opts = [name for name in self.run_card if name.lower().startswith(arg[:3]) or arg in name.lower()] 5690 if close_opts: 5691 logger.info('Did you mean one of the following run_card options:\n%s' % '\t'.join(close_opts)) 5692 5693 return
5694
5695 - def setM(self, block, name, value):
5696 5697 if isinstance(value, list) and len(value) == 1: 5698 value = value[0] 5699 5700 if block not in self.mw_card: 5701 logger.warning('block %s was not present in the current MadWeight card. We are adding it' % block) 5702 self.mw_card[block] = {} 5703 elif name not in self.mw_card[block]: 5704 logger.info('name %s was not present in the block %s for the current MadWeight card. We are adding it' % (name,block),'$MG:BOLD') 5705 if value == 'default': 5706 import madgraph.madweight.Cards as mwcards 5707 mw_default = mwcards.Card(self.paths['MadWeight_default']) 5708 try: 5709 value = mw_default[block][name] 5710 except KeyError: 5711 logger.info('removing id "%s" from Block "%s" '% (name, block),'$MG:BOLD') 5712 if name in self.mw_card[block]: 5713 del self.mw_card[block][name] 5714 return 5715 if value: 5716 logger.info('modify madweight_card information BLOCK "%s" with id "%s" set to %s', 5717 block, name, value, '$MG:BOLD') 5718 else: 5719 logger.warning("Invalid command: No value. To set default value. Use \"default\" as value") 5720 return 5721 5722 self.mw_card[block][name] = value
5723
5724 - def setR(self, name, value):
5725 5726 if self.mother_interface.inputfile: 5727 self.run_card.set(name, value, user=True, raiseerror=True) 5728 else: 5729 self.run_card.set(name, value, user=True) 5730 new_value = self.run_card.get(name) 5731 logger.info('modify parameter %s of the run_card.dat to %s' % (name, new_value),'$MG:BOLD')
5732 5733
5734 - def setML(self, name, value, default=False):
5735 5736 try: 5737 self.MLcard.set(name, value, user=True) 5738 except Exception, error: 5739 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error) 5740 return 5741 logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value),'$MG:BOLD') 5742 if default and name.lower() in self.MLcard.user_set: 5743 self.MLcard.user_set.remove(name.lower())
5744
5745 - def setPY8(self, name, value, default=False):
5746 try: 5747 self.PY8Card.userSet(name, value) 5748 except Exception, error: 5749 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error) 5750 return 5751 logger.info('modify parameter %s of the pythia8_card.dat to %s' % (name, value), '$MG:BOLD') 5752 if default and name.lower() in self.PY8Card.user_set: 5753 self.PY8Card.user_set.remove(name.lower())
5754
5755 - def setP(self, block, lhaid, value):
5756 if isinstance(value, str): 5757 value = value.lower() 5758 if value == 'default': 5759 default = param_card_mod.ParamCard(self.paths['param_default']) 5760 value = default[block].param_dict[lhaid].value 5761 5762 elif value in ['auto', 'auto@nlo']: 5763 if 'nlo' in value: 5764 value = 'Auto@NLO' 5765 else: 5766 value = 'Auto' 5767 if block != 'decay': 5768 logger.warning('Invalid input: \'Auto\' value only valid for DECAY') 5769 return 5770 elif value.startswith('scan'): 5771 if ':' not in value: 5772 logger.warning('Invalid input: \'scan\' mode requires a \':\' before the definition.') 5773 return 5774 tag = value.split(':')[0] 5775 tag = tag[4:].strip() 5776 if tag and not tag.isdigit(): 5777 logger.warning('Invalid input: scan tag need to be integer and not "%s"' % tag) 5778 return 5779 5780 5781 pass 5782 else: 5783 try: 5784 value = float(value) 5785 except ValueError: 5786 logger.warning('Invalid input: \'%s\' not valid intput.'% value) 5787 5788 logger.info('modify param_card information BLOCK %s with id %s set to %s' %\ 5789 (block, lhaid, value), '$MG:BOLD') 5790 self.param_card[block].param_dict[lhaid].value = value
5791
5792 - def check_card_consistency(self):
5793 """This is run on quitting the class. Apply here all the self-consistency 5794 rule that you want. Do the modification via the set command.""" 5795 5796 ######################################################################## 5797 # LO specific check 5798 ######################################################################## 5799 if isinstance(self.run_card,banner_mod.RunCardLO): 5800 5801 proc_charac = self.mother_interface.proc_characteristics 5802 if proc_charac['grouped_matrix'] and \ 5803 abs(self.run_card['lpp1']) == 1 == abs(self.run_card['lpp2']) and \ 5804 (self.run_card['nb_proton1'] != self.run_card['nb_proton2'] or 5805 self.run_card['nb_neutron1'] != self.run_card['nb_neutron2'] or 5806 self.run_card['mass_ion1'] != self.run_card['mass_ion2']): 5807 raise Exception, "Heavy ion profile for both beam are different but the symmetry used forbids it. \n Please generate your process with \"set group_subprocesses False\"." 5808 5809 # check the status of small width status from LO 5810 for param in self.param_card['decay']: 5811 width = param.value 5812 if width == 0 or isinstance(width,str): 5813 continue 5814 try: 5815 mass = self.param_card['mass'].get(param.lhacode).value 5816 except Exception: 5817 continue 5818 if isinstance(mass,str): 5819 continue 5820 5821 if mass: 5822 to_sleep = True 5823 if abs(width/mass) < self.run_card['small_width_treatment']: 5824 logger.warning("Particle %s with small width detected (%s): See https://answers.launchpad.net/mg5amcnlo/+faq/3053 to learn the special handling of that case", 5825 param.lhacode[0], width) 5826 elif abs(width/mass) < 1e-12: 5827 logger.error('The width of particle %s is too small for an s-channel resonance (%s). If you have this particle in an s-channel, this is likely to create numerical instabilities .', param.lhacode[0], width) 5828 else: 5829 to_sleep = False 5830 if CommonRunCmd.sleep_for_error and to_sleep: 5831 time.sleep(5) 5832 CommonRunCmd.sleep_for_error = False 5833 5834 # @LO if PY6 shower => event_norm on sum 5835 if 'pythia_card.dat' in self.cards and 'run' in self.allow_arg: 5836 if self.run_card['event_norm'] != 'sum': 5837 logger.info('Pythia6 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' ) 5838 self.do_set('run_card event_norm sum') 5839 # @LO if PY6 shower => event_norm on sum 5840 elif 'pythia8_card.dat' in self.cards: 5841 if self.run_card['event_norm'] == 'sum': 5842 logger.info('Pythia8 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' ) 5843 self.do_set('run_card event_norm average') 5844 5845 if 'MLM' in proc_charac['limitations']: 5846 if self.run_card['dynamical_scale_choice'] == -1: 5847 raise InvalidCmd, "Your model is identified as not fully supported within MG5aMC.\n" +\ 5848 "As your process seems to be impacted by the issue,\n"+\ 5849 "You can NOT run with CKKW dynamical scale for this model. Please choose another one." 5850 if self.run_card['ickkw']: 5851 raise InvalidCmd, "Your model is identified as not fully supported within MG5aMC.\n" +\ 5852 "As your process seems to be impacted by the issue,\n" +\ 5853 "You can NOT run with MLM matching/merging. Please check if merging outside MG5aMC are suitable or refrain to use merging with this model" 5854 5855 5856 ######################################################################## 5857 # NLO specific check 5858 ######################################################################## 5859 # For NLO run forbid any pdg specific cut on massless particle 5860 if isinstance(self.run_card,banner_mod.RunCardNLO): 5861 5862 try: 5863 proc_charac = self.mother_interface.proc_characteristics 5864 except: 5865 proc_charac = None 5866 5867 if proc_charac and 'MLM' in proc_charac['limitations']: 5868 if self.run_card['ickkw']: 5869 raise Exception, "Your model is identified as not fully supported within MG5aMC.\n" +\ 5870 "You can NOT run with FxFx/UnLOPS matching/merging. Please check if merging outside MG5aMC are suitable or refrain to use merging with this model" 5871 5872 5873 for pdg in set(self.run_card['pt_min_pdg'].keys()+self.run_card['pt_max_pdg'].keys()+ 5874 self.run_card['mxx_min_pdg'].keys()): 5875 5876 if int(pdg)<0: 5877 raise Exception, "For PDG specific cuts, always use positive PDG codes: the cuts are applied to both particles and anti-particles" 5878 if self.param_card.get_value('mass', int(pdg), default=0) ==0: 5879 raise Exception, "For NLO runs, you can use PDG specific cuts only for massive particles: (failed for %s)" % pdg 5880 5881 # if NLO reweighting is ON: ensure that we keep the rwgt information 5882 if 'reweight' in self.allow_arg and 'run' in self.allow_arg and \ 5883 not self.run_card['store_rwgt_info']: 5884 #check if a NLO reweighting is required 5885 re_pattern = re.compile(r'''^\s*change\s*mode\s* (LO\+NLO|LO|NLO|NLO_tree)\s*(?:#|$)''', re.M+re.I) 5886 text = open(self.paths['reweight']).read() 5887 options = re_pattern.findall(text) 5888 if any(o in ['NLO', 'LO+NLO'] for o in options): 5889 logger.info('NLO reweighting is on ON. Automatically set store_rwgt_info to True', '$MG:BOLD' ) 5890 self.do_set('run_card store_rwgt_info True') 5891 5892 # if external computation for the systematics are asked then switch 5893 #automatically the book-keeping of the weight for NLO 5894 if 'run' in self.allow_arg and \ 5895 self.run_card['systematics_program'] == 'systematics' and \ 5896 not self.run_card['store_rwgt_info']: 5897 logger.warning('To be able to run systematics program, we set store_rwgt_info to True') 5898 self.do_set('run_card store_rwgt_info True') 5899 5900 5901 5902 # Check the extralibs flag. 5903 if self.has_shower and isinstance(self.run_card, banner_mod.RunCardNLO): 5904 modify_extralibs, modify_extrapaths = False,False 5905 extralibs = self.shower_card['extralibs'].split() 5906 extrapaths = self.shower_card['extrapaths'].split() 5907 # remove default stdhep/Fmcfio for recent shower 5908 if self.run_card['parton_shower'] in ['PYTHIA8', 'HERWIGPP', 'HW7']: 5909 if 'stdhep' in self.shower_card['extralibs']: 5910 extralibs.remove('stdhep') 5911 modify_extralibs = True 5912 if 'Fmcfio' in self.shower_card['extralibs']: 5913 extralibs.remove('Fmcfio') 5914 modify_extralibs = True 5915 if self.run_card['parton_shower'] == 'PYTHIA8': 5916 # First check sanity of PY8 5917 if not self.mother_interface.options['pythia8_path']: 5918 raise self.mother_interface.InvalidCmd, 'Pythia8 is not correctly specified to MadGraph5_aMC@NLO' 5919 executable = pjoin(self.mother_interface.options['pythia8_path'], 'bin', 'pythia8-config') 5920 if not os.path.exists(executable): 5921 raise self.mother.InvalidCmd, 'Pythia8 is not correctly specified to MadGraph5_aMC@NLO' 5922 5923 # 2. take the compilation flag of PY8 from pythia8-config 5924 libs , paths = [], [] 5925 p = misc.subprocess.Popen([executable, '--libs'], stdout=subprocess.PIPE) 5926 stdout, _ = p. communicate() 5927 libs = [x[2:] for x in stdout.split() if x.startswith('-l') or paths.append(x[2:])] 5928 5929 # Add additional user-defined compilation flags 5930 p = misc.subprocess.Popen([executable, '--config'], stdout=subprocess.PIPE) 5931 stdout, _ = p. communicate() 5932 for lib in ['-ldl','-lstdc++','-lc++']: 5933 if lib in stdout: 5934 libs.append(lib[2:]) 5935 5936 # This precompiler flag is in principle useful for the analysis if it writes HEPMC 5937 # events, but there is unfortunately no way for now to specify it in the shower_card. 5938 supports_HEPMCHACK = '-DHEPMC2HACK' in stdout 5939 5940 #3. ensure that those flag are in the shower card 5941 for L in paths: 5942 if L not in extrapaths: 5943 modify_extrapaths = True 5944 extrapaths.append(L) 5945 for l in libs: 5946 if l == 'boost_iostreams': 5947 #this one is problematic handles it. 5948 for L in paths + extrapaths: 5949 if misc.glob('*boost_iostreams*', L): 5950 break 5951 else: 5952 continue 5953 if l not in extralibs: 5954 modify_extralibs = True 5955 extralibs.append(l) 5956 # Apply the required modification 5957 if modify_extralibs: 5958 if extralibs: 5959 self.do_set('shower_card extralibs %s ' % ' '.join(extralibs)) 5960 else: 5961 self.do_set('shower_card extralibs None ') 5962 if modify_extrapaths: 5963 if extrapaths: 5964 self.do_set('shower_card extrapaths %s ' % ' '.join(extrapaths)) 5965 else: 5966 self.do_set('shower_card extrapaths None ') 5967 5968 # ensure that all cards are in sync 5969 for key in list(self.modified_card): 5970 self.write_card(key)
5971 5972
5973 - def reask(self, *args, **opt):
5974 5975 cmd.OneLinePathCompletion.reask(self,*args, **opt) 5976 if self.has_mw and not os.path.exists(pjoin(self.me_dir,'Cards','transfer_card.dat')): 5977 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
5978 5979 fail_due_to_format = 0 #parameter to avoid infinite loop
5980 - def postcmd(self, stop, line):
5981 5982 if line not in [None, '0', 'done', '']: 5983 ending_question = cmd.OneLinePathCompletion.postcmd(self,stop,line) 5984 else: 5985 ending_question = True 5986 5987 if ending_question: 5988 self.check_card_consistency() 5989 if self.param_consistency: 5990 try: 5991 self.do_update('dependent', timer=20) 5992 except MadGraph5Error, error: 5993 if 'Missing block:' in str(error): 5994 self.fail_due_to_format +=1 5995 if self.fail_due_to_format == 10: 5996 missing, unknow = str(error).split('\n')[-2:] 5997 logger.warning("Invalid param_card:\n%s\n%s\n" % (missing, unknow)) 5998 logger.info("Type \"update missing\" to use default value.\n ", '$MG:BOLD') 5999 self.value = False # to avoid that entering a command stop the question 6000 return self.reask(True) 6001 else: 6002 raise 6003 6004 return ending_question
6005 6006 6007 6008 6009
6010 - def do_update(self, line, timer=0):
6011 """ syntax: update dependent: Change the mass/width of particles which are not free parameter for the model. 6012 update missing: add to the current param_card missing blocks/parameters. 6013 update to_slha1: pass SLHA2 card to SLHA1 convention. (beta) 6014 update to_slha2: pass SLHA1 card to SLHA2 convention. (beta) 6015 update to_full [run_card] 6016 update XXX [where XXX correspond to a hidden block of the run_card] 6017 """ 6018 args = self.split_arg(line) 6019 if len(args)==0: 6020 logger.warning('miss an argument (dependent or missing). Please retry') 6021 return 6022 6023 if args[0] == 'dependent': 6024 if not self.mother_interface: 6025 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)') 6026 6027 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I) 6028 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M) 6029 param_text= open(self.paths['param']).read() 6030 6031 if pattern_scan.search(param_text): 6032 #for block, key in self.restricted_value: 6033 # self.param_card[block].get(key).value = -9.999e-99 6034 # self.param_card.write(self.paths['param']) 6035 return 6036 elif pattern_width.search(param_text): 6037 self.do_compute_widths('') 6038 self.param_card = param_card_mod.ParamCard(self.paths['param']) 6039 6040 # calling the routine doing the work 6041 self.update_dependent(self.mother_interface, self.me_dir, self.param_card, 6042 self.paths['param'], timer) 6043 6044 elif args[0] == 'missing': 6045 self.update_missing() 6046 return 6047 6048 elif args[0] == 'to_slha2': 6049 try: 6050 param_card_mod.convert_to_mg5card(self.paths['param']) 6051 logger.info('card updated') 6052 except Exception, error: 6053 logger.warning('failed to update to slha2 due to %s' % error) 6054 self.param_card = param_card_mod.ParamCard(self.paths['param']) 6055 elif args[0] == 'to_slha1': 6056 try: 6057 param_card_mod.convert_to_slha1(self.paths['param']) 6058 logger.info('card updated') 6059 except Exception, error: 6060 logger.warning('failed to update to slha1 due to %s' % error) 6061 self.param_card = param_card_mod.ParamCard(self.paths['param']) 6062 elif args[0] == 'to_full': 6063 return self.update_to_full(args[1:]) 6064 elif args[0] in self.update_block: 6065 self.run_card.display_block.append(args[0].lower()) 6066 self.modified_card.add('run') # delay writting of the run_card 6067 logger.info('add optional block %s to the run_card', args[0]) 6068 else: 6069 self.help_update() 6070 logger.warning('unvalid options for update command. Please retry')
6071 6072
6073 - def update_to_full(self, line):
6074 """ trigger via update to_full LINE""" 6075 6076 logger.info("update the run_card by including all the hidden parameter") 6077 self.run_card.write(self.paths['run'], self.paths['run_default'], write_hidden=True) 6078 if 'run' in self.modified_card: 6079 self.modified_card.remove('run')
6080
6081 - def write_card(self, name):
6082 """proxy on how to write any card""" 6083 6084 if hasattr(self, 'write_card_%s' % name): 6085 getattr(self, 'write_card_%s' % name)() 6086 if name in self.modified_card: 6087 self.modified_card.remove(name) 6088 else: 6089 raise Exception, "Need to add the associate writter proxy for %s" % name
6090
6091 - def write_card_run(self):
6092 """ write the run_card """ 6093 self.run_card.write(self.paths['run'], self.paths['run_default'])
6094
6095 - def write_card_param(self):
6096 """ write the param_card """ 6097 self.param_card.write(self.paths['param'])
6098 6099 @staticmethod
6100 - def update_dependent(mecmd, me_dir, param_card, path ,timer=0):
6101 """static method which can also be called from outside the class 6102 usefull in presence of scan. 6103 return if the param_card was updated or not 6104 """ 6105 6106 if not param_card: 6107 return False 6108 6109 logger.info('Update the dependent parameter of the param_card.dat') 6110 modify = True 6111 class TimeOutError(Exception): 6112 pass
6113 def handle_alarm(signum, frame): 6114 raise TimeOutError 6115 signal.signal(signal.SIGALRM, handle_alarm) 6116 if timer: 6117 signal.alarm(timer) 6118 log_level=30 6119 else: 6120 log_level=20 6121 # Try to load the model in the limited amount of time allowed 6122 try: 6123 model = mecmd.get_model() 6124 signal.alarm(0) 6125 except TimeOutError: 6126 logger.warning('The model takes too long to load so we bypass the updating of dependent parameter.\n'+\ 6127 'This might create trouble for external program (like MadSpin/shower/...)\n'+\ 6128 'The update can be forced without timer by typing \'update dependent\' at the time of the card edition') 6129 modify =False 6130 except Exception,error: 6131 logger.debug(str(error)) 6132 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)') 6133 signal.alarm(0) 6134 else: 6135 restrict_card = pjoin(me_dir,'Source','MODEL','param_card_rule.dat') 6136 if not os.path.exists(restrict_card): 6137 restrict_card = None 6138 #restrict_card = None 6139 if model: 6140 modify = param_card.update_dependent(model, restrict_card, log_level) 6141 if modify and path: 6142 param_card.write(path) 6143 else: 6144 logger.warning('missing MG5aMC code. Fail to update dependent parameter. This might create trouble for program like MadSpin/shower/...') 6145 6146 if log_level==20: 6147 logger.info('param_card up to date.') 6148 6149 return modify 6150 6151 6152
6153 - def update_missing(self):
6154 6155 def check_block(self, blockname): 6156 add_entry = 0 6157 if blockname.lower() not in self.param_card_default: 6158 logger.info('unknow block %s: block will be ignored', blockname) 6159 return add_entry 6160 block = self.param_card_default[blockname] 6161 for key in block.keys(): 6162 if key not in input_in_block: 6163 param = block.get(key) 6164 if blockname != 'decay': 6165 text.append('\t%s\t%s # %s\n' % (' \t'.join([`i` for i in param.lhacode]), param.value, param.comment)) 6166 else: 6167 text.append('DECAY \t%s\t%s # %s\n' % (' \t'.join([`i` for i in param.lhacode]), param.value, param.comment)) 6168 add_entry += 1 6169 if add_entry: 6170 text.append('\n') 6171 if add_entry: 6172 logger.info("Adding %s parameter(s) to block %s", add_entry, blockname) 6173 return add_entry
6174 6175 # Add to the current param_card all the missing input at default value 6176 current_block = '' 6177 input_in_block = set() 6178 defined_blocks = set() 6179 decay = set() 6180 text = [] 6181 add_entry = 0 6182 for line in open(self.paths['param']): 6183 6184 new_block = re.findall(r'^\s*(block|decay)\s*(\w*)', line, re.I) 6185 if new_block: 6186 new_block = new_block[0] 6187 defined_blocks.add(new_block[1].lower()) 6188 if current_block: 6189 add_entry += check_block(self, current_block) 6190 6191 current_block= new_block[1] 6192 input_in_block = set() 6193 if new_block[0].lower() == 'decay': 6194 decay.add((int(new_block[1]),)) 6195 current_block = '' 6196 if new_block[1].lower() == 'qnumbers': 6197 current_block = '' 6198 6199 text.append(line) 6200 if not current_block: 6201 continue 6202 6203 #normal line. 6204 #strip comment 6205 line = line.split('#',1)[0] 6206 split = line.split() 6207 if not split: 6208 continue 6209 else: 6210 try: 6211 lhacode = [int(i) for i in split[:-1]] 6212 except: 6213 continue 6214 input_in_block.add(tuple(lhacode)) 6215 6216 if current_block: 6217 add_entry += check_block(self, current_block) 6218 6219 # special check for missing block 6220 for block in self.param_card_default: 6221 6222 if block.startswith(('qnumbers', 'decay')): 6223 continue 6224 6225 if block not in defined_blocks: 6226 nb_entry = len(self.param_card_default[block]) 6227 logger.info("Block %s was missing. Adding the %s associated parameter(s)", block,nb_entry) 6228 add_entry += nb_entry 6229 text.append(str(self.param_card_default[block])) 6230 6231 # special check for the decay 6232 input_in_block = decay 6233 add_entry += check_block(self, 'decay') 6234 6235 if add_entry: 6236 logger.info('write new param_card with %s new parameter(s).', add_entry, '$MG:BOLD') 6237 open(self.paths['param'],'w').write(''.join(text)) 6238 self.reload_card(self.paths['param']) 6239 else: 6240 logger.info('No missing parameter detected.', '$MG:BOLD') 6241 6242
6243 - def check_answer_consistency(self):
6244 """function called if the code reads a file""" 6245 self.check_card_consistency() 6246 self.do_update('dependent', timer=20)
6247
6248 - def help_set(self):
6249 '''help message for set''' 6250 6251 logger.info('********************* HELP SET ***************************') 6252 logger.info("syntax: set [run_card|param_card|...] NAME [VALUE|default]") 6253 logger.info("syntax: set [param_card] BLOCK ID(s) [VALUE|default]") 6254 logger.info('') 6255 logger.info('-- Edit the param_card/run_card/... and replace the value of the') 6256 logger.info(' parameter by the value VALUE.') 6257 logger.info(' ') 6258 logger.info('-- Example:') 6259 logger.info(' set run_card ebeam1 4000') 6260 logger.info(' set ebeam2 4000') 6261 logger.info(' set lpp1 0') 6262 logger.info(' set ptj default') 6263 logger.info('') 6264 logger.info(' set param_card mass 6 175') 6265 logger.info(' set mass 25 125.3') 6266 logger.info(' set mass mh 125') 6267 logger.info(' set mh 125') 6268 logger.info(' set decay 25 0.004') 6269 logger.info(' set decay wh 0.004') 6270 logger.info(' set vmix 2 1 2.326612e-01') 6271 logger.info('') 6272 logger.info(' set param_card default #return all parameter to default') 6273 logger.info(' set run_card default') 6274 logger.info('********************* HELP SET ***************************')
6275
6276 - def trigger(self, line):
6277 6278 line = line.strip() 6279 args = line.split() 6280 6281 if not args: 6282 return line 6283 if not hasattr(self, 'trigger_%s' % args[0]): 6284 return line 6285 6286 triggerfct = getattr(self, 'trigger_%s' % args[0]) 6287 6288 # run the trigger function 6289 outline = triggerfct(' '.join(args[1:])) 6290 if not outline: 6291 return 'repeat' 6292 return outline
6293
6294 - def default(self, line):
6295 """Default action if line is not recognized""" 6296 6297 # check if the line need to be modified by a trigger 6298 line = self.trigger(line) 6299 6300 # splitting the line 6301 line = line.strip() 6302 args = line.split() 6303 if line == '' and self.default_value is not None: 6304 self.value = self.default_value 6305 # check if input is a file 6306 elif hasattr(self, 'do_%s' % args[0]): 6307 self.do_set(' '.join(args[1:])) 6308 elif line.strip() != '0' and line.strip() != 'done' and \ 6309 str(line) != 'EOF' and line.strip() in self.allow_arg: 6310 self.open_file(line) 6311 self.value = 'repeat' 6312 elif os.path.isfile(line): 6313 self.copy_file(line) 6314 self.value = 'repeat' 6315 elif self.me_dir and os.path.exists(pjoin(self.me_dir, line)): 6316 self.copy_file(pjoin(self.me_dir,line)) 6317 self.value = 'repeat' 6318 elif line.strip().startswith(('http:','www', 'https')): 6319 self.value = 'repeat' 6320 import tempfile 6321 fsock, path = tempfile.mkstemp() 6322 try: 6323 text = urllib.urlopen(line.strip()) 6324 url = line.strip() 6325 except Exception: 6326 logger.error('fail to load the file') 6327 else: 6328 for line in text: 6329 os.write(fsock, line) 6330 os.close(fsock) 6331 self.copy_file(path, pathname=url) 6332 os.remove(path) 6333 6334 6335 else: 6336 self.value = line 6337 6338 return line
6339 6340
6341 - def do_decay(self, line):
6342 """edit the madspin_card to define the decay of the associate particle""" 6343 signal.alarm(0) # avoid timer if any 6344 path = self.paths['madspin'] 6345 6346 if 'madspin_card.dat' not in self.cards or not os.path.exists(path): 6347 logger.warning("Command decay not valid. Since MadSpin is not available.") 6348 return 6349 6350 if ">" not in line: 6351 logger.warning("invalid command for decay. Line ignored") 6352 return 6353 6354 if "-add" in line: 6355 # just to have to add the line to the end of the file 6356 particle = line.split('>')[0].strip() 6357 text = open(path).read() 6358 line = line.replace('--add', '').replace('-add','') 6359 logger.info("change madspin_card to add one decay to %s: %s" %(particle, line.strip()), '$MG:BOLD') 6360 if 'launch' in text: 6361 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1) 6362 else: 6363 text += '\ndecay %s\n launch \n' % line 6364 else: 6365 # Here we have to remove all the previous definition of the decay 6366 #first find the particle 6367 particle = line.split('>')[0].strip() 6368 logger.info("change madspin_card to define the decay of %s: %s" %(particle, line.strip()), '$MG:BOLD') 6369 particle = particle.replace('+','\+').replace('-','\-') 6370 decay_pattern = re.compile(r"^\s*decay\s+%s\s*>[\s\w+-~]*?$" % particle, re.I+re.M) 6371 text= open(path).read() 6372 text = decay_pattern.sub('', text) 6373 if 'launch' in text: 6374 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1) 6375 else: 6376 text += '\ndecay %s\n launch \n' % line 6377 6378 with open(path,'w') as fsock: 6379 fsock.write(text) 6380 self.reload_card(path)
6381 6382 6383
6384 - def do_compute_widths(self, line):
6385 signal.alarm(0) # avoid timer if any 6386 6387 # ensure that the card is in sync 6388 if 'param' in self.modified_card: 6389 self.write_card('param') 6390 self.modified_card.discard('param') 6391 6392 path = self.paths['param'] 6393 pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I) 6394 text = open(path).read() 6395 pdg_info = pattern.findall(text) 6396 has_nlo = any("@nlo"==nlo.lower() for _, nlo in pdg_info) 6397 pdg = [p for p,_ in pdg_info] 6398 6399 6400 line = '%s %s' % (line, ' '.join(pdg)) 6401 if not '--path' in line: 6402 line += ' --path=%s' % path 6403 if has_nlo: 6404 line += ' --nlo' 6405 6406 try: 6407 out = self.mother_interface.do_compute_widths(line) 6408 except InvalidCmd, error: 6409 logger.error("Invalid command: %s " % error) 6410 else: 6411 if hasattr(self, 'run_card'): 6412 for pid, info in out.items(): 6413 total = 0 6414 for key, partial in info: 6415 total += partial 6416 mass = self.param_card.get_value('mass', pid) 6417 try: 6418 small_width_treatment = self.run_card['small_width_treatment'] 6419 except Exception: #NLO 6420 small_width_treatment = 0 6421 6422 if total and total/mass < small_width_treatment: 6423 text = "Particle %s with very small width (%g): Learn about special handling here: https://answers.launchpad.net/mg5amcnlo/+faq/3053" 6424 logger.warning(text,pid,total) 6425 elif total and total/mass < 1e-11: 6426 text = "Particle %s with very small width (%g): Numerical inaccuracies can occur if that particle is in a s-channel" 6427 logger.critical(text,pid,total)
6428 6429 6430
6431 - def help_compute_widths(self):
6432 signal.alarm(0) # avoid timer if any 6433 return self.mother_interface.help_compute_widths()
6434
6435 - def help_decay(self):
6436 """help for command decay which modifies MadSpin_card""" 6437 6438 signal.alarm(0) # avoid timer if any 6439 print '--syntax: decay PROC [--add]' 6440 print ' ' 6441 print ' modify the madspin_card to modify the decay of the associate particle.' 6442 print ' and define it to PROC.' 6443 print ' if --add is present, just add a new decay for the associate particle.'
6444
6445 - def complete_compute_widths(self, text, line, begidx, endidx, **opts):
6446 prev_timer = signal.alarm(0) # avoid timer if any 6447 if prev_timer: 6448 nb_back = len(line) 6449 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 6450 self.stdout.write(line) 6451 self.stdout.flush() 6452 return self.mother_interface.complete_compute_widths(text, line, begidx, endidx,**opts)
6453 6454
6455 - def help_add(self):
6456 """help for add command""" 6457 6458 logger.info('********************* HELP ADD ***************************') 6459 logger.info( '-- syntax: add pythia8_card NAME VALUE') 6460 logger.info( " add a definition of name in the pythia8_card with the given value") 6461 logger.info( " Do not work for the param_card" ) 6462 logger.info('') 6463 return self.help_edit(prefix=False)
6464
6465 - def help_edit(self, prefix=True):
6466 """help for edit command""" 6467 6468 if prefix: logger.info('********************* HELP ADD|EDIT ***************************') 6469 logger.info( '-- syntax: add filename [OPTION] LINE') 6470 logger.info( '-- syntax: edit filename [OPTION] LINE') 6471 logger.info( ' add the given LINE to the end of the associate file (all file supported).') 6472 logger.info( '') 6473 logger.info( ' OPTION parameter allows to change the position where to write in the file') 6474 logger.info( ' --after_line=banner : write the line at the end of the banner') 6475 logger.info( ' --line_position=X : insert the line before line X (starts at 0)') 6476 logger.info( ' --line_position=afterlast : insert the line after the latest inserted/modified line.') 6477 logger.info( ' --after_line="<regular-expression>" write the line after the first line matching the regular expression') 6478 logger.info( ' --before_line="<regular-expression>" write the line before the first line matching the regular expression') 6479 logger.info( ' --replace_line="<regular-expression>" replace the line matching the regular expression') 6480 logger.info( ' --clean remove all previously existing line in the file') 6481 logger.info('') 6482 logger.info(' Note: all regular-expression will be prefixed by ^\s*') 6483 logger.info('') 6484 logger.info( ' example: edit reweight --after_line="change mode\b" change model heft') 6485 logger.info( ' edit madspin --after_line="banner" change model XXXX') 6486 logger.info('********************* HELP ADD|EDIT ***************************')
6487 6488
6489 - def complete_add(self, text, line, begidx, endidx, formatting=True):
6490 """ auto-completion for add command""" 6491 6492 prev_timer = signal.alarm(0) # avoid timer if any 6493 if prev_timer: 6494 nb_back = len(line) 6495 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 6496 self.stdout.write(line) 6497 self.stdout.flush() 6498 6499 split = line[:begidx].split() 6500 if len(split)==1: 6501 possibilities = {} 6502 cards = [c.rsplit('.',1)[0] for c in self.cards] 6503 possibilities['category of parameter (optional)'] = \ 6504 self.list_completion(text, cards) 6505 elif len(split) == 2: 6506 possibilities = {} 6507 options = ['--line_position=','--line_position=afterlast','--after_line=banner', '--after_line="','--before_line="'] 6508 possibilities['category of parameter (optional)'] = \ 6509 self.list_completion(text, options, line) 6510 else: 6511 return 6512 return self.deal_multiple_categories(possibilities, formatting)
6513
6514 - def do_add(self, line):
6515 """ syntax: add filename NAME VALUE 6516 syntax: add filename LINE""" 6517 6518 args = self.split_arg(line) 6519 if len(args) == 3 and args[0] in ['pythia8_card', 'pythia8_card.dat'] and self.has_PY8: 6520 name= args[1] 6521 value = args[2] 6522 self.PY8Card.userSet(name, value) 6523 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'), 6524 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 6525 print_only_visible=True) 6526 logger.info("add in the pythia8_card the parameter \"%s\" with value \"%s\"" % (name, value), '$MG:BOLD') 6527 elif len(args) > 0: 6528 if args[0] in self.cards: 6529 card = args[0] 6530 elif "%s.dat" % args[0] in self.cards: 6531 card = "%s.dat" % args[0] 6532 elif "%s_card.dat" % args[0] in self.cards: 6533 card = "%s_card.dat" % args[0] 6534 elif self.has_ml and args[0].lower() == "madloop": 6535 card = "MadLoopParams.dat" 6536 else: 6537 logger.error("unknow card %s. Please retry." % args[0]) 6538 return 6539 # ensure that the card is in sync 6540 if card in self.modified_card: 6541 self.write_card(card) 6542 self.modified_card.discard(card) 6543 6544 if card in self.paths: 6545 path = self.paths[card] 6546 elif os.path.exists(card): 6547 path = card 6548 elif os.path.exists(pjoin(self.me_dir,'Cards',card)): 6549 path = pjoin(self.me_dir,'Cards',card) 6550 else: 6551 raise Exception, 'unknow path' 6552 6553 # handling the various option on where to write the line 6554 if args[1] == '--clean': 6555 ff = open(path,'w') 6556 ff.write("# %s \n" % card) 6557 ff.write("%s \n" % line.split(None,2)[2]) 6558 ff.close() 6559 logger.info("writing the line in %s (empty file) the line: \"%s\"" %(card, line.split(None,2)[2] ),'$MG:BOLD') 6560 elif args[1].startswith('--line_position=afterlast'): 6561 #position in file determined by user 6562 text = open(path).read() 6563 split = text.split('\n') 6564 if self.last_editline_pos > 0: 6565 pos = self.last_editline_pos +1 6566 newline = line.split(None,2)[2] 6567 split.insert(pos, newline) 6568 ff = open(path,'w') 6569 ff.write('\n'.join(split)) 6570 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD') 6571 self.last_editline_pos = pos 6572 elif args[1].startswith('--line_position='): 6573 #position in file determined by user 6574 text = open(path).read() 6575 split = text.split('\n') 6576 pos = int(args[1].split('=',1)[1]) 6577 newline = line.split(None,2)[2] 6578 split.insert(pos, newline) 6579 ff = open(path,'w') 6580 ff.write('\n'.join(split)) 6581 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD') 6582 self.last_editline_pos = pos 6583 6584 elif args[1].startswith(('--after_line=banner','--after_line=\'banner\'','--after_line=\"banner\"')): 6585 # write the line at the first not commented line 6586 text = open(path).read() 6587 split = text.split('\n') 6588 for posline,l in enumerate(split): 6589 if not l.startswith('#'): 6590 break 6591 split.insert(posline, line.split(None,2)[2]) 6592 ff = open(path,'w') 6593 ff.write('\n'.join(split)) 6594 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD') 6595 self.last_editline_pos = posline 6596 6597 elif args[1].startswith('--replace_line='): 6598 # catch the line/regular expression and replace the associate line 6599 # if no line match go to check if args[2] has other instruction starting with -- 6600 text = open(path).read() 6601 split = text.split('\n') 6602 search_pattern=r'''replace_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6603 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1] 6604 for posline,l in enumerate(split): 6605 if re.search(pattern, l): 6606 break 6607 else: 6608 new_line = re.split(search_pattern,line)[-1].strip() 6609 if new_line.startswith(('--before_line=','--after_line')): 6610 return self.do_add('%s %s' % (args[0], new_line)) 6611 raise Exception, 'invalid regular expression: not found in file' 6612 # found the line position "posline" 6613 # need to check if the a fail savety is present 6614 new_line = re.split(search_pattern,line)[-1].strip() 6615 if new_line.startswith(('--before_line=','--after_line')): 6616 search_pattern=r'''(?:before|after)_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6617 new_line = re.split(search_pattern,new_line)[-1] 6618 # overwrite the previous line 6619 old_line = split[posline] 6620 split[posline] = new_line 6621 ff = open(path,'w') 6622 ff.write('\n'.join(split)) 6623 logger.info("Replacing the line \"%s\" [line %d of %s] by \"%s\"" % 6624 (old_line, posline, card, new_line ),'$MG:BOLD') 6625 self.last_editline_pos = posline 6626 6627 6628 elif args[1].startswith('--before_line='): 6629 # catch the line/regular expression and write before that line 6630 text = open(path).read() 6631 split = text.split('\n') 6632 search_pattern=r'''before_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6633 pattern = '^\s*' + re.search(search_pattern, line).group()[13:-1] 6634 for posline,l in enumerate(split): 6635 if re.search(pattern, l): 6636 break 6637 else: 6638 raise Exception, 'invalid regular expression: not found in file' 6639 split.insert(posline, re.split(search_pattern,line)[-1]) 6640 ff = open(path,'w') 6641 ff.write('\n'.join(split)) 6642 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD') 6643 self.last_editline_pos = posline 6644 6645 elif args[1].startswith('--after_line='): 6646 # catch the line/regular expression and write after that line 6647 text = open(path).read() 6648 split = text.split('\n') 6649 search_pattern = r'''after_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6650 pattern = '^\s*' + re.search(search_pattern, line).group()[12:-1] 6651 for posline,l in enumerate(split): 6652 if re.search(pattern, l): 6653 break 6654 else: 6655 posline=len(split) 6656 split.insert(posline+1, re.split(search_pattern,line)[-1]) 6657 ff = open(path,'w') 6658 ff.write('\n'.join(split)) 6659 6660 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline+1, card, line.split(None,2)[2] ),'$MG:BOLD') 6661 self.last_editline_pos = posline+1 6662 6663 else: 6664 ff = open(path,'a') 6665 ff.write("%s \n" % line.split(None,1)[1]) 6666 ff.close() 6667 logger.info("adding at the end of the file %s the line: \"%s\"" %(card, line.split(None,1)[1] ),'$MG:BOLD') 6668 self.last_editline_pos = -1 6669 6670 self.reload_card(path)
6671 6672 do_edit = do_add 6673 complete_edit = complete_add 6674
6675 - def help_asperge(self):
6676 """Help associated to the asperge command""" 6677 signal.alarm(0) 6678 6679 print '-- syntax: asperge [options]' 6680 print ' Call ASperGe to diagonalize all mass matrices in the model.' 6681 print ' This works only if the ASperGE module is part of the UFO model (a subdirectory).' 6682 print ' If you specify some names after the command (i.e. asperge m1 m2) then ASperGe will only' 6683 print ' diagonalize the associate mass matrices (here m1 and m2).'
6684
6685 - def complete_asperge(self, text, line, begidx, endidx, formatting=True):
6686 prev_timer = signal.alarm(0) # avoid timer if any 6687 if prev_timer: 6688 nb_back = len(line) 6689 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 6690 self.stdout.write(line) 6691 self.stdout.flush() 6692 blockname = self.pname2block.keys() 6693 # remove those that we know for sure are not mixing 6694 wrong = ['decay', 'mass', 'sminput'] 6695 valid = [k for k in blockname if 'mix' in k] 6696 potential = [k for k in blockname if k not in valid+wrong] 6697 output = {'Mixing matrices': self.list_completion(text, valid, line), 6698 'Other potential valid input': self.list_completion(text, potential, line)} 6699 6700 return self.deal_multiple_categories(output, formatting)
6701 6702
6703 - def do_asperge(self, line):
6704 """Running ASperGe""" 6705 signal.alarm(0) # avoid timer if any 6706 6707 # ensure that the card is in sync 6708 if 'param' in self.modified_card: 6709 self.write_card('param') 6710 self.modified_card.discard('param') 6711 6712 6713 path = pjoin(self.me_dir,'bin','internal','ufomodel','ASperGE') 6714 if not os.path.exists(path): 6715 logger.error('ASperge has not been detected in the current model, therefore it will not be run.') 6716 return 6717 elif not os.path.exists(pjoin(path,'ASperGe')): 6718 logger.info('ASperGe has been detected but is not compiled. Running the compilation now.') 6719 try: 6720 misc.compile(cwd=path,shell=True) 6721 except MadGraph5Error, error: 6722 logger.error('''ASperGe failed to compile. Note that gsl is needed 6723 for this compilation to go trough. More information on how to install this package on 6724 http://www.gnu.org/software/gsl/ 6725 Full compilation log is available at %s''' % pjoin(self.me_dir, 'ASperge_compilation.log')) 6726 open(pjoin(self.me_dir, 'ASperge_compilation.log'),'w').write(str(error)) 6727 return 6728 6729 opts = line.split() 6730 card = self.paths['param'] 6731 logger.info('running ASperGE') 6732 returncode = misc.call([pjoin(path,'ASperGe'), card, '%s.new' % card] + opts) 6733 if returncode: 6734 logger.error('ASperGE fails with status %s' % returncode) 6735 else: 6736 logger.info('AsPerGe creates the file succesfully') 6737 files.mv(card, '%s.beforeasperge' % card) 6738 files.mv('%s.new' % card, card)
6739 6740 6741
6742 - def copy_file(self, path, pathname=None):
6743 """detect the type of the file and overwritte the current file""" 6744 6745 if not pathname: 6746 pathname = path 6747 6748 if path.endswith('.lhco'): 6749 #logger.info('copy %s as Events/input.lhco' % (path)) 6750 #files.cp(path, pjoin(self.mother_interface.me_dir, 'Events', 'input.lhco' )) 6751 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir)) 6752 return 6753 elif path.endswith('.lhco.gz'): 6754 #logger.info('copy %s as Events/input.lhco.gz' % (path)) 6755 #files.cp(path, pjoin(self.mother_interface.me_dir, 'Events', 'input.lhco.gz' )) 6756 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir)) 6757 return 6758 else: 6759 card_name = self.detect_card_type(path) 6760 6761 if card_name == 'unknown': 6762 logger.warning('Fail to determine the type of the file. Not copied') 6763 if card_name != 'banner': 6764 logger.info('copy %s as %s' % (pathname, card_name)) 6765 files.cp(path, self.paths[card_name.rsplit('_',1)[0]]) 6766 self.reload_card(self.paths[card_name.rsplit('_',1)[0]]) 6767 elif card_name == 'banner': 6768 banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False) 6769 logger.info('Splitting the banner in it\'s component') 6770 if not self.mode == 'auto': 6771 self.mother_interface.keep_cards(self.cards) 6772 for card_name in self.cards: 6773 self.reload_card(pjoin(self.me_dir, 'Cards', card_name))
6774
6775 - def detect_card_type(self, path):
6776 """detect card type""" 6777 6778 return CommonRunCmd.detect_card_type(path)
6779
6780 - def open_file(self, answer):
6781 """open the file""" 6782 6783 try: 6784 me_dir = self.mother_interface.me_dir 6785 except: 6786 me_dir = None 6787 6788 if answer.isdigit(): 6789 if answer == '9': 6790 answer = 'plot' 6791 else: 6792 answer = self.cards[int(answer)-self.integer_bias] 6793 6794 if 'madweight' in answer: 6795 answer = answer.replace('madweight', 'MadWeight') 6796 elif 'MadLoopParams' in answer: 6797 answer = self.paths['ML'] 6798 elif 'pythia8_card' in answer: 6799 answer = self.paths['pythia8'] 6800 if os.path.exists(answer): 6801 path = answer 6802 else: 6803 if not '.dat' in answer and not '.lhco' in answer: 6804 if answer != 'trigger': 6805 path = self.paths[answer] 6806 else: 6807 path = self.paths['delphes'] 6808 elif not '.lhco' in answer: 6809 if '_' in answer: 6810 path = self.paths['_'.join(answer.split('_')[:-1])] 6811 else: 6812 path = pjoin(me_dir, 'Cards', answer) 6813 else: 6814 path = pjoin(me_dir, self.mw_card['mw_run']['inputfile']) 6815 if not os.path.exists(path): 6816 logger.info('Path in MW_card not existing') 6817 path = pjoin(me_dir, 'Events', answer) 6818 #security 6819 path = path.replace('_card_card','_card') 6820 6821 if answer in self.modified_card: 6822 self.write_card(answer) 6823 elif os.path.basename(answer.replace('_card.dat','')) in self.modified_card: 6824 self.write_card(os.path.basename(answer.replace('_card.dat',''))) 6825 6826 try: 6827 self.mother_interface.exec_cmd('open %s' % path) 6828 except InvalidCmd, error: 6829 if str(error) != 'No default path for this file': 6830 raise 6831 if answer == 'transfer_card.dat': 6832 logger.warning('You have to specify a transfer function first!') 6833 elif answer == 'input.lhco': 6834 path = pjoin(me_dir,'Events', 'input.lhco') 6835 ff = open(path,'w') 6836 ff.write('''No LHCO information imported at current time. 6837 To import a lhco file: Close this file and type the path of your file. 6838 You can also copy/paste, your event file here.''') 6839 ff.close() 6840 self.open_file(path) 6841 else: 6842 raise 6843 self.reload_card(path)
6844
6845 - def reload_card(self, path):
6846 """reload object to have it in sync""" 6847 6848 if path == self.paths['param']: 6849 try: 6850 self.param_card = param_card_mod.ParamCard(path) 6851 except (param_card_mod.InvalidParamCard, ValueError) as e: 6852 logger.error('Current param_card is not valid. We are going to use the default one.') 6853 logger.error('problem detected: %s' % e) 6854 logger.error('Please re-open the file and fix the problem.') 6855 logger.warning('using the \'set\' command without opening the file will discard all your manual change') 6856 elif path == self.paths['run']: 6857 self.run_card = banner_mod.RunCard(path) 6858 elif path == self.paths['shower']: 6859 self.shower_card = shower_card_mod.ShowerCard(path) 6860 elif path == self.paths['ML']: 6861 self.MLcard = banner_mod.MadLoopParam(path) 6862 elif path == self.paths['pythia8']: 6863 # Use the read function so that modified/new parameters are correctly 6864 # set as 'user_set' 6865 if not self.PY8Card: 6866 self.PY8Card = self.PY8Card_class(self.paths['pythia8_default']) 6867 6868 self.PY8Card.read(self.paths['pythia8'], setter='user') 6869 self.py8_vars = [k.lower() for k in self.PY8Card.keys()] 6870 elif path == self.paths['MadWeight']: 6871 try: 6872 import madgraph.madweight.Cards as mwcards 6873 except: 6874 import internal.madweight.Cards as mwcards 6875 self.mw_card = mwcards.Card(path) 6876 else: 6877 logger.debug('not keep in sync: %s', path) 6878 return path 6879
6880 6881 # A decorator function to handle in a nice way scan/auto width 6882 -def scanparamcardhandling(input_path=lambda obj: pjoin(obj.me_dir, 'Cards', 'param_card.dat'), 6883 store_for_scan=lambda obj: obj.store_scan_result, 6884 get_run_name=lambda obj: obj.run_name, 6885 set_run_name=lambda obj: obj.set_run_name, 6886 result_path=lambda obj: pjoin(obj.me_dir, 'Events', 'scan_%s.txt' ), 6887 ignoreerror=ZeroResult, 6888 iteratorclass=param_card_mod.ParamCardIterator, 6889 summaryorder=lambda obj: lambda:None, 6890 check_card=lambda obj: CommonRunCmd.static_check_param_card, 6891 ):
6892 """ This is a decorator for customizing/using scan over the param_card (or technically other) 6893 This should be use like this: 6894 6895 @scanparamcardhandling(arguments) 6896 def run_launch(self, *args, **opts) 6897 6898 possible arguments are listed above and should be function who takes a single 6899 argument the instance of intereset. those return 6900 input_path -> function that return the path of the card to read 6901 store_for_scan -> function that return a dict of entry to keep in memory 6902 get_run_name -> function that return the string with the current run_name 6903 set_run_name -> function that return the function that allow the set the next run_name 6904 result_path -> function that return the path of the summary result to write 6905 ignoreerror -> one class of error which are not for the error 6906 IteratorClass -> class to use for the iterator 6907 summaryorder -> function that return the function to call to get the order 6908 6909 advanced: 6910 check_card -> function that return the function to read the card and init stuff (compute auto-width/init self.iterator/...) 6911 This function should define the self.param_card_iterator if a scan exists 6912 and the one calling the auto-width functionalities/... 6913 6914 All the function are taking a single argument (an instance of the class on which the decorator is used) 6915 and they can either return themself a function or a string. 6916 6917 Note: 6918 1. the link to auto-width is not fully trivial due to the model handling 6919 a. If you inherit from CommonRunCmd (or if the self.mother is). Then 6920 everything should be automatic. 6921 6922 b. If you do not you can/should create the funtion self.get_model(). 6923 Which returns the appropriate MG model (like the one from import_ufo.import_model) 6924 6925 c. You can also have full control by defining your own do_compute_widths(self, line) 6926 functions. 6927 """ 6928 class restore_iterator(object): 6929 """ensure that the original card is always restore even for crash""" 6930 def __init__(self, iterator, path): 6931 self.iterator = iterator 6932 self.path = path
6933 6934 def __enter__(self): 6935 return self.iterator 6936 6937 def __exit__(self, ctype, value, traceback ): 6938 self.iterator.write(self.path) 6939 6940 def decorator(original_fct): 6941 def new_fct(obj, *args, **opts): 6942 6943 if isinstance(input_path, str): 6944 card_path = input_path 6945 else: 6946 card_path = input_path(obj) 6947 6948 # 6949 # This is the function that 6950 # 1. compute the widths 6951 # 2. define the scan iterator 6952 # 3. raise some warning 6953 # 4. update dependent parameter (off by default but for scan) 6954 # if scan is found object.param_card_iterator should be define by the function 6955 check_card(obj)(card_path, obj, iterator_class=iteratorclass) 6956 6957 param_card_iterator = None 6958 if obj.param_card_iterator: 6959 param_card_iterator = obj.param_card_iterator 6960 obj.param_card_iterator = [] # ensure that the code does not re-trigger a scan 6961 6962 if not param_card_iterator: 6963 #first run of the function 6964 original_fct(obj, *args, **opts) 6965 return 6966 6967 with restore_iterator(param_card_iterator, card_path): 6968 # this with statement ensure that the original card is restore 6969 # whatever happens inside those block 6970 6971 if not hasattr(obj, 'allow_notification_center'): 6972 obj.allow_notification_center = False 6973 with misc.TMP_variable(obj, 'allow_notification_center', False): 6974 orig_name = get_run_name(obj) 6975 next_name = orig_name 6976 #next_name = param_card_iterator.get_next_name(orig_name) 6977 set_run_name(obj)(next_name) 6978 # run for the first time 6979 original_fct(obj, *args, **opts) 6980 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path) 6981 for card in param_card_iterator: 6982 card.write(card_path) 6983 # still have to check for the auto-wdith 6984 check_card(obj)(card_path, obj, dependent=True) 6985 next_name = param_card_iterator.get_next_name(next_name) 6986 set_run_name(obj)(next_name) 6987 try: 6988 original_fct(obj, *args, **opts) 6989 except ignoreerror, error: 6990 param_card_iterator.store_entry(next_name, {'exception': error}) 6991 else: 6992 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path) 6993 6994 #param_card_iterator.write(card_path) #-> this is done by the with statement 6995 name = misc.get_scan_name(orig_name, next_name) 6996 path = result_path(obj) % name 6997 logger.info("write scan results in %s" % path ,'$MG:BOLD') 6998 order = summaryorder(obj)() 6999 param_card_iterator.write_summary(path, order=order) 7000 return new_fct 7001 return decorator 7002