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