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