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

Source Code for Module madgraph.interface.common_run_interface

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