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