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