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 2271 2272 args = self.split_arg(line) 2273 opts = self.check_compute_widths(args) 2274 2275 from madgraph.interface.master_interface import MasterCmd 2276 cmd = MasterCmd() 2277 self.define_child_cmd_interface(cmd, interface=False) 2278 cmd.options.update(self.options) 2279 cmd.exec_cmd('set automatic_html_opening False --no_save') 2280 if not opts['path']: 2281 opts['path'] = pjoin(self.me_dir, 'Cards', 'param_card.dat') 2282 if not opts['force'] : 2283 self.ask_edit_cards(['param_card.dat'],[], plot=False) 2284 2285 2286 line = 'compute_widths %s %s' % \ 2287 (' '.join([str(i) for i in opts['particles']]), 2288 ' '.join('--%s=%s' % (key,value) for (key,value) in opts.items() 2289 if key not in ['model', 'force', 'particles'] and value)) 2290 cmd.exec_cmd(line, model=opts['model']) 2291 self.child = None 2292 del cmd
2293 2294 ############################################################################
2295 - def do_print_results(self, line):
2296 """Not in help:Print the cross-section/ number of events for a given run""" 2297 2298 args = self.split_arg(line) 2299 options={'path':None, 'mode':'w', 'format':'full'} 2300 for arg in list(args): 2301 if arg.startswith('--') and '=' in arg: 2302 name,value=arg.split('=',1) 2303 name = name [2:] 2304 options[name] = value 2305 args.remove(arg) 2306 2307 2308 if len(args) > 0: 2309 run_name = args[0] 2310 else: 2311 for i, run_name in enumerate(self.results.order): 2312 for j, one_result in enumerate(self.results[run_name]): 2313 if i or j: 2314 options['mode'] = "a" 2315 if options['path']: 2316 self.print_results_in_file(one_result, options['path'], options['mode'], options['format']) 2317 else: 2318 self.print_results_in_shell(one_result) 2319 return 2320 2321 if run_name not in self.results: 2322 raise self.InvalidCmd('%s is not a valid run_name or it doesn\'t have any information' \ 2323 % run_name) 2324 2325 2326 if len(args) == 2: 2327 tag = args[1] 2328 if tag.isdigit(): 2329 tag = int(tag) - 1 2330 if len(self.results[run_name]) < tag: 2331 raise self.InvalidCmd('Only %s different tag available' % \ 2332 len(self.results[run_name])) 2333 data = self.results[run_name][tag] 2334 else: 2335 data = self.results[run_name].return_tag(tag) 2336 else: 2337 data = self.results[run_name].return_tag(None) # return the last 2338 2339 if options['path']: 2340 self.print_results_in_file(data, options['path'], options['mode'], options['format']) 2341 else: 2342 self.print_results_in_shell(data)
2343
2344 - def configure_directory(self, *args, **opts):
2345 """ All action require before any type of run. Typically overloaded by 2346 daughters if need be.""" 2347 pass
2348 2349 ############################################################################ 2350 # Start of MadAnalysis5 related function 2351 ############################################################################ 2352 2353 @staticmethod
2354 - def runMA5(MA5_interpreter, MA5_cmds, MA5_runtag, logfile_path, advertise_log=True):
2355 """ Run MA5 in a controlled environnment.""" 2356 successfull_MA5_run = True 2357 2358 try: 2359 # Predefine MA5_logger as None in case we don't manage to retrieve it. 2360 MA5_logger = None 2361 MA5_logger = logging.getLogger('MA5') 2362 BackUp_MA5_handlers = MA5_logger.handlers 2363 for handler in BackUp_MA5_handlers: 2364 MA5_logger.removeHandler(handler) 2365 file_handler = logging.FileHandler(logfile_path) 2366 MA5_logger.addHandler(file_handler) 2367 if advertise_log: 2368 logger.info("Follow Madanalysis5 run with the following command in a separate terminal:") 2369 logger.info(' tail -f %s'%logfile_path) 2370 # Now the magic, finally call MA5. 2371 with misc.stdchannel_redirected(sys.stdout, os.devnull): 2372 with misc.stdchannel_redirected(sys.stderr, os.devnull): 2373 MA5_interpreter.print_banner() 2374 MA5_interpreter.load(MA5_cmds) 2375 except Exception as e: 2376 logger.warning("MadAnalysis5 failed to run the commands for task "+ 2377 "'%s'. Madanalys5 analysis will be skipped."%MA5_runtag) 2378 error=StringIO.StringIO() 2379 traceback.print_exc(file=error) 2380 logger.debug('MadAnalysis5 error was:') 2381 logger.debug('-'*60) 2382 logger.debug(error.getvalue()[:-1]) 2383 logger.debug('-'*60) 2384 successfull_MA5_run = False 2385 finally: 2386 if not MA5_logger is None: 2387 for handler in MA5_logger.handlers: 2388 MA5_logger.removeHandler(handler) 2389 for handler in BackUp_MA5_handlers: 2390 MA5_logger.addHandler(handler) 2391 2392 return successfull_MA5_run
2393 2394 #=============================================================================== 2395 # Return a Main instance of MadAnlysis5, provided its path 2396 #=============================================================================== 2397 @staticmethod
2398 - def get_MadAnalysis5_interpreter(mg5_path, ma5_path, mg5_interface=None, 2399 logstream = sys.stdout, loglevel =logging.INFO, forced = True, 2400 compilation=False):
2401 """ Makes sure to correctly setup paths and constructs and return an MA5 path""" 2402 2403 MA5path = os.path.normpath(pjoin(mg5_path,ma5_path)) 2404 2405 if MA5path is None or not os.path.isfile(pjoin(MA5path,'bin','ma5')): 2406 return None 2407 if MA5path not in sys.path: 2408 sys.path.insert(0, MA5path) 2409 2410 try: 2411 # We must backup the readline module attributes because they get modified 2412 # when MA5 imports root and that supersedes MG5 autocompletion 2413 import readline 2414 old_completer = readline.get_completer() 2415 old_delims = readline.get_completer_delims() 2416 old_history = [readline.get_history_item(i) for i in range(1,readline.get_current_history_length()+1)] 2417 except ImportError: 2418 old_completer, old_delims, old_history = None, None, None 2419 try: 2420 from madanalysis.interpreter.ma5_interpreter import MA5Interpreter 2421 with misc.stdchannel_redirected(sys.stdout, os.devnull): 2422 with misc.stdchannel_redirected(sys.stderr, os.devnull): 2423 MA5_interpreter = MA5Interpreter(MA5path, LoggerLevel=loglevel, 2424 LoggerStream=logstream,forced=forced, 2425 no_compilation=not compilation) 2426 except Exception as e: 2427 logger.warning('MadAnalysis5 failed to start so that MA5 analysis will be skipped.') 2428 error=StringIO.StringIO() 2429 traceback.print_exc(file=error) 2430 logger.debug('MadAnalysis5 error was:') 2431 logger.debug('-'*60) 2432 logger.debug(error.getvalue()[:-1]) 2433 logger.debug('-'*60) 2434 MA5_interpreter = None 2435 finally: 2436 # Now restore the readline MG5 state 2437 if not old_history is None: 2438 readline.clear_history() 2439 for line in old_history: 2440 readline.add_history(line) 2441 if not old_completer is None: 2442 readline.set_completer(old_completer) 2443 if not old_delims is None: 2444 readline.set_completer_delims(old_delims) 2445 # Also restore the completion_display_matches_hook if an mg5 interface 2446 # is specified as it could also have been potentially modified 2447 if not mg5_interface is None and any(not elem is None for elem in [old_completer, old_delims, old_history]): 2448 mg5_interface.set_readline_completion_display_matches_hook() 2449 2450 return MA5_interpreter
2451
2452 - def check_madanalysis5(self, args, mode='parton'):
2453 """Check the argument for the madanalysis5 command 2454 syntax: madanalysis5_parton [NAME] 2455 """ 2456 2457 MA5_options = {'MA5_stdout_lvl':'default'} 2458 2459 stdout_level_tags = [a for a in args if a.startswith('--MA5_stdout_lvl=')] 2460 for slt in stdout_level_tags: 2461 lvl = slt.split('=')[1].strip() 2462 try: 2463 # It is likely an int 2464 MA5_options['MA5_stdout_lvl']=int(lvl) 2465 except ValueError: 2466 if lvl.startswith('logging.'): 2467 lvl = lvl[8:] 2468 try: 2469 MA5_options['MA5_stdout_lvl'] = getattr(logging, lvl) 2470 except: 2471 raise InvalidCmd("MA5 output level specification"+\ 2472 " '%s' is incorrect." % str(lvl)) 2473 args.remove(slt) 2474 2475 if mode=='parton': 2476 # We will attempt to run MA5 on the parton level output 2477 # found in the last run if not specified. 2478 MA5_options['inputs'] = '*.lhe' 2479 elif mode=='hadron': 2480 # We will run MA5 on all sources of post-partonic output we 2481 # can find if not specified. PY8 is a keyword indicating shower 2482 # piped to MA5. 2483 MA5_options['inputs'] = ['fromCard'] 2484 else: 2485 raise MadGraph5Error('Mode %s not reckognized'%mode+ 2486 ' in function check_madanalysis5.') 2487 # If not madanalysis5 path 2488 if not self.options['madanalysis5_path']: 2489 logger.info('Now trying to read the configuration file again'+ 2490 ' to find MadAnalysis5 path') 2491 self.set_configuration() 2492 2493 if not self.options['madanalysis5_path'] or not \ 2494 os.path.exists(pjoin(self.options['madanalysis5_path'],'bin','ma5')): 2495 error_msg = 'No valid MadAnalysis5 path set.\n' 2496 error_msg += 'Please use the set command to define the path and retry.\n' 2497 error_msg += 'You can also define it in the configuration file.\n' 2498 error_msg += 'Finally, it can be installed automatically using the' 2499 error_msg += ' install command.\n' 2500 raise self.InvalidCmd(error_msg) 2501 2502 # Now make sure that the corresponding default card exists 2503 if not os.path.isfile(pjoin(self.me_dir, 2504 'Cards','madanalysis5_%s_card.dat'%mode)): 2505 raise self.InvalidCmd('Your installed version of MadAnalysis5 and/or'+\ 2506 ' MadGraph5_aMCatNLO does not seem to support analysis at'+ 2507 '%s level.'%mode) 2508 2509 tag = [a for a in args if a.startswith('--tag=')] 2510 if tag: 2511 args.remove(tag[0]) 2512 tag = tag[0][6:] 2513 2514 if len(args) == 0 and not self.run_name: 2515 if self.results.lastrun: 2516 args.insert(0, self.results.lastrun) 2517 else: 2518 raise self.InvalidCmd('No run name currently defined. '+ 2519 'Please add this information.') 2520 2521 if len(args) >= 1: 2522 if mode=='parton' and args[0] != self.run_name and \ 2523 not os.path.exists(pjoin(self.me_dir,'Events',args[0], 2524 'unweighted_events.lhe.gz')) and not os.path.exists( 2525 pjoin(self.me_dir,'Events',args[0])): 2526 raise self.InvalidCmd('No events file in the %s run.'%args[0]) 2527 self.set_run_name(args[0], tag, level='madanalysis5_%s'%mode) 2528 else: 2529 if tag: 2530 self.run_card['run_tag'] = args[0] 2531 self.set_run_name(self.run_name, tag, level='madanalysis5_%s'%mode) 2532 2533 if mode=='parton': 2534 if any(t for t in args if t.startswith('--input=')): 2535 raise InvalidCmd('The option --input=<input_file> is not'+ 2536 ' available when running partonic MadAnalysis5 analysis. The'+ 2537 ' .lhe output of the selected run is used automatically.') 2538 input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe') 2539 MA5_options['inputs'] = '%s.gz'%input_file 2540 if not os.path.exists('%s.gz'%input_file): 2541 if os.path.exists(input_file): 2542 misc.gzip(input_file, stdout='%s.gz' % input_file) 2543 else: 2544 logger.warning("LHE event file not found in \n%s\ns"%input_file+ 2545 "Parton-level MA5 analysis will be skipped.") 2546 2547 if mode=='hadron': 2548 # Make sure to store current results (like Pythia8 hep files) 2549 # so that can be found here 2550 self.store_result() 2551 2552 hadron_tag = [t for t in args if t.startswith('--input=')] 2553 if hadron_tag and hadron_tag[0][8:]: 2554 hadron_inputs = hadron_tag[0][8:].split(',') 2555 2556 # If not set above, then we must read it from the card 2557 elif MA5_options['inputs'] == ['fromCard']: 2558 hadron_inputs = banner_mod.MadAnalysis5Card(pjoin(self.me_dir, 2559 'Cards','madanalysis5_hadron_card.dat'),mode='hadron')['inputs'] 2560 2561 # Make sure the corresponding input files are present and unfold 2562 # potential wildcard while making their path absolute as well. 2563 MA5_options['inputs'] = [] 2564 special_source_tags = [] 2565 for htag in hadron_inputs: 2566 # Possible pecial tag for MA5 run inputs 2567 if htag in special_source_tags: 2568 # Special check/actions 2569 continue 2570 # Check if the specified file exists and is not a wildcard 2571 if os.path.isfile(htag) or (os.path.exists(htag) and 2572 stat.S_ISFIFO(os.stat(htag).st_mode)): 2573 MA5_options['inputs'].append(htag) 2574 continue 2575 2576 # Now select one source per tag, giving priority to unzipped 2577 # files with 'events' in their name (case-insensitive). 2578 file_candidates = misc.glob(htag, pjoin(self.me_dir,'Events',self.run_name))+\ 2579 misc.glob('%s.gz'%htag, pjoin(self.me_dir,'Events',self.run_name)) 2580 priority_files = [f for f in file_candidates if 2581 self.run_card['run_tag'] in os.path.basename(f)] 2582 priority_files = [f for f in priority_files if 2583 'EVENTS' in os.path.basename(f).upper()] 2584 # Make sure to always prefer the original partonic event file 2585 for f in file_candidates: 2586 if os.path.basename(f).startswith('unweighted_events.lhe'): 2587 priority_files.append(f) 2588 if priority_files: 2589 MA5_options['inputs'].append(priority_files[-1]) 2590 continue 2591 if file_candidates: 2592 MA5_options['inputs'].append(file_candidates[-1]) 2593 continue 2594 2595 return MA5_options
2596
2597 - def ask_madanalysis5_run_configuration(self, runtype='parton',mode=None):
2598 """Ask the question when launching madanalysis5. 2599 In the future we can ask here further question about the MA5 run, but 2600 for now we just edit the cards""" 2601 2602 cards = ['madanalysis5_%s_card.dat'%runtype] 2603 self.keep_cards(cards) 2604 2605 if self.force: 2606 return runtype 2607 2608 # This heavy-looking structure of auto is just to mimick what is done 2609 # for ask_pythia_configuration 2610 auto=False 2611 if mode=='auto': 2612 auto=True 2613 if auto: 2614 self.ask_edit_cards(cards, mode='auto', plot=False) 2615 else: 2616 self.ask_edit_cards(cards, plot=False) 2617 2618 # For now, we don't pass any further information and simply return the 2619 # input mode asked for 2620 mode = runtype 2621 return mode
2622
2623 - def complete_madanalysis5_hadron(self,text, line, begidx, endidx):
2624 "Complete the madanalysis5 command" 2625 args = self.split_arg(line[0:begidx], error=False) 2626 if len(args) == 1: 2627 #return valid run_name 2628 data = [] 2629 for name in banner_mod.MadAnalysis5Card._default_hadron_inputs: 2630 data += misc.glob(pjoin('*','%s'%name), pjoin(self.me_dir, 'Events')) 2631 data += misc.glob(pjoin('*','%s.gz'%name), pjoin(self.me_dir, 'Events')) 2632 data = [n.rsplit('/',2)[1] for n in data] 2633 tmp1 = self.list_completion(text, data) 2634 if not self.run_name: 2635 return tmp1 2636 else: 2637 tmp2 = self.list_completion(text, ['-f', 2638 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line) 2639 return tmp1 + tmp2 2640 2641 elif '--MA5_stdout_lvl=' in line and not any(arg.startswith( 2642 '--MA5_stdout_lvl=') for arg in args): 2643 return self.list_completion(text, 2644 ['--MA5_stdout_lvl=%s'%opt for opt in 2645 ['logging.INFO','logging.DEBUG','logging.WARNING', 2646 'logging.CRITICAL','90']], line) 2647 elif '--input=' in line and not any(arg.startswith( 2648 '--input=') for arg in args): 2649 return self.list_completion(text, ['--input=%s'%opt for opt in 2650 (banner_mod.MadAnalysis5Card._default_hadron_inputs +['path'])], line) 2651 else: 2652 return self.list_completion(text, ['-f', 2653 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line)
2654
2655 - def do_madanalysis5_hadron(self, line):
2656 """launch MadAnalysis5 at the hadron level.""" 2657 return self.run_madanalysis5(line,mode='hadron')
2658
2659 - def run_madanalysis5(self, line, mode='parton'):
2660 """launch MadAnalysis5 at the parton level or at the hadron level with 2661 a specific command line.""" 2662 2663 # Check argument's validity 2664 args = self.split_arg(line) 2665 2666 if '--no_default' in args: 2667 no_default = True 2668 args.remove('--no_default') 2669 else: 2670 no_default = False 2671 2672 if no_default: 2673 # Called issued by MG5aMC itself during a generate_event action 2674 if mode=='parton' and not os.path.exists(pjoin(self.me_dir, 'Cards', 2675 'madanalysis5_parton_card.dat')): 2676 return 2677 if mode=='hadron' and not os.path.exists(pjoin(self.me_dir, 'Cards', 2678 'madanalysis5_hadron_card.dat')): 2679 return 2680 else: 2681 # Called issued by the user itself and only MA5 will be run. 2682 # we must therefore ask wheter the user wants to edit the card 2683 self.ask_madanalysis5_run_configuration(runtype=mode) 2684 2685 if not self.options['madanalysis5_path'] or \ 2686 all(not os.path.exists(pjoin(self.me_dir, 'Cards',card)) for card in 2687 ['madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat']): 2688 if no_default: 2689 return 2690 else: 2691 raise InvalidCmd('You must have MadAnalysis5 available to run'+ 2692 " this command. Consider installing it with the 'install' function.") 2693 2694 if not self.run_name: 2695 MA5_opts = self.check_madanalysis5(args, mode=mode) 2696 self.configure_directory(html_opening =False) 2697 else: 2698 # initialize / remove lhapdf mode 2699 self.configure_directory(html_opening =False) 2700 MA5_opts = self.check_madanalysis5(args, mode=mode) 2701 2702 # Now check that there is at least one input to run 2703 if MA5_opts['inputs']==[]: 2704 if no_default: 2705 logger.warning('No hadron level input found to run MadAnalysis5 on.'+ 2706 ' Skipping its hadron-level analysis.') 2707 return 2708 else: 2709 raise self.InvalidCmd('\nNo input files specified or availabled for'+ 2710 ' this MadAnalysis5 hadron-level run.\nPlease double-check the options of this'+ 2711 ' MA5 command (or card) and which output files\nare currently in the chosen'+ 2712 " run directory '%s'."%self.run_name) 2713 2714 MA5_card = banner_mod.MadAnalysis5Card(pjoin(self.me_dir, 'Cards', 2715 'madanalysis5_%s_card.dat'%mode), mode=mode) 2716 2717 if MA5_card._skip_analysis: 2718 logger.info('Madanalysis5 %s-level analysis was skipped following user request.'%mode) 2719 logger.info("To run the analysis, remove or comment the tag '%s skip_analysis' " 2720 %banner_mod.MadAnalysis5Card._MG5aMC_escape_tag+ 2721 "in\n '%s'."%pjoin(self.me_dir, 'Cards','madanalysis5_%s_card.dat'%mode)) 2722 return 2723 2724 MA5_cmds_list = MA5_card.get_MA5_cmds(MA5_opts['inputs'], 2725 pjoin(self.me_dir,'MA5_%s_ANALYSIS'%mode.upper()), 2726 run_dir_path = pjoin(self.me_dir,'Events', self.run_name), 2727 UFO_model_path=pjoin(self.me_dir,'bin','internal','ufomodel'), 2728 run_tag = self.run_tag) 2729 2730 # Here's how to print the MA5 commands generated by MG5aMC 2731 # for MA5_runtag, MA5_cmds in MA5_cmds_list: 2732 # misc.sprint('****************************************') 2733 # misc.sprint('* Commands for MA5 runtag %s:'%MA5_runtag) 2734 # misc.sprint('\n'+('\n'.join('* %s'%cmd for cmd in MA5_cmds))) 2735 # misc.sprint('****************************************') 2736 2737 self.update_status('\033[92mRunning MadAnalysis5 [arXiv:1206.1599]\033[0m', 2738 level='madanalysis5_%s'%mode) 2739 if mode=='hadron': 2740 logger.info('Hadron input files considered:') 2741 for input in MA5_opts['inputs']: 2742 logger.info(' --> %s'%input) 2743 elif mode=='parton': 2744 logger.info('Parton input file considered:') 2745 logger.info(' --> %s'%MA5_opts['inputs']) 2746 2747 # Obtain a main MA5 interpreter 2748 # Ideally we would like to do it all with a single interpreter 2749 # but we'd need a way to reset it for this. 2750 if MA5_opts['MA5_stdout_lvl']=='default': 2751 if MA5_card['stdout_lvl'] is None: 2752 MA5_lvl = self.options['stdout_level'] 2753 else: 2754 MA5_lvl = MA5_card['stdout_lvl'] 2755 else: 2756 MA5_lvl = MA5_opts['MA5_stdout_lvl'] 2757 2758 # Bypass initialization information 2759 MA5_interpreter = CommonRunCmd.get_MadAnalysis5_interpreter( 2760 self.options['mg5_path'], 2761 self.options['madanalysis5_path'], 2762 logstream=sys.stdout, 2763 loglevel=100, 2764 forced=True, 2765 compilation=True) 2766 2767 2768 # If failed to start MA5, then just leave 2769 if MA5_interpreter is None: 2770 return 2771 2772 # Make sure to only run over one analysis over each fifo. 2773 used_up_fifos = [] 2774 # Now loop over the different MA5_runs 2775 for MA5_run_number, (MA5_runtag, MA5_cmds) in enumerate(MA5_cmds_list): 2776 2777 # Since we place every MA5 run in a fresh new folder, the MA5_run_number 2778 # is always zero. 2779 MA5_run_number = 0 2780 # Bypass the banner. 2781 MA5_interpreter.setLogLevel(100) 2782 # Make sure to properly initialize MA5 interpreter 2783 if mode=='hadron': 2784 MA5_interpreter.init_reco() 2785 else: 2786 MA5_interpreter.init_parton() 2787 MA5_interpreter.setLogLevel(MA5_lvl) 2788 2789 if MA5_runtag!='default': 2790 if MA5_runtag.startswith('_reco_'): 2791 logger.info("MadAnalysis5 now running the reconstruction '%s'..."% 2792 MA5_runtag[6:],'$MG:color:GREEN') 2793 elif MA5_runtag=='Recasting': 2794 logger.info("MadAnalysis5 now running the recasting...", 2795 '$MG:color:GREEN') 2796 else: 2797 logger.info("MadAnalysis5 now running the '%s' analysis..."% 2798 MA5_runtag,'$MG:color:GREEN') 2799 2800 2801 # Now the magic, let's call MA5 2802 if not CommonRunCmd.runMA5(MA5_interpreter, MA5_cmds, MA5_runtag, 2803 pjoin(self.me_dir,'Events',self.run_name,'%s_MA5_%s.log'%(self.run_tag,MA5_runtag))): 2804 # Unsuccessful MA5 run, we therefore stop here. 2805 return 2806 2807 if MA5_runtag.startswith('_reco_'): 2808 # When doing a reconstruction we must first link the event file 2809 # created with MA5 reconstruction and then directly proceed to the 2810 # next batch of instructions. There can be several output directory 2811 # if there were several input files. 2812 links_created=[] 2813 for i, input in enumerate(MA5_opts['inputs']): 2814 # Make sure it is not an lhco or root input, which would not 2815 # undergo any reconstruction of course. 2816 if not banner_mod.MadAnalysis5Card.events_can_be_reconstructed(input): 2817 continue 2818 2819 if input.endswith('.fifo'): 2820 if input in used_up_fifos: 2821 # Only run once on each fifo 2822 continue 2823 else: 2824 used_up_fifos.append(input) 2825 2826 reco_output = pjoin(self.me_dir, 2827 'MA5_%s_ANALYSIS%s_%d'%(mode.upper(),MA5_runtag,i+1)) 2828 # Look for either a root or .lhe.gz output 2829 reco_event_file = misc.glob('*.lhe.gz',pjoin(reco_output,'Output','_reco_events','lheEvents0_%d'%MA5_run_number))+\ 2830 misc.glob('*.root',pjoin(reco_output,'Output','_reco_events', 'RecoEvents0_%d'%MA5_run_number)) 2831 if len(reco_event_file)==0: 2832 raise MadGraph5Error, "MadAnalysis5 failed to produce the "+\ 2833 "reconstructed event file for reconstruction '%s'."%MA5_runtag[6:] 2834 reco_event_file = reco_event_file[0] 2835 # move the reconstruction output to the HTML directory 2836 shutil.move(reco_output,pjoin(self.me_dir,'HTML', 2837 self.run_name,'%s_MA5_%s_ANALYSIS%s_%d'% 2838 (self.run_tag,mode.upper(),MA5_runtag,i+1))) 2839 2840 # link the reconstructed event file to the run directory 2841 links_created.append(os.path.basename(reco_event_file)) 2842 parent_dir_name = os.path.basename(os.path.dirname(reco_event_file)) 2843 files.ln(pjoin(self.me_dir,'HTML',self.run_name, 2844 '%s_MA5_%s_ANALYSIS%s_%d'%(self.run_tag,mode.upper(), 2845 MA5_runtag,i+1),'Output','_reco_events',parent_dir_name,links_created[-1]), 2846 pjoin(self.me_dir,'Events',self.run_name)) 2847 2848 logger.info("MadAnalysis5 successfully completed the reconstruction "+ 2849 "'%s'. Links to the reconstructed event files are:"%MA5_runtag[6:]) 2850 for link in links_created: 2851 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,link)) 2852 continue 2853 2854 if MA5_runtag.upper()=='RECASTING': 2855 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\ 2856 %(mode.upper(),MA5_runtag),'Output','CLs_output_summary.dat') 2857 else: 2858 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\ 2859 %(mode.upper(),MA5_runtag),'Output','PDF','MadAnalysis5job_%d'%MA5_run_number,'main.pdf') 2860 has_pdf = True 2861 if not os.path.isfile(target): 2862 has_pdf = False 2863 2864 # Copy the PDF report or CLs in the Events/run directory. 2865 if MA5_runtag.upper()=='RECASTING': 2866 carboncopy_name = '%s_MA5_CLs.dat'%(self.run_tag) 2867 else: 2868 carboncopy_name = '%s_MA5_%s_analysis_%s.pdf'%( 2869 self.run_tag,mode,MA5_runtag) 2870 if has_pdf: 2871 shutil.copy(target, pjoin(self.me_dir,'Events',self.run_name,carboncopy_name)) 2872 else: 2873 logger.error('MadAnalysis5 failed to create PDF output') 2874 if MA5_runtag!='default': 2875 logger.info("MadAnalysis5 successfully completed the "+ 2876 "%s. Reported results are placed in:"%("analysis '%s'"%MA5_runtag 2877 if MA5_runtag.upper()!='RECASTING' else "recasting")) 2878 else: 2879 logger.info("MadAnalysis5 successfully completed the analysis."+ 2880 " Reported results are placed in:") 2881 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,carboncopy_name)) 2882 2883 anal_dir = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s' %(mode.upper(),MA5_runtag)) 2884 if not os.path.exists(anal_dir): 2885 logger.error('MadAnalysis5 failed to completed succesfully') 2886 return 2887 # Copy the entire analysis in the HTML directory 2888 shutil.move(anal_dir, pjoin(self.me_dir,'HTML',self.run_name, 2889 '%s_MA5_%s_ANALYSIS_%s'%(self.run_tag,mode.upper(),MA5_runtag))) 2890 2891 # Set the number of events and cross-section to the last one 2892 # (maybe do something smarter later) 2893 new_details={} 2894 for detail in ['nb_event','cross','error']: 2895 new_details[detail] = \ 2896 self.results[self.run_name].get_current_info()[detail] 2897 for detail in new_details: 2898 self.results.add_detail(detail,new_details[detail]) 2899 2900 self.update_status('Finished MA5 analyses.', level='madanalysis5_%s'%mode, 2901 makehtml=False) 2902 2903 #Update the banner 2904 self.banner.add(pjoin(self.me_dir, 'Cards', 2905 'madanalysis5_%s_card.dat'%mode)) 2906 banner_path = pjoin(self.me_dir,'Events', self.run_name, 2907 '%s_%s_banner.txt'%(self.run_name, self.run_tag)) 2908 self.banner.write(banner_path) 2909 2910 if not no_default: 2911 logger.info('Find more information about this run on the HTML local page') 2912 logger.info(' --> %s'%pjoin(self.me_dir,'index.html'))
2913 2914 ############################################################################ 2915 # End of MadAnalysis5 related function 2916 ############################################################################ 2917
2918 - def do_delphes(self, line):
2919 """ run delphes and make associate root file/plot """ 2920 2921 args = self.split_arg(line) 2922 # Check argument's validity 2923 if '--no_default' in args: 2924 no_default = True 2925 args.remove('--no_default') 2926 else: 2927 no_default = False 2928 2929 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')): 2930 logger.info('No delphes_card detected, so not run Delphes') 2931 return 2932 2933 # Check all arguments 2934 filepath = self.check_delphes(args, nodefault=no_default) 2935 if no_default and not filepath: 2936 return # no output file but nothing to do either. 2937 2938 self.update_status('prepare delphes run', level=None) 2939 2940 if os.path.exists(pjoin(self.options['delphes_path'], 'data')): 2941 delphes3 = False 2942 prog = '../bin/internal/run_delphes' 2943 if filepath and '.hepmc' in filepath[:-10]: 2944 raise self.InvalidCmd, 'delphes2 do not support hepmc' 2945 else: 2946 delphes3 = True 2947 prog = '../bin/internal/run_delphes3' 2948 2949 # Check that the delphes_card exists. If not copy the default and 2950 # ask for edition of the card. 2951 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')): 2952 if no_default: 2953 logger.info('No delphes_card detected, so not running Delphes') 2954 return 2955 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_card_default.dat'), 2956 pjoin(self.me_dir, 'Cards', 'delphes_card.dat')) 2957 logger.info('No delphes card found. Take the default one.') 2958 if not delphes3 and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')): 2959 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_trigger_default.dat'), 2960 pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')) 2961 if not (no_default or self.force): 2962 if delphes3: 2963 self.ask_edit_cards(['delphes_card.dat'], args) 2964 else: 2965 self.ask_edit_cards(['delphes_card.dat', 'delphes_trigger.dat'], args) 2966 2967 self.update_status('Running Delphes', level=None) 2968 2969 delphes_dir = self.options['delphes_path'] 2970 tag = self.run_tag 2971 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')): 2972 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_card.dat')) 2973 if not delphes3: 2974 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_trigger.dat')) 2975 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag))) 2976 2977 cross = self.results[self.run_name].get_current_info()['cross'] 2978 2979 delphes_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_delphes.log" % tag) 2980 if not self.cluster: 2981 clus = cluster.onecore 2982 else: 2983 clus = self.cluster 2984 clus.launch_and_wait(prog, 2985 argument= [delphes_dir, self.run_name, tag, str(cross), filepath], 2986 stdout=delphes_log, stderr=subprocess.STDOUT, 2987 cwd=pjoin(self.me_dir,'Events')) 2988 2989 if not os.path.exists(pjoin(self.me_dir, 'Events', 2990 self.run_name, '%s_delphes_events.lhco.gz' % tag))\ 2991 and not os.path.exists(pjoin(self.me_dir, 'Events', 2992 self.run_name, '%s_delphes_events.lhco' % tag)): 2993 logger.info('If you are interested in lhco output. please run root2lhco converter.') 2994 logger.info(' or edit bin/internal/run_delphes3 to run the converter automatically.') 2995 2996 2997 #eradir = self.options['exrootanalysis_path'] 2998 madir = self.options['madanalysis_path'] 2999 td = self.options['td_path'] 3000 3001 if os.path.exists(pjoin(self.me_dir, 'Events', 3002 self.run_name, '%s_delphes_events.lhco' % tag)): 3003 # Creating plots 3004 self.create_plot('Delphes') 3005 3006 if os.path.exists(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)): 3007 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)) 3008 3009 self.update_status('delphes done', level='delphes', makehtml=False)
3010 3011 3012 ############################################################################
3013 - def get_pid_final_initial_states(self):
3014 """Find the pid of all particles in the final and initial states""" 3015 pids = set() 3016 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 3017 'subproc.mg'))] 3018 nb_init = self.ninitial 3019 pat = re.compile(r'''DATA \(IDUP\(I,\d+\),I=1,\d+\)/([\+\-\d,\s]*)/''', re.I) 3020 for Pdir in subproc: 3021 text = open(pjoin(self.me_dir, 'SubProcesses', Pdir, 'born_leshouche.inc')).read() 3022 group = pat.findall(text) 3023 for particles in group: 3024 particles = particles.split(',') 3025 pids.update(set(particles)) 3026 3027 return pids
3028 3029 ############################################################################
3030 - def get_pdf_input_filename(self):
3031 """return the name of the file which is used by the pdfset""" 3032 3033 if self.options["cluster_local_path"] and \ 3034 os.path.exists(self.options["cluster_local_path"]) and \ 3035 self.options['run_mode'] ==1: 3036 # no need to transfer the pdf. 3037 return '' 3038 3039 def check_cluster(path): 3040 if not self.options["cluster_local_path"] or \ 3041 os.path.exists(self.options["cluster_local_path"]) or\ 3042 self.options['run_mode'] !=1: 3043 return path 3044 main = self.options["cluster_local_path"] 3045 if os.path.isfile(path): 3046 filename = os.path.basename(path) 3047 possible_path = [pjoin(main, filename), 3048 pjoin(main, "lhadpf", filename), 3049 pjoin(main, "Pdfdata", filename)] 3050 if any(os.path.exists(p) for p in possible_path): 3051 return " " 3052 else: 3053 return path
3054 3055 3056 if hasattr(self, 'pdffile') and self.pdffile: 3057 return self.pdffile 3058 else: 3059 for line in open(pjoin(self.me_dir,'Source','PDF','pdf_list.txt')): 3060 data = line.split() 3061 if len(data) < 4: 3062 continue 3063 if data[1].lower() == self.run_card['pdlabel'].lower(): 3064 self.pdffile = check_cluster(pjoin(self.me_dir, 'lib', 'Pdfdata', data[2])) 3065 return self.pdffile 3066 else: 3067 # possible when using lhapdf 3068 path = pjoin(self.me_dir, 'lib', 'PDFsets') 3069 if os.path.exists(path): 3070 self.pdffile = path 3071 else: 3072 self.pdffile = " " 3073 return self.pdffile 3074 3075 ############################################################################
3076 - def do_open(self, line):
3077 """Open a text file/ eps file / html file""" 3078 3079 args = self.split_arg(line) 3080 # Check Argument validity and modify argument to be the real path 3081 self.check_open(args) 3082 file_path = args[0] 3083 3084 misc.open_file(file_path)
3085 3086 ############################################################################
3087 - def do_set(self, line, log=True):
3088 """Set an option, which will be default for coming generations/outputs 3089 """ 3090 # cmd calls automaticaly post_set after this command. 3091 3092 3093 args = self.split_arg(line) 3094 # Check the validity of the arguments 3095 self.check_set(args) 3096 # Check if we need to save this in the option file 3097 if args[0] in self.options_configuration and '--no_save' not in args: 3098 self.do_save('options --auto') 3099 3100 if args[0] == "stdout_level": 3101 if args[1].isdigit(): 3102 logging.root.setLevel(int(args[1])) 3103 logging.getLogger('madgraph').setLevel(int(args[1])) 3104 else: 3105 logging.root.setLevel(eval('logging.' + args[1])) 3106 logging.getLogger('madgraph').setLevel(eval('logging.' + args[1])) 3107 if log: logger.info('set output information to level: %s' % args[1]) 3108 elif args[0] == "fortran_compiler": 3109 if args[1] == 'None': 3110 args[1] = None 3111 self.options['fortran_compiler'] = args[1] 3112 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'fortran') 3113 if current != args[1] and args[1] != None: 3114 misc.mod_compilator(self.me_dir, args[1], current, 'gfortran') 3115 elif args[0] == "cpp_compiler": 3116 if args[1] == 'None': 3117 args[1] = None 3118 self.options['cpp_compiler'] = args[1] 3119 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'cpp') 3120 if current != args[1] and args[1] != None: 3121 misc.mod_compilator(self.me_dir, args[1], current, 'cpp') 3122 elif args[0] == "run_mode": 3123 if not args[1] in [0,1,2,'0','1','2']: 3124 raise self.InvalidCmd, 'run_mode should be 0, 1 or 2.' 3125 self.cluster_mode = int(args[1]) 3126 self.options['run_mode'] = self.cluster_mode 3127 elif args[0] in ['cluster_type', 'cluster_queue', 'cluster_temp_path']: 3128 if args[1] == 'None': 3129 args[1] = None 3130 self.options[args[0]] = args[1] 3131 # cluster (re)-initialization done later 3132 # self.cluster update at the end of the routine 3133 elif args[0] in ['cluster_nb_retry', 'cluster_retry_wait', 'cluster_size']: 3134 self.options[args[0]] = int(args[1]) 3135 # self.cluster update at the end of the routine 3136 elif args[0] == 'nb_core': 3137 if args[1] == 'None': 3138 import multiprocessing 3139 self.nb_core = multiprocessing.cpu_count() 3140 self.options['nb_core'] = self.nb_core 3141 return 3142 if not args[1].isdigit(): 3143 raise self.InvalidCmd('nb_core should be a positive number') 3144 self.nb_core = int(args[1]) 3145 self.options['nb_core'] = self.nb_core 3146 elif args[0] == 'timeout': 3147 self.options[args[0]] = int(args[1]) 3148 elif args[0] == 'cluster_status_update': 3149 if '(' in args[1]: 3150 data = ' '.join([a for a in args[1:] if not a.startswith('-')]) 3151 data = data.replace('(','').replace(')','').replace(',',' ').split() 3152 first, second = data[:2] 3153 else: 3154 first, second = args[1:3] 3155 3156 self.options[args[0]] = (int(first), int(second)) 3157 elif args[0] == 'notification_center': 3158 if args[1] in ['None','True','False']: 3159 self.allow_notification_center = eval(args[1]) 3160 self.options[args[0]] = eval(args[1]) 3161 else: 3162 raise self.InvalidCmd('Not a valid value for notification_center') 3163 # True/False formatting 3164 elif args[0] in ['crash_on_error']: 3165 try: 3166 tmp = banner_mod.ConfigFile.format_variable(args[1], bool, 'crash_on_error') 3167 except: 3168 if args[1].lower() in ['never']: 3169 tmp = args[1].lower() 3170 else: 3171 raise 3172 self.options[args[0]] = tmp 3173 elif args[0] in self.options: 3174 if args[1] in ['None','True','False']: 3175 self.options[args[0]] = ast.literal_eval(args[1]) 3176 elif args[0].endswith('path'): 3177 if os.path.exists(args[1]): 3178 self.options[args[0]] = args[1] 3179 elif os.path.exists(pjoin(self.me_dir, args[1])): 3180 self.options[args[0]] = pjoin(self.me_dir, args[1]) 3181 else: 3182 raise self.InvalidCmd('Not a valid path: keep previous value: \'%s\'' % self.options[args[0]]) 3183 else: 3184 self.options[args[0]] = args[1]
3185
3186 - def post_set(self, stop, line):
3187 """Check if we need to save this in the option file""" 3188 try: 3189 args = self.split_arg(line) 3190 if 'cluster' in args[0] or args[0] == 'run_mode': 3191 self.configure_run_mode(self.options['run_mode']) 3192 3193 3194 # Check the validity of the arguments 3195 self.check_set(args) 3196 3197 if args[0] in self.options_configuration and '--no_save' not in args: 3198 self.exec_cmd('save options %s --auto' % args[0]) 3199 elif args[0] in self.options_madevent: 3200 logger.info('This option will be the default in any output that you are going to create in this session.') 3201 logger.info('In order to keep this changes permanent please run \'save options\'') 3202 return stop 3203 except self.InvalidCmd: 3204 return stop
3205
3206 - def configure_run_mode(self, run_mode):
3207 """change the way to submit job 0: single core, 1: cluster, 2: multicore""" 3208 3209 self.cluster_mode = run_mode 3210 self.options['run_mode'] = run_mode 3211 3212 if run_mode == 2: 3213 if not self.options['nb_core']: 3214 import multiprocessing 3215 self.options['nb_core'] = multiprocessing.cpu_count() 3216 nb_core = self.options['nb_core'] 3217 elif run_mode == 0: 3218 nb_core = 1 3219 3220 3221 3222 if run_mode in [0, 2]: 3223 self.cluster = cluster.MultiCore(**self.options) 3224 self.cluster.nb_core = nb_core 3225 #cluster_temp_path=self.options['cluster_temp_path'], 3226 3227 if self.cluster_mode == 1: 3228 opt = self.options 3229 cluster_name = opt['cluster_type'] 3230 if cluster_name in cluster.from_name: 3231 self.cluster = cluster.from_name[cluster_name](**opt) 3232 print "using cluster:", cluster_name 3233 else: 3234 print "cluster_class", cluster_name 3235 print self.plugin_path 3236 # Check if a plugin define this type of cluster 3237 # check for PLUGIN format 3238 cluster_class = misc.from_plugin_import(self.plugin_path, 3239 'new_cluster', cluster_name, 3240 info = 'cluster handling will be done with PLUGIN: %(plug)s' ) 3241 print type(cluster_class) 3242 if cluster_class: 3243 self.cluster = cluster_class(**self.options) 3244 else: 3245 raise self.InvalidCmd, "%s is not recognized as a supported cluster format." % cluster_name
3246 - def check_param_card(self, path, run=True, dependent=False):
3247 """ 3248 1) Check that no scan parameter are present 3249 2) Check that all the width are define in the param_card. 3250 - If a scan parameter is define. create the iterator and recall this fonction 3251 on the first element. 3252 - If some width are set on 'Auto', call the computation tools. 3253 - Check that no width are too small (raise a warning if this is the case) 3254 3) if dependent is on True check for dependent parameter (automatic for scan)""" 3255 3256 self.static_check_param_card(path, self, run=run, dependent=dependent) 3257 3258 card = param_card_mod.ParamCard(path) 3259 for param in card['decay']: 3260 width = param.value 3261 if width == 0: 3262 continue 3263 try: 3264 mass = card['mass'].get(param.lhacode).value 3265 except Exception: 3266 continue
3267 3268 3269 3270 @staticmethod
3271 - def static_check_param_card(path, interface, run=True, dependent=False, 3272 iterator_class=param_card_mod.ParamCardIterator):
3273 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M) 3274 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I) 3275 text = open(path).read() 3276 3277 if pattern_scan.search(text): 3278 if not isinstance(interface, cmd.CmdShell): 3279 # we are in web mode => forbid scan due to security risk 3280 raise Exception, "Scan are not allowed in web mode" 3281 # at least one scan parameter found. create an iterator to go trough the cards 3282 main_card = iterator_class(text) 3283 interface.param_card_iterator = main_card 3284 first_card = main_card.next(autostart=True) 3285 first_card.write(path) 3286 return CommonRunCmd.static_check_param_card(path, interface, run, dependent=True) 3287 3288 pdg_info = pattern_width.findall(text) 3289 if pdg_info: 3290 if run: 3291 logger.info('Computing the width set on auto in the param_card.dat') 3292 has_nlo = any(nlo.lower()=="@nlo" for _,nlo in pdg_info) 3293 pdg = [pdg for pdg,nlo in pdg_info] 3294 if not has_nlo: 3295 line = '%s' % (' '.join(pdg)) 3296 else: 3297 line = '%s --nlo' % (' '.join(pdg)) 3298 CommonRunCmd.static_compute_widths(line, interface, path) 3299 else: 3300 logger.info('''Some width are on Auto in the card. 3301 Those will be computed as soon as you have finish the edition of the cards. 3302 If you want to force the computation right now and being able to re-edit 3303 the cards afterwards, you can type \"compute_wdiths\".''') 3304 3305 card = param_card_mod.ParamCard(path) 3306 if dependent: 3307 AskforEditCard.update_dependent(interface, interface.me_dir, card, path, timer=20) 3308 3309 for param in card['decay']: 3310 width = param.value 3311 if width == 0: 3312 continue 3313 try: 3314 mass = card['mass'].get(param.lhacode).value 3315 except Exception: 3316 logger.warning('Missing mass in the lhef file (%s) . Please fix this (use the "update missing" command if needed)', param.lhacode[0]) 3317 continue 3318 if mass and abs(width/mass) < 1e-12: 3319 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) 3320 if CommonRunCmd.sleep_for_error: 3321 time.sleep(5) 3322 CommonRunCmd.sleep_for_error = False 3323 elif not mass and width: 3324 logger.error('The width of particle %s is different of zero for a massless particle.', param.lhacode[0]) 3325 if CommonRunCmd.sleep_for_error: 3326 time.sleep(5) 3327 CommonRunCmd.sleep_for_error = False 3328 return
3329 3330 @staticmethod
3331 - def static_compute_widths(line, interface, path=None):
3332 """ factory to try to find a way to call the static method""" 3333 3334 handled = True 3335 if isinstance(interface, CommonRunCmd): 3336 if path: 3337 line = '%s %s' % (line, path) 3338 interface.do_compute_widths(line) 3339 else: 3340 handled = False 3341 3342 if handled: 3343 return 3344 3345 if hasattr(interface, 'do_compute_width'): 3346 interface.do_compute_widths('%s --path=%s' % (line, path)) 3347 elif hasattr(interface, 'mother') and interface.mother and isinstance(interface, CommonRunCmd): 3348 return CommonRunCmd.static_compute_width(line, interface.mother, path) 3349 elif not MADEVENT: 3350 from madgraph.interface.master_interface import MasterCmd 3351 cmd = MasterCmd() 3352 interface.define_child_cmd_interface(cmd, interface=False) 3353 if hasattr(interface, 'options'): 3354 cmd.options.update(interface.options) 3355 try: 3356 cmd.exec_cmd('set automatic_html_opening False --no_save') 3357 except Exception: 3358 pass 3359 3360 model = interface.get_model() 3361 3362 3363 line = 'compute_widths %s --path=%s' % (line, path) 3364 cmd.exec_cmd(line, model=model) 3365 interface.child = None 3366 del cmd 3367 return 3368 3369 3370 3371 raise Exception, 'fail to find a way to handle Auto width'
3372 3373
3374 - def store_scan_result(self):
3375 """return the information that need to be kept for the scan summary. 3376 Auto-width are automatically added.""" 3377 3378 return {'cross': self.results.current['cross']}
3379 3380
3381 - def add_error_log_in_html(self, errortype=None):
3382 """If a ME run is currently running add a link in the html output""" 3383 3384 # Be very carefull to not raise any error here (the traceback 3385 #will be modify in that case.) 3386 if hasattr(self, 'results') and hasattr(self.results, 'current') and\ 3387 self.results.current and 'run_name' in self.results.current and \ 3388 hasattr(self, 'me_dir'): 3389 name = self.results.current['run_name'] 3390 tag = self.results.current['tag'] 3391 self.debug_output = pjoin(self.me_dir, '%s_%s_debug.log' % (name,tag)) 3392 if errortype: 3393 self.results.current.debug = errortype 3394 else: 3395 self.results.current.debug = self.debug_output 3396 3397 else: 3398 #Force class default 3399 self.debug_output = CommonRunCmd.debug_output 3400 if os.path.exists('ME5_debug') and not 'ME5_debug' in self.debug_output: 3401 try: 3402 os.remove('ME5_debug') 3403 except Exception: 3404 pass 3405 if not 'ME5_debug' in self.debug_output: 3406 os.system('ln -s %s ME5_debug &> /dev/null' % self.debug_output)
3407 3408
3409 - def do_quit(self, line):
3410 """Not in help: exit """ 3411 3412 if not self.force_run: 3413 try: 3414 os.remove(pjoin(self.me_dir,'RunWeb')) 3415 except Exception: 3416 pass 3417 3418 try: 3419 self.store_result() 3420 except Exception: 3421 # If nothing runs they they are no result to update 3422 pass 3423 3424 try: 3425 self.update_status('', level=None) 3426 except Exception, error: 3427 pass 3428 3429 self.gen_card_html() 3430 return super(CommonRunCmd, self).do_quit(line)
3431 3432 # Aliases 3433 do_EOF = do_quit 3434 do_exit = do_quit 3435
3436 - def __del__(self):
3437 """try to remove RunWeb?""" 3438 3439 if not self.stop_for_runweb and not self.force_run: 3440 try: 3441 os.remove(pjoin(self.me_dir,'RunWeb')) 3442 except Exception: 3443 pass
3444 3445
3446 - def update_status(self, status, level, makehtml=True, force=True, 3447 error=False, starttime = None, update_results=True, 3448 print_log=True):
3449 """ update the index status """ 3450 3451 if makehtml and not force: 3452 if hasattr(self, 'next_update') and time.time() < self.next_update: 3453 return 3454 else: 3455 self.next_update = time.time() + 3 3456 3457 if print_log: 3458 if isinstance(status, str): 3459 if '<br>' not in status: 3460 logger.info(status) 3461 elif starttime: 3462 running_time = misc.format_timer(time.time()-starttime) 3463 logger.info(' Idle: %s, Running: %s, Completed: %s [ %s ]' % \ 3464 (status[0], status[1], status[2], running_time)) 3465 else: 3466 logger.info(' Idle: %s, Running: %s, Completed: %s' % status[:3]) 3467 3468 if isinstance(status, str) and status.startswith('\x1b['): 3469 status = status[status.index('m')+1:-7] 3470 if 'arXiv' in status: 3471 if '[' in status: 3472 status = status.split('[',1)[0] 3473 else: 3474 status = status.split('arXiv',1)[0] 3475 3476 if update_results: 3477 self.results.update(status, level, makehtml=makehtml, error=error)
3478 3479 ############################################################################
3480 - def keep_cards(self, need_card=[], ignore=[]):
3481 """Ask the question when launching generate_events/multi_run""" 3482 3483 check_card = ['pythia_card.dat', 'pgs_card.dat','delphes_card.dat', 3484 'delphes_trigger.dat', 'madspin_card.dat', 'shower_card.dat', 3485 'reweight_card.dat','pythia8_card.dat', 3486 'madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat', 3487 'plot_card.dat'] 3488 3489 cards_path = pjoin(self.me_dir,'Cards') 3490 for card in check_card: 3491 if card in ignore or (ignore == ['*'] and card not in need_card): 3492 continue 3493 if card not in need_card: 3494 if os.path.exists(pjoin(cards_path, card)): 3495 files.mv(pjoin(cards_path, card), pjoin(cards_path, '.%s' % card)) 3496 else: 3497 if not os.path.exists(pjoin(cards_path, card)): 3498 if os.path.exists(pjoin(cards_path, '.%s' % card)): 3499 files.mv(pjoin(cards_path, '.%s' % card), pjoin(cards_path, card)) 3500 else: 3501 default = card.replace('.dat', '_default.dat') 3502 files.cp(pjoin(cards_path, default),pjoin(cards_path, card))
3503 3504 ############################################################################
3505 - def set_configuration(self, config_path=None, final=True, initdir=None, amcatnlo=False):
3506 """ assign all configuration variable from file 3507 ./Cards/mg5_configuration.txt. assign to default if not define """ 3508 3509 if not hasattr(self, 'options') or not self.options: 3510 self.options = dict(self.options_configuration) 3511 self.options.update(self.options_madgraph) 3512 self.options.update(self.options_madevent) 3513 3514 if not config_path: 3515 if os.environ.has_key('MADGRAPH_BASE'): 3516 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt') 3517 self.set_configuration(config_path=config_path, final=False) 3518 if 'HOME' in os.environ: 3519 config_path = pjoin(os.environ['HOME'],'.mg5', 3520 'mg5_configuration.txt') 3521 if os.path.exists(config_path): 3522 self.set_configuration(config_path=config_path, final=False) 3523 if amcatnlo: 3524 me5_config = pjoin(self.me_dir, 'Cards', 'amcatnlo_configuration.txt') 3525 else: 3526 me5_config = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 3527 self.set_configuration(config_path=me5_config, final=False, initdir=self.me_dir) 3528 3529 if self.options.has_key('mg5_path') and self.options['mg5_path']: 3530 MG5DIR = self.options['mg5_path'] 3531 config_file = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 3532 self.set_configuration(config_path=config_file, final=False,initdir=MG5DIR) 3533 else: 3534 self.options['mg5_path'] = None 3535 return self.set_configuration(config_path=me5_config, final=final,initdir=self.me_dir) 3536 3537 config_file = open(config_path) 3538 3539 # read the file and extract information 3540 logger.info('load configuration from %s ' % config_file.name) 3541 for line in config_file: 3542 3543 if '#' in line: 3544 line = line.split('#',1)[0] 3545 line = line.replace('\n','').replace('\r\n','') 3546 try: 3547 name, value = line.split('=') 3548 except ValueError: 3549 pass 3550 else: 3551 name = name.strip() 3552 value = value.strip() 3553 if name.endswith('_path') and not name.startswith('cluster'): 3554 path = value 3555 if os.path.isdir(path): 3556 self.options[name] = os.path.realpath(path) 3557 continue 3558 if not initdir: 3559 continue 3560 path = pjoin(initdir, value) 3561 if os.path.isdir(path): 3562 self.options[name] = os.path.realpath(path) 3563 continue 3564 else: 3565 self.options[name] = value 3566 if value.lower() == "none": 3567 self.options[name] = None 3568 3569 if not final: 3570 return self.options # the return is usefull for unittest 3571 3572 # Treat each expected input 3573 # delphes/pythia/... path 3574 for key in self.options: 3575 # Final cross check for the path 3576 if key.endswith('path') and not key.startswith("cluster"): 3577 path = self.options[key] 3578 if path is None: 3579 continue 3580 if os.path.isdir(path): 3581 self.options[key] = os.path.realpath(path) 3582 continue 3583 path = pjoin(self.me_dir, self.options[key]) 3584 if os.path.isdir(path): 3585 self.options[key] = os.path.realpath(path) 3586 continue 3587 elif self.options.has_key('mg5_path') and self.options['mg5_path']: 3588 path = pjoin(self.options['mg5_path'], self.options[key]) 3589 if os.path.isdir(path): 3590 self.options[key] = os.path.realpath(path) 3591 continue 3592 self.options[key] = None 3593 elif key.startswith('cluster') and key != 'cluster_status_update': 3594 if key in ('cluster_nb_retry','cluster_wait_retry'): 3595 self.options[key] = int(self.options[key]) 3596 if hasattr(self,'cluster'): 3597 del self.cluster 3598 pass 3599 elif key == 'automatic_html_opening': 3600 if self.options[key] in ['False', 'True']: 3601 self.options[key] =ast.literal_eval(self.options[key]) 3602 elif key == "notification_center": 3603 if self.options[key] in ['False', 'True']: 3604 self.allow_notification_center =ast.literal_eval(self.options[key]) 3605 self.options[key] =ast.literal_eval(self.options[key]) 3606 elif key not in ['text_editor','eps_viewer','web_browser','stdout_level', 3607 'complex_mass_scheme', 'gauge', 'group_subprocesses']: 3608 # Default: try to set parameter 3609 try: 3610 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False) 3611 except self.InvalidCmd: 3612 logger.warning("Option %s from config file not understood" \ 3613 % key) 3614 3615 # Configure the way to open a file: 3616 misc.open_file.configure(self.options) 3617 3618 # update the path to the PLUGIN directory of MG% 3619 if MADEVENT and 'mg5_path' in self.options and self.options['mg5_path']: 3620 mg5dir = self.options['mg5_path'] 3621 if mg5dir not in sys.path: 3622 sys.path.append(mg5dir) 3623 if pjoin(mg5dir, 'PLUGIN') not in self.plugin_path: 3624 self.plugin_path.append(pjoin(mg5dir,'PLUGIN')) 3625 3626 self.configure_run_mode(self.options['run_mode']) 3627 return self.options
3628 3629 @staticmethod
3630 - def find_available_run_name(me_dir):
3631 """ find a valid run_name for the current job """ 3632 3633 name = 'run_%02d' 3634 data = [int(s[4:j]) for s in os.listdir(pjoin(me_dir,'Events')) for 3635 j in range(4,len(s)+1) if \ 3636 s.startswith('run_') and s[4:j].isdigit()] 3637 return name % (max(data+[0])+1)
3638 3639 3640 ############################################################################
3641 - def do_decay_events(self,line):
3642 """Require MG5 directory: decay events with spin correlations 3643 """ 3644 3645 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')): 3646 return 3647 3648 # First need to load MadSpin 3649 # Check that MG5 directory is present . 3650 if MADEVENT and not self.options['mg5_path']: 3651 raise self.InvalidCmd, '''The module decay_events requires that MG5 is installed on the system. 3652 You can install it and set its path in ./Cards/me5_configuration.txt''' 3653 elif MADEVENT: 3654 sys.path.append(self.options['mg5_path']) 3655 try: 3656 import MadSpin.decay as decay 3657 import MadSpin.interface_madspin as interface_madspin 3658 except ImportError: 3659 if __debug__: 3660 raise 3661 else: 3662 raise self.ConfigurationError, '''Can\'t load MadSpin 3663 The variable mg5_path might not be correctly configured.''' 3664 3665 self.update_status('Running MadSpin', level='madspin') 3666 if not '-from_cards' in line and '-f' not in line: 3667 self.keep_cards(['madspin_card.dat'], ignore=['*']) 3668 self.ask_edit_cards(['madspin_card.dat'], 'fixed', plot=False) 3669 self.help_decay_events(skip_syntax=True) 3670 3671 # load the name of the event file 3672 args = self.split_arg(line) 3673 self.check_decay_events(args) 3674 # args now alway content the path to the valid files 3675 madspin_cmd = interface_madspin.MadSpinInterface(args[0]) 3676 # pass current options to the interface 3677 madspin_cmd.mg5cmd.options.update(self.options) 3678 for key, value in self.options.items(): 3679 if isinstance(value, str): 3680 madspin_cmd.mg5cmd.exec_cmd( 'set %s %s' %(key,value), errorhandling=False, printcmd=False, precmd=False, postcmd=True) 3681 madspin_cmd.cluster = self.cluster 3682 3683 madspin_cmd.update_status = lambda *x,**opt: self.update_status(*x, level='madspin',**opt) 3684 3685 path = pjoin(self.me_dir, 'Cards', 'madspin_card.dat') 3686 3687 madspin_cmd.import_command_file(path) 3688 3689 # create a new run_name directory for this output 3690 i = 1 3691 while os.path.exists(pjoin(self.me_dir,'Events', '%s_decayed_%i' % (self.run_name,i))): 3692 i+=1 3693 new_run = '%s_decayed_%i' % (self.run_name,i) 3694 evt_dir = pjoin(self.me_dir, 'Events') 3695 3696 os.mkdir(pjoin(evt_dir, new_run)) 3697 current_file = args[0].replace('.lhe', '_decayed.lhe') 3698 new_file = pjoin(evt_dir, new_run, os.path.basename(args[0])) 3699 if not os.path.exists(current_file): 3700 if os.path.exists(current_file+'.gz'): 3701 current_file += '.gz' 3702 new_file += '.gz' 3703 elif current_file.endswith('.gz') and os.path.exists(current_file[:-3]): 3704 current_file = current_file[:-3] 3705 new_file = new_file[:-3] 3706 else: 3707 logger.error('MadSpin fails to create any decayed file.') 3708 return 3709 3710 files.mv(current_file, new_file) 3711 logger.info("The decayed event file has been moved to the following location: ") 3712 logger.info(new_file) 3713 3714 if hasattr(self, 'results'): 3715 current = self.results.current 3716 nb_event = self.results.current['nb_event'] 3717 if not nb_event: 3718 current = self.results[self.run_name][0] 3719 nb_event = current['nb_event'] 3720 3721 cross = current['cross'] 3722 error = current['error'] 3723 self.results.add_run( new_run, self.run_card) 3724 self.results.add_detail('nb_event', int(nb_event*madspin_cmd.efficiency)) 3725 self.results.add_detail('cross', madspin_cmd.cross)#cross * madspin_cmd.branching_ratio) 3726 self.results.add_detail('error', madspin_cmd.error+ cross * madspin_cmd.err_branching_ratio) 3727 self.results.add_detail('run_mode', current['run_mode']) 3728 self.to_store.append("event") 3729 3730 self.run_name = new_run 3731 self.banner = madspin_cmd.banner 3732 self.banner.add(path) 3733 self.banner.write(pjoin(self.me_dir,'Events',self.run_name, '%s_%s_banner.txt' % 3734 (self.run_name, self.run_tag))) 3735 self.update_status('MadSpin Done', level='parton', makehtml=False) 3736 if 'unweighted' in os.path.basename(args[0]): 3737 self.create_plot('parton')
3738
3739 - def complete_decay_events(self, text, line, begidx, endidx):
3740 args = self.split_arg(line[0:begidx], error=False) 3741 if len(args) == 1: 3742 return self.complete_plot(text, line, begidx, endidx) 3743 else: 3744 return
3745
3746 - def complete_print_results(self,text, line, begidx, endidx):
3747 "Complete the print results command" 3748 args = self.split_arg(line[0:begidx], error=False) 3749 if len(args) == 1: 3750 #return valid run_name 3751 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'), 3752 pjoin(self.me_dir, 'Events')) 3753 3754 data = [n.rsplit('/',2)[1] for n in data] 3755 tmp1 = self.list_completion(text, data) 3756 return tmp1 3757 else: 3758 data = misc.glob('*_pythia_events.hep.gz', pjoin(self.me_dir, 'Events', args[0])) 3759 data = [os.path.basename(p).rsplit('_',1)[0] for p in data] 3760 data += ["--mode=a", "--mode=w", "--path=", "--format=short"] 3761 tmp1 = self.list_completion(text, data) 3762 return tmp1
3763
3764 - def help_print_result(self):
3765 logger.info("syntax: print_result [RUN] [TAG] [options]") 3766 logger.info("-- show in text format the status of the run (cross-section/nb-event/...)") 3767 logger.info("--path= defines the path of the output file.") 3768 logger.info("--mode=a allow to add the information at the end of the file.") 3769 logger.info("--format=short (only if --path is define)") 3770 logger.info(" allows to have a multi-column output easy to parse")
3771 3772 3773 ############################################################################
3774 - def find_model_name(self):
3775 """ return the model name """ 3776 if hasattr(self, 'model_name'): 3777 return self.model_name 3778 3779 def join_line(old, to_add): 3780 if old.endswith('\\'): 3781 newline = old[:-1] + to_add 3782 else: 3783 newline = old + line 3784 return newline
3785 3786 3787 3788 model = 'sm' 3789 proc = [] 3790 continuation_line = None 3791 for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')): 3792 line = line.split('#')[0] 3793 if continuation_line: 3794 line = line.strip() 3795 if continuation_line == 'model': 3796 model = join_line(model, line) 3797 elif continuation_line == 'proc': 3798 proc = join_line(proc, line) 3799 if not line.endswith('\\'): 3800 continuation_line = None 3801 continue 3802 #line = line.split('=')[0] 3803 if line.startswith('import') and 'model' in line: 3804 model = line.split()[2] 3805 proc = [] 3806 if model.endswith('\\'): 3807 continuation_line = 'model' 3808 elif line.startswith('generate'): 3809 proc.append(line.split(None,1)[1]) 3810 if proc[-1].endswith('\\'): 3811 continuation_line = 'proc' 3812 elif line.startswith('add process'): 3813 proc.append(line.split(None,2)[2]) 3814 if proc[-1].endswith('\\'): 3815 continuation_line = 'proc' 3816 self.model = model 3817 self.process = proc 3818 return model 3819 3820 3821 ############################################################################
3822 - def do_check_events(self, line):
3823 """ Run some sanity check on the generated events.""" 3824 3825 # Check that MG5 directory is present . 3826 if MADEVENT and not self.options['mg5_path']: 3827 raise self.InvalidCmd, '''The module reweight requires that MG5 is installed on the system. 3828 You can install it and set its path in ./Cards/me5_configuration.txt''' 3829 elif MADEVENT: 3830 sys.path.append(self.options['mg5_path']) 3831 try: 3832 import madgraph.interface.reweight_interface as reweight_interface 3833 except ImportError: 3834 raise self.ConfigurationError, '''Can\'t load Reweight module. 3835 The variable mg5_path might not be correctly configured.''' 3836 3837 3838 # load the name of the event file 3839 args = self.split_arg(line) 3840 self.check_check_events(args) 3841 # args now alway content the path to the valid files 3842 reweight_cmd = reweight_interface.ReweightInterface(args[0], allow_madspin=True) 3843 reweight_cmd.mother = self 3844 self.update_status('Running check on events', level='check') 3845 3846 reweight_cmd.check_events()
3847 3848 ############################################################################
3849 - def complete_check_events(self, text, line, begidx, endidx):
3850 args = self.split_arg(line[0:begidx], error=False) 3851 3852 if len(args) == 1 and os.path.sep not in text: 3853 #return valid run_name 3854 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events')) 3855 data = [n.rsplit('/',2)[1] for n in data] 3856 return self.list_completion(text, data, line) 3857 else: 3858 return self.path_completion(text, 3859 os.path.join('.',*[a for a in args \ 3860 if a.endswith(os.path.sep)]))
3861
3862 - def complete_reweight(self,text, line, begidx, endidx):
3863 "Complete the pythia command" 3864 args = self.split_arg(line[0:begidx], error=False) 3865 3866 #return valid run_name 3867 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events')) 3868 data = list(set([n.rsplit('/',2)[1] for n in data])) 3869 if not '-f' in args: 3870 data.append('-f') 3871 tmp1 = self.list_completion(text, data) 3872 return tmp1
3873 3874 3875
3876 - def complete_compute_widths(self, text, line, begidx, endidx, formatting=True):
3877 "Complete the compute_widths command" 3878 3879 args = self.split_arg(line[0:begidx]) 3880 3881 if args[-1] in ['--path=', '--output=']: 3882 completion = {'path': self.path_completion(text)} 3883 elif line[begidx-1] == os.path.sep: 3884 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)]) 3885 if current_dir.startswith('--path='): 3886 current_dir = current_dir[7:] 3887 if current_dir.startswith('--output='): 3888 current_dir = current_dir[9:] 3889 completion = {'path': self.path_completion(text, current_dir)} 3890 else: 3891 completion = {} 3892 completion['options'] = self.list_completion(text, 3893 ['--path=', '--output=', '--min_br=0.\$', '--nlo', 3894 '--precision_channel=0.\$', '--body_decay=']) 3895 3896 return self.deal_multiple_categories(completion, formatting)
3897 3898
3899 - def update_make_opts(self):
3900 """update the make_opts file writing the environmental variables 3901 stored in make_opts_var""" 3902 make_opts = os.path.join(self.me_dir, 'Source', 'make_opts') 3903 3904 # Set some environment variables common to all interfaces 3905 if not hasattr(self,'options') or not 'pythia8_path' in self.options or \ 3906 not self.options['pythia8_path'] or \ 3907 not os.path.isfile(pjoin(self.options['pythia8_path'],'bin','pythia8-config')): 3908 self.make_opts_var['PYTHIA8_PATH']='NotInstalled' 3909 else: 3910 self.make_opts_var['PYTHIA8_PATH']=self.options['pythia8_path'] 3911 3912 self.make_opts_var['MG5AMC_VERSION'] = misc.get_pkg_info()['version'] 3913 3914 return self.update_make_opts_full(make_opts, self.make_opts_var)
3915 3916 @staticmethod
3917 - def update_make_opts_full(path, def_variables, keep_old=True):
3918 """update the make_opts file writing the environmental variables 3919 of def_variables. 3920 if a value of the dictionary is None then it is not written. 3921 """ 3922 make_opts = path 3923 pattern = re.compile(r'^(\w+)\s*=\s*(.*)$',re.DOTALL) 3924 diff = False # set to True if one varible need to be updated 3925 #if on False the file is not modify 3926 3927 tag = '#end_of_make_opts_variables\n' 3928 make_opts_variable = True # flag to say if we are in edition area or not 3929 content = [] 3930 variables = dict(def_variables) 3931 need_keys = variables.keys() 3932 for line in open(make_opts): 3933 line = line.strip() 3934 if make_opts_variable: 3935 if line.startswith('#') or not line: 3936 if line.startswith('#end_of_make_opts_variables'): 3937 make_opts_variable = False 3938 continue 3939 elif pattern.search(line): 3940 key, value = pattern.search(line).groups() 3941 if key not in variables: 3942 variables[key] = value 3943 elif value != variables[key]: 3944 diff=True 3945 else: 3946 need_keys.remove(key) 3947 else: 3948 make_opts_variable = False 3949 content.append(line) 3950 else: 3951 content.append(line) 3952 3953 if need_keys: 3954 diff=True #This means that new definition are added to the file. 3955 3956 content_variables = '\n'.join('%s=%s' % (k,v) for k, v in variables.items() if v is not None) 3957 content_variables += '\n%s' % tag 3958 3959 if diff: 3960 with open(make_opts, 'w') as fsock: 3961 fsock.write(content_variables + '\n'.join(content)) 3962 return
3963 3964 3965 # lhapdf-related functions 3995 3996
3997 - def get_characteristics(self, path=None):
3998 """reads the proc_characteristics file and initialises the correspondant 3999 dictionary""" 4000 4001 if not path: 4002 path = os.path.join(self.me_dir, 'SubProcesses', 'proc_characteristics') 4003 4004 self.proc_characteristics = banner_mod.ProcCharacteristic(path) 4005 return self.proc_characteristics
4006 4007
4008 - def copy_lhapdf_set(self, lhaid_list, pdfsets_dir, require_local=True):
4009 """copy (if needed) the lhapdf set corresponding to the lhaid in lhaid_list 4010 into lib/PDFsets. 4011 if require_local is False, just ensure that the pdf is in pdfsets_dir 4012 """ 4013 4014 if not hasattr(self, 'lhapdf_pdfsets'): 4015 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsets_dir) 4016 4017 pdfsetname=set() 4018 for lhaid in lhaid_list: 4019 if isinstance(lhaid, str) and lhaid.isdigit(): 4020 lhaid = int(lhaid) 4021 if isinstance(lhaid, (int,float)): 4022 try: 4023 if lhaid in self.lhapdf_pdfsets: 4024 pdfsetname.add(self.lhapdf_pdfsets[lhaid]['filename']) 4025 else: 4026 raise MadGraph5Error('lhaid %s not valid input number for the current lhapdf' % lhaid ) 4027 except KeyError: 4028 if self.lhapdf_version.startswith('5'): 4029 raise MadGraph5Error(\ 4030 ('invalid lhaid set in th run_card: %d .\nPlease note that some sets' % lhaid) + \ 4031 '(eg MSTW 90%CL error sets) \nare not available in aMC@NLO + LHAPDF 5.x.x') 4032 else: 4033 logger.debug('%d not found in pdfsets.index' % lhaid) 4034 else: 4035 pdfsetname.add(lhaid) 4036 4037 # check if the file exists, otherwise install it: 4038 # also check that the PDFsets dir exists, otherwise create it. 4039 # if fails, install the lhapdfset into lib/PDFsets 4040 if not os.path.isdir(pdfsets_dir): 4041 try: 4042 os.mkdir(pdfsets_dir) 4043 except OSError: 4044 pdfsets_dir = pjoin(self.me_dir, 'lib', 'PDFsets') 4045 elif os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets')): 4046 #clean previous set of pdf used 4047 for name in os.listdir(pjoin(self.me_dir, 'lib', 'PDFsets')): 4048 if name not in pdfsetname: 4049 try: 4050 if os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', name)): 4051 shutil.rmtree(pjoin(self.me_dir, 'lib', 'PDFsets', name)) 4052 else: 4053 os.remove(pjoin(self.me_dir, 'lib', 'PDFsets', name)) 4054 except Exception, error: 4055 logger.debug('%s', error) 4056 4057 if self.options["cluster_local_path"]: 4058 lhapdf_cluster_possibilities = [self.options["cluster_local_path"], 4059 pjoin(self.options["cluster_local_path"], "lhapdf"), 4060 pjoin(self.options["cluster_local_path"], "lhapdf", "pdfsets"), 4061 pjoin(self.options["cluster_local_path"], "..", "lhapdf"), 4062 pjoin(self.options["cluster_local_path"], "..", "lhapdf", "pdfsets"), 4063 pjoin(self.options["cluster_local_path"], "..", "lhapdf","pdfsets", "6.1") 4064 ] 4065 else: 4066 lhapdf_cluster_possibilities = [] 4067 4068 for pdfset in pdfsetname: 4069 # Check if we need to copy the pdf 4070 if self.options["cluster_local_path"] and self.options["run_mode"] == 1 and \ 4071 any((os.path.exists(pjoin(d, pdfset)) for d in lhapdf_cluster_possibilities)): 4072 4073 os.environ["LHAPATH"] = [d for d in lhapdf_cluster_possibilities if os.path.exists(pjoin(d, pdfset))][0] 4074 os.environ["CLUSTER_LHAPATH"] = os.environ["LHAPATH"] 4075 # no need to copy it 4076 if os.path.exists(pjoin(pdfsets_dir, pdfset)): 4077 try: 4078 if os.path.isdir(pjoin(pdfsets_dir, name)): 4079 shutil.rmtree(pjoin(pdfsets_dir, name)) 4080 else: 4081 os.remove(pjoin(pdfsets_dir, name)) 4082 except Exception, error: 4083 logger.debug('%s', error) 4084 if not require_local and (os.path.exists(pjoin(pdfsets_dir, pdfset)) or \ 4085 os.path.isdir(pjoin(pdfsets_dir, pdfset))): 4086 continue 4087 #check that the pdfset is not already there 4088 elif not os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)) and \ 4089 not os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)): 4090 4091 if pdfset and not os.path.exists(pjoin(pdfsets_dir, pdfset)): 4092 self.install_lhapdf_pdfset(pdfsets_dir, pdfset) 4093 4094 if os.path.exists(pjoin(pdfsets_dir, pdfset)): 4095 files.cp(pjoin(pdfsets_dir, pdfset), pjoin(self.me_dir, 'lib', 'PDFsets')) 4096 elif os.path.exists(pjoin(os.path.dirname(pdfsets_dir), pdfset)): 4097 files.cp(pjoin(os.path.dirname(pdfsets_dir), pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4098
4099 - def install_lhapdf_pdfset(self, pdfsets_dir, filename):
4100 """idownloads and install the pdfset filename in the pdfsets_dir""" 4101 lhapdf_version = self.get_lhapdf_version() 4102 local_path = pjoin(self.me_dir, 'lib', 'PDFsets') 4103 return self.install_lhapdf_pdfset_static(self.options['lhapdf'], 4104 pdfsets_dir, filename, 4105 lhapdf_version=lhapdf_version, 4106 alternate_path=local_path)
4107 4108 4109 @staticmethod
4110 - def install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir, filename, 4111 lhapdf_version=None, alternate_path=None):
4112 """idownloads and install the pdfset filename in the pdfsets_dir. 4113 Version which can be used independently of the class. 4114 local path is used if the global installation fails. 4115 """ 4116 4117 if not lhapdf_version: 4118 lhapdf_version = subprocess.Popen([lhapdf_config, '--version'], 4119 stdout = subprocess.PIPE).stdout.read().strip() 4120 4121 4122 if not pdfsets_dir: 4123 if 'LHAPATH' in os.environ: 4124 for p in os.environ['LHAPATH'].split(':'): 4125 if os.path.exists(p): 4126 pdfsets_dir = p 4127 break 4128 else: 4129 del os.environ['LHAPATH'] 4130 pdfsets_dir = subprocess.Popen([lhapdf_config, '--datadir'], 4131 stdout = subprocess.PIPE).stdout.read().strip() 4132 else: 4133 pdfsets_dir = subprocess.Popen([lhapdf_config, '--datadir'], 4134 stdout = subprocess.PIPE).stdout.read().strip() 4135 4136 if isinstance(filename, int): 4137 pdf_info = CommonRunCmd.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version) 4138 filename = pdf_info[filename]['filename'] 4139 4140 if os.path.exists(pjoin(pdfsets_dir, filename)): 4141 logger.debug('%s is already present in %s', filename, pdfsets_dir) 4142 return 4143 4144 logger.info('Trying to download %s' % filename) 4145 4146 4147 if lhapdf_version.startswith('5.'): 4148 4149 # use the lhapdf-getdata command, which is in the same path as 4150 # lhapdf-config 4151 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf-getdata')) 4152 misc.call([getdata, filename], cwd = pdfsets_dir) 4153 4154 elif lhapdf_version.startswith('6.'): 4155 # use the "lhapdf install xxx" command, which is in the same path as 4156 # lhapdf-config 4157 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf')) 4158 4159 if lhapdf_version.startswith('6.1'): 4160 misc.call([getdata, 'install', filename], cwd = pdfsets_dir) 4161 else: 4162 #for python 6.2.1, import lhapdf should be working to download pdf 4163 lhapdf = misc.import_python_lhapdf(lhapdf_config) 4164 if lhapdf: 4165 if 'PYTHONPATH' in os.environ: 4166 os.environ['PYTHONPATH']+= ':' + os.path.dirname(lhapdf.__file__) 4167 else: 4168 os.environ['PYTHONPATH'] = ':'.join(sys.path) + ':' + os.path.dirname(lhapdf.__file__) 4169 else: 4170 logger.warning('lhapdf 6.2.1 requires python integration in order to download pdf set. Trying anyway') 4171 misc.call([getdata, 'install', filename], cwd = pdfsets_dir) 4172 4173 else: 4174 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version) 4175 4176 # check taht the file has been installed in the global dir 4177 if os.path.exists(pjoin(pdfsets_dir, filename)) or \ 4178 os.path.isdir(pjoin(pdfsets_dir, filename)): 4179 logger.info('%s successfully downloaded and stored in %s' \ 4180 % (filename, pdfsets_dir)) 4181 #otherwise (if v5) save it locally 4182 elif lhapdf_version.startswith('5.'): 4183 logger.warning('Could not download %s into %s. Trying to save it locally' \ 4184 % (filename, pdfsets_dir)) 4185 CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, alternate_path, filename, 4186 lhapdf_version=lhapdf_version) 4187 elif lhapdf_version.startswith('6.') and '.LHgrid' in filename: 4188 logger.info('Could not download %s: Try %s', filename, filename.replace('.LHgrid','')) 4189 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir, 4190 filename.replace('.LHgrid',''), 4191 lhapdf_version, alternate_path) 4192 elif lhapdf_version.startswith('6.'): 4193 # try to do a simple wget 4194 wwwpath = "http://www.hepforge.org/archive/lhapdf/pdfsets/%s/%s.tar.gz" 4195 wwwpath %= ('.'.join(lhapdf_version.split('.')[:2]), filename) 4196 misc.wget(wwwpath, pjoin(pdfsets_dir, '%s.tar.gz' %filename)) 4197 misc.call(['tar', '-xzpvf', '%s.tar.gz' %filename], 4198 cwd=pdfsets_dir) 4199 if os.path.exists(pjoin(pdfsets_dir, filename)) or \ 4200 os.path.isdir(pjoin(pdfsets_dir, filename)): 4201 logger.info('%s successfully downloaded and stored in %s' \ 4202 % (filename, pdfsets_dir)) 4203 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']: 4204 misc.sprint(os.environ['LHAPATH'], '-> retry') 4205 if pdfsets_dir in os.environ['LHAPATH'].split(':'): 4206 lhapath = os.environ['LHAPATH'].split(':') 4207 lhapath = [p for p in lhapath if os.path.exists(p)] 4208 lhapath.remove(pdfsets_dir) 4209 os.environ['LHAPATH'] = ':'.join(lhapath) 4210 if lhapath: 4211 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4212 filename, 4213 lhapdf_version, alternate_path) 4214 else: 4215 raise MadGraph5Error, \ 4216 'Could not download %s into %s. Please try to install it manually.' \ 4217 % (filename, pdfsets_dir) 4218 else: 4219 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None, 4220 filename, 4221 lhapdf_version, alternate_path) 4222 else: 4223 raise MadGraph5Error, \ 4224 'Could not download %s into %s. Please try to install it manually.' \ 4225 % (filename, pdfsets_dir) 4226 4227 else: 4228 raise MadGraph5Error, \ 4229 'Could not download %s into %s. Please try to install it manually.' \ 4230 % (filename, pdfsets_dir)
4231 4232 4233
4234 - def get_lhapdf_pdfsets_list(self, pdfsets_dir):
4235 """read the PDFsets.index file, which should be located in the same 4236 place as pdfsets_dir, and return a list of dictionaries with the information 4237 about each pdf set""" 4238 lhapdf_version = self.get_lhapdf_version() 4239 return self.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4240 4241 @staticmethod
4242 - def get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version):
4243 4244 if lhapdf_version.startswith('5.'): 4245 if os.path.exists('%s.index' % pdfsets_dir): 4246 indexfile = '%s.index' % pdfsets_dir 4247 else: 4248 raise MadGraph5Error, 'index of lhapdf file not found' 4249 pdfsets_lines = \ 4250 [l for l in open(indexfile).read().split('\n') if l.strip() and \ 4251 not '90cl' in l] 4252 lhapdf_pdfsets = dict( (int(l.split()[0]), {'lhaid': int(l.split()[0]), 4253 'pdflib_ntype': int(l.split()[1]), 4254 'pdflib_ngroup': int(l.split()[2]), 4255 'pdflib_nset': int(l.split()[3]), 4256 'filename': l.split()[4], 4257 'lhapdf_nmem': int(l.split()[5]), 4258 'q2min': float(l.split()[6]), 4259 'q2max': float(l.split()[7]), 4260 'xmin': float(l.split()[8]), 4261 'xmax': float(l.split()[9]), 4262 'description': l.split()[10]}) \ 4263 for l in pdfsets_lines) 4264 4265 elif lhapdf_version.startswith('6.'): 4266 pdfsets_lines = \ 4267 [l for l in open(pjoin(pdfsets_dir, 'pdfsets.index')).read().split('\n') if l.strip()] 4268 lhapdf_pdfsets = dict( (int(l.split()[0]), 4269 {'lhaid': int(l.split()[0]), 4270 'filename': l.split()[1]}) \ 4271 for l in pdfsets_lines) 4272 4273 else: 4274 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version) 4275 4276 return lhapdf_pdfsets
4277 4278
4279 - def get_lhapdf_version(self):
4280 """returns the lhapdf version number""" 4281 if not hasattr(self, 'lhapdfversion'): 4282 try: 4283 self.lhapdf_version = \ 4284 subprocess.Popen([self.options['lhapdf'], '--version'], 4285 stdout = subprocess.PIPE).stdout.read().strip() 4286 except OSError, error: 4287 if error.errno == 2: 4288 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'] 4289 else: 4290 raise 4291 4292 # this will be removed once some issues in lhapdf6 will be fixed 4293 if self.lhapdf_version.startswith('6.0'): 4294 raise MadGraph5Error('LHAPDF 6.0.x not supported. Please use v6.1 or later') 4295 return self.lhapdf_version
4296 4297
4298 - def get_lhapdf_pdfsetsdir(self):
4299 lhapdf_version = self.get_lhapdf_version() 4300 4301 # check if the LHAPDF_DATA_PATH variable is defined 4302 if 'LHAPDF_DATA_PATH' in os.environ.keys() and os.environ['LHAPDF_DATA_PATH']: 4303 datadir = os.environ['LHAPDF_DATA_PATH'] 4304 elif lhapdf_version.startswith('5.'): 4305 datadir = subprocess.Popen([self.options['lhapdf'], '--pdfsets-path'], 4306 stdout = subprocess.PIPE).stdout.read().strip() 4307 4308 elif lhapdf_version.startswith('6.'): 4309 datadir = subprocess.Popen([self.options['lhapdf'], '--datadir'], 4310 stdout = subprocess.PIPE).stdout.read().strip() 4311 4312 if ':' in datadir: 4313 for totry in datadir.split(':'): 4314 if os.path.exists(pjoin(totry, 'pdfsets.index')): 4315 return totry 4316 else: 4317 return None 4318 4319 return datadir
4320 4321 ############################################################################
4322 - def get_Pdir(self):
4323 """get the list of Pdirectory if not yet saved.""" 4324 4325 if hasattr(self, "Pdirs"): 4326 if self.me_dir in self.Pdirs[0]: 4327 return self.Pdirs 4328 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip()) 4329 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))] 4330 return self.Pdirs
4331
4332 - def get_lhapdf_libdir(self):
4333 4334 if 'LHAPATH' in os.environ: 4335 for d in os.environ['LHAPATH'].split(':'): 4336 if os.path.isdir(d): 4337 return d 4338 4339 4340 lhapdf_version = self.get_lhapdf_version() 4341 4342 if lhapdf_version.startswith('5.'): 4343 libdir = subprocess.Popen([self.options['lhapdf-config'], '--libdir'], 4344 stdout = subprocess.PIPE).stdout.read().strip() 4345 4346 elif lhapdf_version.startswith('6.'): 4347 libdir = subprocess.Popen([self.options['lhapdf'], '--libs'], 4348 stdout = subprocess.PIPE).stdout.read().strip() 4349 4350 return libdir
4351
4352 -class AskforEditCard(cmd.OneLinePathCompletion):
4353 """A class for asking a question where in addition you can have the 4354 set command define and modifying the param_card/run_card correctly 4355 4356 special action can be trigger via trigger_XXXX when the user start a line 4357 with XXXX. the output of such function should be new line that can be handle. 4358 (return False to repeat the question) 4359 """ 4360 4361 all_card_name = ['param_card', 'run_card', 'pythia_card', 'pythia8_card', 4362 'madweight_card', 'MadLoopParams', 'shower_card'] 4363 to_init_card = ['param', 'run', 'madweight', 'madloop', 4364 'shower', 'pythia8','delphes','madspin'] 4365 special_shortcut = {} 4366 special_shortcut_help = {} 4367 4368 integer_bias = 1 # integer corresponding to the first entry in self.cards 4369 4370 PY8Card_class = banner_mod.PY8Card 4371
4372 - def load_default(self):
4373 """ define all default variable. No load of card here. 4374 This allow to subclass this class and just change init and still have 4375 all variables defined.""" 4376 4377 if not hasattr(self, 'me_dir'): 4378 self.me_dir = None 4379 self.param_card = None 4380 self.run_card = {} 4381 self.pname2block = {} 4382 self.conflict = [] 4383 self.restricted_value = {} 4384 self.mode = '' 4385 self.cards = [] 4386 self.run_set = [] 4387 self.has_mw = False 4388 self.has_ml = False 4389 self.has_shower = False 4390 self.has_PY8 = False 4391 self.has_delphes = False 4392 self.paths = {} 4393 self.update_block = []
4394 4395
4396 - def define_paths(self, **opt):
4397 # Initiation 4398 if 'pwd' in opt: 4399 self.me_dir = opt['pwd'] 4400 elif 'mother_interface' in opt: 4401 self.mother_interface = opt['mother_interface'] 4402 if not hasattr(self, 'me_dir') or not self.me_dir: 4403 self.me_dir = self.mother_interface.me_dir 4404 4405 #define paths 4406 self.paths['param'] = pjoin(self.me_dir,'Cards','param_card.dat') 4407 self.paths['param_default'] = pjoin(self.me_dir,'Cards','param_card_default.dat') 4408 self.paths['run'] = pjoin(self.me_dir,'Cards','run_card.dat') 4409 self.paths['run_default'] = pjoin(self.me_dir,'Cards','run_card_default.dat') 4410 self.paths['transfer'] =pjoin(self.me_dir,'Cards','transfer_card.dat') 4411 self.paths['MadWeight'] =pjoin(self.me_dir,'Cards','MadWeight_card.dat') 4412 self.paths['MadWeight_default'] =pjoin(self.me_dir,'Cards','MadWeight_card_default.dat') 4413 self.paths['ML'] =pjoin(self.me_dir,'Cards','MadLoopParams.dat') 4414 self.paths['shower'] = pjoin(self.me_dir,'Cards','shower_card.dat') 4415 self.paths['shower_default'] = pjoin(self.me_dir,'Cards','shower_card_default.dat') 4416 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards','FO_analyse_card.dat') 4417 self.paths['FO_analyse_default'] = pjoin(self.me_dir,'Cards','FO_analyse_card_default.dat') 4418 self.paths['pythia'] =pjoin(self.me_dir, 'Cards','pythia_card.dat') 4419 self.paths['pythia8'] = pjoin(self.me_dir, 'Cards','pythia8_card.dat') 4420 self.paths['pythia8_default'] = pjoin(self.me_dir, 'Cards','pythia8_card_default.dat') 4421 self.paths['madspin_default'] = pjoin(self.me_dir,'Cards/madspin_card_default.dat') 4422 self.paths['madspin'] = pjoin(self.me_dir,'Cards/madspin_card.dat') 4423 self.paths['reweight'] = pjoin(self.me_dir,'Cards','reweight_card.dat') 4424 self.paths['delphes'] = pjoin(self.me_dir,'Cards','delphes_card.dat') 4425 self.paths['plot'] = pjoin(self.me_dir,'Cards','plot_card.dat') 4426 self.paths['plot_default'] = pjoin(self.me_dir,'Cards','plot_card_default.dat') 4427 self.paths['madanalysis5_parton'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card.dat') 4428 self.paths['madanalysis5_hadron'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card.dat') 4429 self.paths['madanalysis5_parton_default'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card_default.dat') 4430 self.paths['madanalysis5_hadron_default'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card_default.dat') 4431 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards', 'FO_analyse_card.dat')
4432 4433 4434 4435
4436 - def __init__(self, question, cards=[], from_banner=None, banner=None, mode='auto', *args, **opt):
4437 4438 4439 self.load_default() 4440 self.define_paths(**opt) 4441 self.last_editline_pos = 0 4442 4443 if 'allow_arg' not in opt or not opt['allow_arg']: 4444 # add some mininal content for this: 4445 opt['allow_arg'] = range(self.integer_bias, self.integer_bias+len(cards)) 4446 4447 self.param_consistency = True 4448 if 'param_consistency' in opt: 4449 self.param_consistency = opt['param_consistency'] 4450 4451 cmd.OneLinePathCompletion.__init__(self, question, *args, **opt) 4452 4453 self.conflict = set() 4454 self.mode = mode 4455 self.cards = cards 4456 self.all_vars = set() 4457 self.modified_card = set() #set of cards not in sync with filesystem 4458 # need to sync them before editing/leaving 4459 self.init_from_banner(from_banner, banner) 4460 4461 #update default path by custom one if specify in cards 4462 for card in cards: 4463 if os.path.exists(card) and os.path.sep in cards: 4464 card_name = CommonRunCmd.detect_card_type(card) 4465 card_name = card_name.split('_',1)[0] 4466 self.paths[card_name] = card 4467 4468 # go trough the initialisation of each card and detect conflict 4469 for name in self.to_init_card: 4470 new_vars = set(getattr(self, 'init_%s' % name)(cards)) 4471 new_conflict = self.all_vars.intersection(new_vars) 4472 self.conflict.union(new_conflict) 4473 self.all_vars.union(new_vars)
4474 4475
4476 - def init_from_banner(self, from_banner, banner):
4477 """ defined card that need to be initialized from the banner file 4478 from_banner should be a list of card to load from the banner object 4479 """ 4480 4481 if from_banner is None: 4482 self.from_banner = {} 4483 return 4484 misc.sprint(from_banner) 4485 self.from_banner = {} 4486 for card in from_banner: 4487 self.from_banner[card] = banner.charge_card(card) 4488 return self.from_banner
4489 4490
4491 - def get_path(self, name, cards):
4492 """initialise the path if requested""" 4493 4494 defname = '%s_default' % name 4495 4496 if name in self.from_banner: 4497 return self.from_banner[name] 4498 4499 if isinstance(cards, list): 4500 if name in cards: 4501 return True 4502 elif '%s_card.dat' % name in cards: 4503 return True 4504 elif name in self.paths and self.paths[name] in cards: 4505 return True 4506 else: 4507 cardnames = [os.path.basename(p) for p in cards] 4508 if '%s_card.dat' % name in cardnames: 4509 return True 4510 else: 4511 return False 4512 4513 elif isinstance(cards, dict) and name in cards: 4514 self.paths[name]= cards[name] 4515 if defname in cards: 4516 self.paths[defname] = cards[defname] 4517 elif os.path.isfile(cards[name].replace('.dat', '_default.dat')): 4518 self.paths[defname] = cards[name].replace('.dat', '_default.dat') 4519 else: 4520 self.paths[defname] = self.paths[name] 4521 4522 return True 4523 else: 4524 return False
4525
4526 - def init_param(self, cards):
4527 """check if we need to load the param_card""" 4528 4529 self.pname2block = {} 4530 self.restricted_value = {} 4531 self.param_card = {} 4532 4533 is_valid_path = self.get_path('param', cards) 4534 if not is_valid_path: 4535 self.param_consistency = False 4536 return [] 4537 if isinstance(is_valid_path, param_card_mod.ParamCard): 4538 self.param_card = is_valid_path 4539 self.param_consistency = False 4540 return [] 4541 4542 try: 4543 self.param_card = param_card_mod.ParamCard(self.paths['param']) 4544 except (param_card_mod.InvalidParamCard, ValueError) as e: 4545 logger.error('Current param_card is not valid. We are going to use the default one.') 4546 logger.error('problem detected: %s' % e) 4547 files.cp(self.paths['param_default'], self.paths['param']) 4548 self.param_card = param_card_mod.ParamCard(self.paths['param']) 4549 4550 # Read the comment of the param_card_default to find name variable for 4551 # the param_card also check which value seems to be constrained in the 4552 # model. 4553 if os.path.exists(self.paths['param_default']): 4554 default_param = param_card_mod.ParamCard(self.paths['param_default']) 4555 else: 4556 default_param = param_card_mod.ParamCard(self.param_card) 4557 self.pname2block, self.restricted_value = default_param.analyze_param_card() 4558 self.param_card_default = default_param 4559 return self.pname2block.keys()
4560
4561 - def init_run(self, cards):
4562 4563 self.run_set = [] 4564 is_valid_path = self.get_path('run', cards) 4565 if not is_valid_path: 4566 return [] 4567 if isinstance(is_valid_path, banner_mod.RunCard): 4568 self.run_card = is_valid_path 4569 return [] 4570 4571 4572 try: 4573 self.run_card = banner_mod.RunCard(self.paths['run'], consistency='warning') 4574 except IOError: 4575 self.run_card = {} 4576 try: 4577 run_card_def = banner_mod.RunCard(self.paths['run_default']) 4578 except IOError: 4579 run_card_def = {} 4580 4581 4582 if run_card_def: 4583 if self.run_card: 4584 self.run_set = run_card_def.keys() + self.run_card.hidden_param 4585 else: 4586 self.run_set = run_card_def.keys() + run_card_def.hidden_param 4587 elif self.run_card: 4588 self.run_set = self.run_card.keys() 4589 else: 4590 self.run_set = [] 4591 4592 if self.run_set: 4593 self.special_shortcut.update( 4594 {'ebeam':([float],['run_card ebeam1 %(0)s', 'run_card ebeam2 %(0)s']), 4595 'lpp': ([int],['run_card lpp1 %(0)s', 'run_card lpp2 %(0)s' ]), 4596 'lhc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']), 4597 'lep': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']), 4598 'ilc': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']), 4599 'lcc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']), 4600 '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']), 4601 'no_parton_cut':([],['run_card nocut T']), 4602 'cm_velocity':([float], [lambda self :self.set_CM_velocity]), 4603 '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']), 4604 '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' ]), 4605 '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']), 4606 }) 4607 4608 self.special_shortcut_help.update({ 4609 'ebeam' : 'syntax: set ebeam VALUE:\n This parameter sets the energy to both beam to the value in GeV', 4610 'lpp' : 'syntax: set ebeam VALUE:\n'+\ 4611 ' Set the type of beam to a given value for both beam\n'+\ 4612 ' 0 : means no PDF\n'+\ 4613 ' 1 : means proton PDF\n'+\ 4614 ' -1 : means antiproton PDF\n'+\ 4615 ' 2 : means PDF for elastic photon emited from a proton\n'+\ 4616 ' 3 : means PDF for elastic photon emited from an electron', 4617 'lhc' : 'syntax: set lhc VALUE:\n Set for a proton-proton collision with that given center of mass energy (in TeV)', 4618 'lep' : 'syntax: set lep VALUE:\n Set for a electron-positron collision with that given center of mass energy (in GeV)', 4619 'fixed_scale' : 'syntax: set fixed_scale VALUE:\n Set all scales to the give value (in GeV)', 4620 'no_parton_cut': 'remove all cut (but BW_cutoff)', 4621 'cm_velocity': 'set sqrts to have the above velocity for the incoming particles', 4622 'pbpb': 'setup heavy ion configuration for lead-lead collision', 4623 'pbp': 'setup heavy ion configuration for lead-proton collision', 4624 'pp': 'remove setup of heavy ion configuration to set proton-proton collision', 4625 }) 4626 4627 self.update_block += [b.name for b in self.run_card.blocks] 4628 4629 return self.run_set
4630
4631 - def init_madweight(self, cards):
4632 4633 self.has_mw = False 4634 if not self.get_path('madweight', cards): 4635 return [] 4636 4637 #add special function associated to MW 4638 self.do_change_tf = self.mother_interface.do_define_transfer_fct 4639 self.complete_change_tf = self.mother_interface.complete_define_transfer_fct 4640 self.help_change_tf = self.mother_interface.help_define_transfer_fct 4641 if not os.path.exists(self.paths['transfer']): 4642 logger.warning('No transfer function currently define. Please use the change_tf command to define one.') 4643 4644 self.has_mw = True 4645 try: 4646 import madgraph.madweight.Cards as mwcards 4647 except: 4648 import internal.madweight.Cards as mwcards 4649 self.mw_card = mwcards.Card(self.paths['MadWeight']) 4650 self.mw_card = self.mw_card.info 4651 self.mw_vars = [] 4652 for key in self.mw_card: 4653 if key == 'comment': 4654 continue 4655 for key2 in self.mw_card.info[key]: 4656 if isinstance(key2, str) and not key2.isdigit(): 4657 self.mw_vars.append(key2) 4658 return self.mw_vars
4659
4660 - def init_madloop(self, cards):
4661 4662 if isinstance(cards, dict): 4663 for key in ['ML', 'madloop','MadLoop']: 4664 if key in cards: 4665 self.paths['ML'] = cards[key] 4666 4667 self.has_ml = False 4668 if os.path.isfile(self.paths['ML']): 4669 self.has_ml = True 4670 self.MLcard = banner_mod.MadLoopParam(self.paths['ML']) 4671 self.MLcardDefault = banner_mod.MadLoopParam() 4672 self.ml_vars = [k.lower() for k in self.MLcard.keys()] 4673 return self.ml_vars 4674 return []
4675
4676 - def init_shower(self, cards):
4677 4678 self.has_shower = False 4679 if not self.get_path('shower', cards): 4680 return [] 4681 self.has_shower = True 4682 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower']) 4683 self.shower_vars = self.shower_card.keys() 4684 return self.shower_vars
4685
4686 - def init_pythia8(self, cards):
4687 4688 self.has_PY8 = False 4689 if not self.get_path('pythia8', cards): 4690 return [] 4691 4692 self.has_PY8 = True 4693 self.PY8Card = self.PY8Card_class(self.paths['pythia8']) 4694 self.PY8CardDefault = self.PY8Card_class() 4695 4696 self.py8_vars = [k.lower() for k in self.PY8Card.keys()] 4697 4698 self.special_shortcut.update({ 4699 'simplepy8':([],['pythia8_card hadronlevel:all False', 4700 'pythia8_card partonlevel:mpi False', 4701 'pythia8_card BeamRemnants:primordialKT False', 4702 'pythia8_card PartonLevel:Remnants False', 4703 'pythia8_card Check:event False', 4704 'pythia8_card TimeShower:QEDshowerByQ False', 4705 'pythia8_card TimeShower:QEDshowerByL False', 4706 'pythia8_card SpaceShower:QEDshowerByQ False', 4707 'pythia8_card SpaceShower:QEDshowerByL False', 4708 'pythia8_card PartonLevel:FSRinResonances False', 4709 'pythia8_card ProcessLevel:resonanceDecays False', 4710 ]), 4711 'mpi':([bool],['pythia8_card partonlevel:mpi %(0)s']), 4712 }) 4713 self.special_shortcut_help.update({ 4714 'simplepy8' : 'Turn off non-perturbative slow features of Pythia8.', 4715 'mpi' : 'syntax: set mpi value: allow to turn mpi in Pythia8 on/off', 4716 }) 4717 return []
4718
4719 - def init_madspin(self, cards):
4720 4721 if not self.get_path('madspin', cards): 4722 return [] 4723 4724 self.special_shortcut.update({ 4725 'spinmode':([str], ['add madspin_card --before_line="launch" set spinmode %(0)s']) 4726 }) 4727 self.special_shortcut_help.update({ 4728 '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.' 4729 }) 4730 return []
4731
4732 - def init_delphes(self, cards):
4733 4734 self.has_delphes = False 4735 if not self.get_path('pythia8', cards): 4736 return [] 4737 self.has_delphes = True 4738 return []
4739 4740
4741 - def set_CM_velocity(self, line):
4742 """compute sqrts from the velocity in the center of mass frame""" 4743 4744 v = banner_mod.ConfigFile.format_variable(line, float, 'velocity') 4745 # Define self.proc_characteristics 4746 self.mother_interface.get_characteristics() 4747 proc_info = self.mother_interface.proc_characteristics 4748 if 'pdg_initial1' not in proc_info: 4749 logger.warning('command not supported') 4750 4751 if len(proc_info['pdg_initial1']) == 1 == len(proc_info['pdg_initial2']) and\ 4752 abs(proc_info['pdg_initial1'][0]) == abs(proc_info['pdg_initial2'][0]): 4753 4754 m = self.param_card.get_value('mass', abs(proc_info['pdg_initial1'][0])) 4755 sqrts = 2*m/ math.sqrt(1-v**2) 4756 self.do_set('run_card ebeam1 %s' % (sqrts/2.0)) 4757 self.do_set('run_card ebeam2 %s' % (sqrts/2.0)) 4758 self.do_set('run_card lpp 0') 4759 else: 4760 logger.warning('This is only possible for a single particle in the initial state')
4761 4762 4763
4764 - def do_help(self, line, conflict_raise=False, banner=True):
4765 # TODO nicer factorization ! 4766 4767 # try: 4768 if banner: 4769 logger.info('*** HELP MESSAGE ***', '$MG:BOLD') 4770 4771 args = self.split_arg(line) 4772 # handle comand related help 4773 if len(args)==0 or (len(args) == 1 and hasattr(self, 'do_%s' % args[0])): 4774 out = cmd.BasicCmd.do_help(self, line) 4775 if len(args)==0: 4776 print 'Allowed Argument' 4777 print '================' 4778 print '\t'.join(self.allow_arg) 4779 print 4780 print 'Special shortcut: (type help <name>)' 4781 print '====================================' 4782 print ' syntax: set <name> <value>' 4783 print '\t'.join(self.special_shortcut) 4784 print 4785 if banner: 4786 logger.info('*** END HELP ***', '$MG:BOLD') 4787 return out 4788 # check for special shortcut. 4789 # special shortcut: 4790 if args[0] in self.special_shortcut: 4791 if args[0] in self.special_shortcut_help: 4792 print self.special_shortcut_help[args[0]] 4793 if banner: 4794 logger.info('*** END HELP ***', '$MG:BOLD') 4795 return 4796 4797 start = 0 4798 card = '' 4799 if args[0]+'_card' in self.all_card_name+ self.cards: 4800 args[0] += '_card' 4801 elif args[0]+'.dat' in self.all_card_name+ self.cards: 4802 args[0] += '.dat' 4803 elif args[0]+'_card.dat' in self.all_card_name+ self.cards: 4804 args[0] += '_card.dat' 4805 if args[0] in self.all_card_name + self.cards: 4806 start += 1 4807 card = args[0] 4808 if len(args) == 1: 4809 if args[0] == 'pythia8_card': 4810 args[0] = 'PY8Card' 4811 if args[0] == 'param_card': 4812 logger.info("Param_card information: ", '$MG:color:BLUE') 4813 print "File to define the various model parameter" 4814 logger.info("List of the Block defined:",'$MG:color:BLUE') 4815 print "\t".join(self.param_card.keys()) 4816 elif args[0].startswith('madanalysis5'): 4817 print 'This card allow to make plot with the madanalysis5 package' 4818 print 'An example card is provided. For more information about the ' 4819 print 'syntax please refer to: https://madanalysis.irmp.ucl.ac.be/' 4820 print 'or to the user manual [arXiv:1206.1599]' 4821 if args[0].startswith('madanalysis5_hadron'): 4822 print 4823 print 'This card also allow to make recasting analysis' 4824 print 'For more detail, see: arXiv:1407.3278' 4825 elif hasattr(self, args[0]): 4826 logger.info("%s information: " % args[0], '$MG:color:BLUE') 4827 print(eval('self.%s' % args[0]).__doc__) 4828 logger.info("List of parameter associated", '$MG:color:BLUE') 4829 print "\t".join(eval('self.%s' % args[0]).keys()) 4830 if banner: 4831 logger.info('*** END HELP ***', '$MG:BOLD') 4832 return card 4833 4834 #### RUN CARD 4835 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']: 4836 if args[start] not in self.run_set: 4837 args[start] = [l for l in self.run_set if l.lower() == args[start]][0] 4838 4839 if args[start] in self.conflict and not conflict_raise: 4840 conflict_raise = True 4841 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4842 if card == '': 4843 logger.info('** If not explicitely speficy this parameter will modif the run_card file', '$MG:BOLD') 4844 4845 self.run_card.do_help(args[start]) 4846 ### PARAM_CARD WITH BLOCK NAME ----------------------------------------- 4847 elif (args[start] in self.param_card or args[start] == 'width') \ 4848 and card in ['','param_card']: 4849 if args[start] in self.conflict and not conflict_raise: 4850 conflict_raise = True 4851 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4852 if card == '': 4853 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD') 4854 4855 if args[start] == 'width': 4856 args[start] = 'decay' 4857 4858 if len(args) == start+1: 4859 self.param_card.do_help(args[start], tuple()) 4860 key = None 4861 elif args[start+1] in self.pname2block: 4862 all_var = self.pname2block[args[start+1]] 4863 key = None 4864 for bname, lhaid in all_var: 4865 if bname == args[start]: 4866 key = lhaid 4867 break 4868 else: 4869 logger.warning('%s is not part of block "%s" but "%s". please correct.' % 4870 (args[start+1], args[start], bname)) 4871 else: 4872 try: 4873 key = tuple([int(i) for i in args[start+1:]]) 4874 except ValueError: 4875 logger.warning('Failed to identify LHA information') 4876 return card 4877 4878 if key in self.param_card[args[start]].param_dict: 4879 self.param_card.do_help(args[start], key, default=self.param_card_default) 4880 elif key: 4881 logger.warning('invalid information: %s not defined in the param_card' % (key,)) 4882 # PARAM_CARD NO BLOCK NAME --------------------------------------------- 4883 elif args[start] in self.pname2block and card in ['','param_card']: 4884 if args[start] in self.conflict and not conflict_raise: 4885 conflict_raise = True 4886 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4887 if card == '': 4888 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD') 4889 4890 all_var = self.pname2block[args[start]] 4891 for bname, lhaid in all_var: 4892 new_line = 'param_card %s %s %s' % (bname, 4893 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:])) 4894 self.do_help(new_line, conflict_raise=True, banner=False) 4895 4896 # MadLoop Parameter --------------------------------------------------- 4897 elif self.has_ml and args[start] in self.ml_vars \ 4898 and card in ['', 'MadLoop_card']: 4899 4900 if args[start] in self.conflict and not conflict_raise: 4901 conflict_raise = True 4902 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4903 if card == '': 4904 logger.info('** If not explicitely speficy this parameter will modif the madloop_card file', '$MG:BOLD') 4905 4906 self.MLcard.do_help(args[start]) 4907 4908 # Pythia8 Parameter --------------------------------------------------- 4909 elif self.has_PY8 and args[start] in self.PY8Card: 4910 if args[start] in self.conflict and not conflict_raise: 4911 conflict_raise = True 4912 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD') 4913 if card == '': 4914 logger.info('** If not explicitely speficy this parameter will modif the pythia8_card file', '$MG:BOLD') 4915 4916 self.PY8Card.do_help(args[start]) 4917 elif card.startswith('madanalysis5'): 4918 print 'MA5' 4919 4920 4921 elif banner: 4922 print "no help available" 4923 4924 if banner: 4925 logger.info('*** END HELP ***', '$MG:BOLD') 4926 #raw_input('press enter to quit the help') 4927 return card
4928 # except Exception, error: 4929 # if __debug__: 4930 # import traceback 4931 # traceback.print_exc() 4932 # print error 4933
4934 - def complete_help(self, text, line, begidx, endidx):
4935 prev_timer = signal.alarm(0) # avoid timer if any 4936 if prev_timer: 4937 nb_back = len(line) 4938 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 4939 self.stdout.write(line) 4940 self.stdout.flush() 4941 # try: 4942 possibilities = self.complete_set(text, line, begidx, endidx,formatting=False) 4943 if line[:begidx].strip() == 'help': 4944 possibilities['Defined command'] = cmd.BasicCmd.completenames(self, text, line)#, begidx, endidx) 4945 possibilities.update(self.complete_add(text, line, begidx, endidx,formatting=False)) 4946 return self.deal_multiple_categories(possibilities)
4947 # except Exception, error: 4948 # import traceback 4949 # traceback.print_exc() 4950 # print error 4951
4952 - def complete_update(self, text, line, begidx, endidx):
4953 prev_timer = signal.alarm(0) # avoid timer if any 4954 if prev_timer: 4955 nb_back = len(line) 4956 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 4957 self.stdout.write(line) 4958 self.stdout.flush() 4959 4960 valid = ['dependent', 'missing', 'to_slha1', 'to_slha2', 'to_full'] 4961 valid += self.update_block 4962 4963 arg = line[:begidx].split() 4964 if len(arg) <=1: 4965 return self.list_completion(text, valid, line) 4966 elif arg[0] == 'to_full': 4967 return self.list_completion(text, self.cards , line)
4968
4969 - def complete_set(self, text, line, begidx, endidx, formatting=True):
4970 """ Complete the set command""" 4971 4972 prev_timer = signal.alarm(0) # avoid timer if any 4973 if prev_timer: 4974 nb_back = len(line) 4975 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 4976 self.stdout.write(line) 4977 self.stdout.flush() 4978 4979 possibilities = {} 4980 allowed = {} 4981 args = self.split_arg(line[0:begidx]) 4982 if args[-1] in ['Auto', 'default']: 4983 return 4984 4985 if len(args) == 1: 4986 allowed = {'category':'', 'run_card':'', 'block':'all', 'param_card':'','shortcut':''} 4987 if self.has_mw: 4988 allowed['madweight_card'] = '' 4989 allowed['mw_block'] = 'all' 4990 if self.has_shower: 4991 allowed['shower_card'] = '' 4992 if self.has_ml: 4993 allowed['madloop_card'] = '' 4994 if self.has_PY8: 4995 allowed['pythia8_card'] = '' 4996 if self.has_delphes: 4997 allowed['delphes_card'] = '' 4998 4999 elif len(args) == 2: 5000 if args[1] == 'run_card': 5001 allowed = {'run_card':'default'} 5002 elif args[1] == 'param_card': 5003 allowed = {'block':'all', 'param_card':'default'} 5004 elif self.param_card and args[1] in self.param_card.keys(): 5005 allowed = {'block':args[1]} 5006 elif args[1] == 'width': 5007 allowed = {'block': 'decay'} 5008 elif args[1] == 'MadWeight_card': 5009 allowed = {'madweight_card':'default', 'mw_block': 'all'} 5010 elif args[1] == 'MadLoop_card': 5011 allowed = {'madloop_card':'default'} 5012 elif args[1] == 'pythia8_card': 5013 allowed = {'pythia8_card':'default'} 5014 elif self.has_mw and args[1] in self.mw_card.keys(): 5015 allowed = {'mw_block':args[1]} 5016 elif args[1] == 'shower_card': 5017 allowed = {'shower_card':'default'} 5018 elif args[1] == 'delphes_card': 5019 allowed = {'delphes_card':'default'} 5020 else: 5021 allowed = {'value':''} 5022 5023 else: 5024 start = 1 5025 if args[1] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card', 5026 'MadLoop_card','pythia8_card','delphes_card','plot_card', 5027 'madanalysis5_parton_card','madanalysis5_hadron_card']: 5028 start = 2 5029 5030 if args[-1] in self.pname2block.keys(): 5031 allowed['value'] = 'default' 5032 elif args[start] in self.param_card.keys() or args[start] == 'width': 5033 if args[start] == 'width': 5034 args[start] = 'decay' 5035 5036 if args[start+1:]: 5037 allowed = {'block':(args[start], args[start+1:])} 5038 else: 5039 allowed = {'block':args[start]} 5040 elif self.has_mw and args[start] in self.mw_card.keys(): 5041 if args[start+1:]: 5042 allowed = {'mw_block':(args[start], args[start+1:])} 5043 else: 5044 allowed = {'mw_block':args[start]} 5045 #elif len(args) == start +1: 5046 # allowed['value'] = '' 5047 else: 5048 allowed['value'] = '' 5049 5050 if 'category' in allowed.keys(): 5051 categories = ['run_card', 'param_card'] 5052 if self.has_mw: 5053 categories.append('MadWeight_card') 5054 if self.has_shower: 5055 categories.append('shower_card') 5056 if self.has_ml: 5057 categories.append('MadLoop_card') 5058 if self.has_PY8: 5059 categories.append('pythia8_card') 5060 if self.has_delphes: 5061 categories.append('delphes_card') 5062 5063 possibilities['category of parameter (optional)'] = \ 5064 self.list_completion(text, categories) 5065 5066 if 'shortcut' in allowed.keys(): 5067 possibilities['special values'] = self.list_completion(text, self.special_shortcut.keys()+['qcut', 'showerkt']) 5068 5069 if 'run_card' in allowed.keys(): 5070 opts = self.run_set 5071 if allowed['run_card'] == 'default': 5072 opts.append('default') 5073 5074 5075 possibilities['Run Card'] = self.list_completion(text, opts) 5076 5077 if 'param_card' in allowed.keys(): 5078 opts = self.pname2block.keys() 5079 if allowed['param_card'] == 'default': 5080 opts.append('default') 5081 possibilities['Param Card'] = self.list_completion(text, opts) 5082 5083 if 'madweight_card' in allowed.keys(): 5084 opts = self.mw_vars + [k for k in self.mw_card.keys() if k !='comment'] 5085 if allowed['madweight_card'] == 'default': 5086 opts.append('default') 5087 possibilities['MadWeight Card'] = self.list_completion(text, opts) 5088 5089 if 'madloop_card' in allowed.keys(): 5090 opts = self.ml_vars 5091 if allowed['madloop_card'] == 'default': 5092 opts.append('default') 5093 possibilities['MadLoop Parameter'] = self.list_completion(text, opts) 5094 5095 if 'pythia8_card' in allowed.keys(): 5096 opts = self.py8_vars 5097 if allowed['pythia8_card'] == 'default': 5098 opts.append('default') 5099 possibilities['Pythia8 Parameter'] = self.list_completion(text, opts) 5100 5101 if 'shower_card' in allowed.keys(): 5102 opts = self.shower_vars + [k for k in self.shower_card.keys() if k !='comment'] 5103 if allowed['shower_card'] == 'default': 5104 opts.append('default') 5105 possibilities['Shower Card'] = self.list_completion(text, opts) 5106 5107 if 'delphes_card' in allowed: 5108 if allowed['delphes_card'] == 'default': 5109 opts = ['default', 'atlas', 'cms'] 5110 possibilities['Delphes Card'] = self.list_completion(text, opts) 5111 5112 if 'value' in allowed.keys(): 5113 opts = ['default'] 5114 if 'decay' in args: 5115 opts.append('Auto') 5116 opts.append('Auto@NLO') 5117 elif args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay': 5118 opts.append('Auto') 5119 opts.append('Auto@NLO') 5120 if args[-1] in self.run_set: 5121 allowed_for_run = [] 5122 if args[-1].lower() in self.run_card.allowed_value: 5123 allowed_for_run = self.run_card.allowed_value[args[-1].lower()] 5124 if '*' in allowed_for_run: 5125 allowed_for_run.remove('*') 5126 elif isinstance(self.run_card[args[-1]], bool): 5127 allowed_for_run = ['True', 'False'] 5128 opts += [str(i) for i in allowed_for_run] 5129 5130 5131 possibilities['Special Value'] = self.list_completion(text, opts) 5132 5133 if 'block' in allowed.keys() and self.param_card: 5134 if allowed['block'] == 'all' and self.param_card: 5135 allowed_block = [i for i in self.param_card.keys() if 'qnumbers' not in i] 5136 allowed_block.append('width') 5137 possibilities['Param Card Block' ] = \ 5138 self.list_completion(text, allowed_block) 5139 5140 elif isinstance(allowed['block'], basestring): 5141 block = self.param_card[allowed['block']].param_dict 5142 ids = [str(i[0]) for i in block 5143 if (allowed['block'], i) not in self.restricted_value] 5144 possibilities['Param Card id' ] = self.list_completion(text, ids) 5145 varname = [name for name, all_var in self.pname2block.items() 5146 if any((bname == allowed['block'] 5147 for bname,lhaid in all_var))] 5148 possibilities['Param card variable'] = self.list_completion(text, 5149 varname) 5150 else: 5151 block = self.param_card[allowed['block'][0]].param_dict 5152 nb = len(allowed['block'][1]) 5153 ids = [str(i[nb]) for i in block if len(i) > nb and \ 5154 [str(a) for a in i[:nb]] == allowed['block'][1]] 5155 5156 if not ids: 5157 if tuple([int(i) for i in allowed['block'][1]]) in block: 5158 opts = ['default'] 5159 if allowed['block'][0] == 'decay': 5160 opts.append('Auto') 5161 opts.append('Auto@NLO') 5162 possibilities['Special value'] = self.list_completion(text, opts) 5163 possibilities['Param Card id' ] = self.list_completion(text, ids) 5164 5165 if 'mw_block' in allowed.keys(): 5166 if allowed['mw_block'] == 'all': 5167 allowed_block = [i for i in self.mw_card.keys() if 'comment' not in i] 5168 possibilities['MadWeight Block' ] = \ 5169 self.list_completion(text, allowed_block) 5170 elif isinstance(allowed['mw_block'], basestring): 5171 block = self.mw_card[allowed['mw_block']] 5172 ids = [str(i[0]) if isinstance(i, tuple) else str(i) for i in block] 5173 possibilities['MadWeight Card id' ] = self.list_completion(text, ids) 5174 else: 5175 block = self.mw_card[allowed['mw_block'][0]] 5176 nb = len(allowed['mw_block'][1]) 5177 ids = [str(i[nb]) for i in block if isinstance(i, tuple) and\ 5178 len(i) > nb and \ 5179 [str(a) for a in i[:nb]] == allowed['mw_block'][1]] 5180 5181 if not ids: 5182 if tuple([i for i in allowed['mw_block'][1]]) in block or \ 5183 allowed['mw_block'][1][0] in block.keys(): 5184 opts = ['default'] 5185 possibilities['Special value'] = self.list_completion(text, opts) 5186 possibilities['MadWeight Card id' ] = self.list_completion(text, ids) 5187 5188 return self.deal_multiple_categories(possibilities, formatting)
5189
5190 - def do_set(self, line):
5191 """ edit the value of one parameter in the card""" 5192 5193 5194 args = self.split_arg(line) 5195 5196 5197 if len(args) == 0: 5198 logger.warning("No argument. For help type 'help set'.") 5199 # fix some formatting problem 5200 if len(args)==1 and '=' in args[-1]: 5201 arg1, arg2 = args.pop(-1).split('=',1) 5202 args += [arg1, arg2] 5203 if '=' in args: 5204 args.remove('=') 5205 5206 args[:-1] = [ a.lower() for a in args[:-1]] 5207 if len(args) == 1: #special shortcut without argument -> lowercase 5208 args = [args[0].lower()] 5209 # special shortcut: 5210 if args[0] in self.special_shortcut: 5211 targettypes , cmd = self.special_shortcut[args[0]] 5212 if len(args) != len(targettypes) +1: 5213 logger.warning('shortcut %s requires %s argument' % (args[0], len(targettypes))) 5214 if len(args) < len(targettypes) +1: 5215 return 5216 else: 5217 logger.warning('additional argument will be ignored') 5218 values ={} 5219 for i, argtype in enumerate(targettypes): 5220 try: 5221 values = {str(i): banner_mod.ConfigFile.format_variable(args[i+1], argtype, args[0])} 5222 except ValueError as e: 5223 logger.warning("Wrong argument: The entry #%s should be of type %s.", i+1, argtype) 5224 return 5225 except InvalidCmd as e: 5226 logger.warning(str(e)) 5227 return 5228 #else: 5229 # logger.warning("too many argument for this command") 5230 # return 5231 for arg in cmd: 5232 if isinstance(arg, str): 5233 try: 5234 text = arg % values 5235 except KeyError: 5236 logger.warning("This command requires one argument") 5237 return 5238 except Exception as e: 5239 logger.warning(str(e)) 5240 return 5241 else: 5242 split = text.split() 5243 if hasattr(self, 'do_%s' % split[0]): 5244 getattr(self, 'do_%s' % split[0])(' '.join(split[1:])) 5245 else: 5246 self.do_set(text) 5247 #need to call a function 5248 else: 5249 val = [values[str(i)] for i in range(len(values))] 5250 try: 5251 arg(self)(*val) 5252 except Exception, e: 5253 logger.warning(str(e)) 5254 return 5255 5256 start = 0 5257 if len(args) < 2: 5258 logger.warning('Invalid set command %s (need two arguments)' % line) 5259 return 5260 5261 # Special case for the qcut value 5262 if args[0].lower() == 'qcut': 5263 pythia_path = self.paths['pythia'] 5264 if os.path.exists(pythia_path): 5265 logger.info('add line QCUT = %s in pythia_card.dat' % args[1]) 5266 p_card = open(pythia_path,'r').read() 5267 p_card, n = re.subn('''^\s*QCUT\s*=\s*[\de\+\-\.]*\s*$''', 5268 ''' QCUT = %s ''' % args[1], \ 5269 p_card, flags=(re.M+re.I)) 5270 if n==0: 5271 p_card = '%s \n QCUT= %s' % (p_card, args[1]) 5272 with open(pythia_path, 'w') as fsock: 5273 fsock.write(p_card) 5274 return 5275 # Special case for the showerkt value 5276 if args[0].lower() == 'showerkt': 5277 pythia_path = self.paths['pythia'] 5278 if os.path.exists(pythia_path): 5279 logger.info('add line SHOWERKT = %s in pythia_card.dat' % args[1].upper()) 5280 p_card = open(pythia_path,'r').read() 5281 p_card, n = re.subn('''^\s*SHOWERKT\s*=\s*[default\de\+\-\.]*\s*$''', 5282 ''' SHOWERKT = %s ''' % args[1].upper(), \ 5283 p_card, flags=(re.M+re.I)) 5284 if n==0: 5285 p_card = '%s \n SHOWERKT= %s' % (p_card, args[1].upper()) 5286 with open(pythia_path, 'w') as fsock: 5287 fsock.write(p_card) 5288 return 5289 5290 card = '' #store which card need to be modify (for name conflict) 5291 if args[0] == 'madweight_card': 5292 if not self.mw_card: 5293 logger.warning('Invalid Command: No MadWeight card defined.') 5294 return 5295 args[0] = 'MadWeight_card' 5296 5297 if args[0] == 'shower_card': 5298 if not self.shower_card: 5299 logger.warning('Invalid Command: No Shower card defined.') 5300 return 5301 args[0] = 'shower_card' 5302 5303 if args[0] == "madloop_card": 5304 if not self.has_ml: 5305 logger.warning('Invalid Command: No MadLoopParam card defined.') 5306 return 5307 args[0] = 'MadLoop_card' 5308 5309 if args[0] == "pythia8_card": 5310 if not self.has_PY8: 5311 logger.warning('Invalid Command: No Pythia8 card defined.') 5312 return 5313 args[0] = 'pythia8_card' 5314 5315 if args[0] == 'delphes_card': 5316 if not self.has_delphes: 5317 logger.warning('Invalid Command: No Delphes card defined.') 5318 return 5319 if args[1] == 'atlas': 5320 logger.info("set default ATLAS configuration for Delphes", '$MG:BOLD') 5321 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_ATLAS.dat'), 5322 pjoin(self.me_dir,'Cards', 'delphes_card.dat')) 5323 return 5324 elif args[1] == 'cms': 5325 logger.info("set default CMS configuration for Delphes",'$MG:BOLD') 5326 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_CMS.dat'), 5327 pjoin(self.me_dir,'Cards', 'delphes_card.dat')) 5328 return 5329 5330 if args[0] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card', 5331 'delphes_card','madanalysis5_hadron_card','madanalysis5_parton_card']: 5332 5333 if args[1] == 'default': 5334 logger.info('replace %s by the default card' % args[0],'$MG:BOLD') 5335 files.cp(self.paths['%s_default' %args[0][:-5]], self.paths[args[0][:-5]]) 5336 if args[0] == 'param_card': 5337 self.param_card = param_card_mod.ParamCard(self.paths['param']) 5338 elif args[0] == 'run_card': 5339 self.run_card = banner_mod.RunCard(self.paths['run']) 5340 elif args[0] == 'shower_card': 5341 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower']) 5342 return 5343 else: 5344 card = args[0] 5345 start=1 5346 if len(args) < 3: 5347 logger.warning('Invalid set command: %s (not enough arguments)' % line) 5348 return 5349 5350 elif args[0] in ['MadLoop_card']: 5351 if args[1] == 'default': 5352 logger.info('replace MadLoopParams.dat by the default card','$MG:BOLD') 5353 self.MLcard = banner_mod.MadLoopParam(self.MLcardDefault) 5354 self.MLcard.write(self.paths['ML'], 5355 commentdefault=True) 5356 return 5357 else: 5358 card = args[0] 5359 start=1 5360 if len(args) < 3: 5361 logger.warning('Invalid set command: %s (not enough arguments)' % line) 5362 return 5363 elif args[0] in ['pythia8_card']: 5364 if args[1] == 'default': 5365 logger.info('replace pythia8_card.dat by the default card','$MG:BOLD') 5366 self.PY8Card = self.PY8Card_class(self.PY8CardDefault) 5367 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'), 5368 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 5369 print_only_visible=True) 5370 return 5371 else: 5372 card = args[0] 5373 start=1 5374 if len(args) < 3: 5375 logger.warning('Invalid set command: %s (not enough arguments)' % line) 5376 return 5377 elif args[0] in ['madspin_card']: 5378 if args[1] == 'default': 5379 logger.info('replace madspin_card.dat by the default card','$MG:BOLD') 5380 files.cp(self.paths['MS_default'], self.paths['madspin']) 5381 return 5382 else: 5383 logger.warning("""Command set not allowed for modifying the madspin_card. 5384 Check the command \"decay\" instead.""") 5385 return 5386 5387 #### RUN CARD 5388 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']: 5389 5390 if args[start] not in self.run_set: 5391 if card in self.from_banner or 'run' in self.from_banner: 5392 raise Exception, "change not allowed for this card: event already generated!" 5393 args[start] = [l for l in self.run_set if l.lower() == args[start]][0] 5394 5395 if args[start] in self.conflict and card == '': 5396 text = 'Ambiguous name (present in more than one card). Will assume it to be referred to run_card.\n' 5397 text += 'If this is not intended, please reset it in the run_card and specify the relevant card to \n' 5398 text += 'edit, in the format < set card parameter value >' 5399 logger.warning(text) 5400 5401 if args[start+1] == 'default': 5402 default = banner_mod.RunCard(self.paths['run_default']) 5403 if args[start] in default.keys(): 5404 self.setR(args[start],default[args[start]]) 5405 else: 5406 logger.info('remove information %s from the run_card' % args[start],'$MG:BOLD') 5407 del self.run_card[args[start]] 5408 else: 5409 lower_name = args[0].lower() 5410 if lower_name.startswith('sys_') or \ 5411 lower_name in self.run_card.list_parameter or \ 5412 lower_name in self.run_card.dict_parameter: 5413 val = ' '.join(args[start+1:]) 5414 val = val.split('#')[0] 5415 else: 5416 val = args[start+1] 5417 self.setR(args[start], val) 5418 self.modified_card.add('run') # delayed writing of the run_card 5419 # special mode for set run_card nocut T (generated by set no_parton_cut 5420 elif card == 'run_card' and args[start] in ['nocut', 'no_cut']: 5421 logger.info("Going to remove all cuts from the run_card", '$MG:BOLD') 5422 self.run_card.remove_all_cut() 5423 self.modified_card.add('run') # delayed writing of the run_card 5424 ### PARAM_CARD WITH BLOCK NAME ----------------------------------------- 5425 elif self.param_card and (args[start] in self.param_card or args[start] == 'width') \ 5426 and card in ['','param_card']: 5427 #special treatment for scan 5428 if any(t.startswith('scan') for t in args): 5429 index = [i for i,t in enumerate(args) if t.startswith('scan')][0] 5430 args = args[:index] + [' '.join(args[index:])] 5431 5432 if args[start] in self.conflict and card == '': 5433 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5434 text += ' in the format < set card parameter value>' 5435 logger.warning(text) 5436 return 5437 5438 if args[start] == 'width': 5439 args[start] = 'decay' 5440 5441 if args[start+1] in self.pname2block: 5442 all_var = self.pname2block[args[start+1]] 5443 key = None 5444 for bname, lhaid in all_var: 5445 if bname == args[start]: 5446 key = lhaid 5447 break 5448 else: 5449 logger.warning('%s is not part of block "%s" but "%s". please correct.' % 5450 (args[start+1], args[start], bname)) 5451 return 5452 else: 5453 try: 5454 key = tuple([int(i) for i in args[start+1:-1]]) 5455 except ValueError: 5456 if args[start] == 'decay' and args[start+1:-1] == ['all']: 5457 for key in self.param_card[args[start]].param_dict: 5458 if (args[start], key) in self.restricted_value: 5459 continue 5460 else: 5461 self.setP(args[start], key, args[-1]) 5462 self.modified_card.add('param') 5463 return 5464 logger.warning('invalid set command %s (failed to identify LHA information)' % line) 5465 return 5466 5467 if key in self.param_card[args[start]].param_dict: 5468 if (args[start], key) in self.restricted_value: 5469 text = "Note that this parameter seems to be ignore by MG.\n" 5470 text += "MG will use instead the expression: %s\n" % \ 5471 self.restricted_value[(args[start], key)] 5472 text += "You need to match this expression for external program (such pythia)." 5473 logger.warning(text) 5474 5475 if args[-1].lower() in ['default', 'auto', 'auto@nlo'] or args[-1].startswith('scan'): 5476 self.setP(args[start], key, args[-1]) 5477 else: 5478 try: 5479 value = float(args[-1]) 5480 except Exception: 5481 logger.warning('Invalid input: Expected number and not \'%s\'' \ 5482 % args[-1]) 5483 return 5484 self.setP(args[start], key, value) 5485 else: 5486 logger.warning('invalid set command %s' % line) 5487 return 5488 self.modified_card.add('param') 5489 5490 # PARAM_CARD NO BLOCK NAME --------------------------------------------- 5491 elif args[start] in self.pname2block and card in ['','param_card']: 5492 if args[start] in self.conflict and card == '': 5493 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5494 text += ' in the format < set card parameter value>' 5495 logger.warning(text) 5496 return 5497 5498 all_var = self.pname2block[args[start]] 5499 for bname, lhaid in all_var: 5500 new_line = 'param_card %s %s %s' % (bname, 5501 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:])) 5502 self.do_set(new_line) 5503 if len(all_var) > 1: 5504 logger.warning('This variable correspond to more than one parameter in the param_card.') 5505 for bname, lhaid in all_var: 5506 logger.warning(' %s %s' % (bname, ' '.join([str(i) for i in lhaid]))) 5507 logger.warning('all listed variables have been modified') 5508 5509 # MadWeight_card with block name --------------------------------------- 5510 elif self.has_mw and (args[start] in self.mw_card and args[start] != 'comment') \ 5511 and card in ['','MadWeight_card']: 5512 5513 if args[start] in self.conflict and card == '': 5514 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5515 text += ' in the format < set card parameter value>' 5516 logger.warning(text) 5517 return 5518 5519 block = args[start] 5520 name = args[start+1] 5521 value = args[start+2:] 5522 self.setM(block, name, value) 5523 self.mw_card.write(self.paths['MadWeight']) 5524 5525 # MadWeight_card NO Block name ----------------------------------------- 5526 elif self.has_mw and args[start] in self.mw_vars \ 5527 and card in ['', 'MadWeight_card']: 5528 5529 if args[start] in self.conflict and card == '': 5530 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5531 text += ' in the format < set card parameter value>' 5532 logger.warning(text) 5533 return 5534 5535 block = [b for b, data in self.mw_card.items() if args[start] in data] 5536 if len(block) > 1: 5537 logger.warning('%s is define in more than one block: %s.Please specify.' 5538 % (args[start], ','.join(block))) 5539 return 5540 5541 block = block[0] 5542 name = args[start] 5543 value = args[start+1:] 5544 self.setM(block, name, value) 5545 self.mw_card.write(self.paths['MadWeight']) 5546 5547 # MadWeight_card New Block --------------------------------------------- 5548 elif self.has_mw and args[start].startswith('mw_') and len(args[start:]) == 3\ 5549 and card == 'MadWeight_card': 5550 block = args[start] 5551 name = args[start+1] 5552 value = args[start+2] 5553 self.setM(block, name, value) 5554 self.mw_card.write(self.paths['MadWeight']) 5555 5556 #### SHOWER CARD 5557 elif self.has_shower and args[start].lower() in [l.lower() for l in \ 5558 self.shower_card.keys()] and card in ['', 'shower_card']: 5559 if args[start] not in self.shower_card: 5560 args[start] = [l for l in self.shower_card if l.lower() == args[start].lower()][0] 5561 5562 if args[start] in self.conflict and card == '': 5563 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5564 text += ' in the format < set card parameter value>' 5565 logger.warning(text) 5566 return 5567 5568 if args[start+1].lower() == 'default': 5569 default = shower_card_mod.ShowerCard(self.paths['shower_default']) 5570 if args[start] in default.keys(): 5571 self.shower_card.set_param(args[start],default[args[start]], self.paths['shower']) 5572 else: 5573 logger.info('remove information %s from the shower_card' % args[start],'$MG:BOLD') 5574 del self.shower_card[args[start]] 5575 elif args[start+1].lower() in ['t','.true.','true']: 5576 self.shower_card.set_param(args[start],'.true.',self.paths['shower']) 5577 elif args[start+1].lower() in ['f','.false.','false']: 5578 self.shower_card.set_param(args[start],'.false.',self.paths['shower']) 5579 elif args[start] in ['analyse', 'extralibs', 'extrapaths', 'includepaths'] or\ 5580 args[start].startswith('dm_'): 5581 #case sensitive parameters 5582 args = line.split() 5583 args_str = ' '.join(str(a) for a in args[start+1:len(args)]) 5584 self.shower_card.set_param(args[start],args_str,pjoin(self.me_dir,'Cards','shower_card.dat')) 5585 else: 5586 args_str = ' '.join(str(a) for a in args[start+1:len(args)]) 5587 self.shower_card.set_param(args[start],args_str,self.paths['shower']) 5588 5589 # MadLoop Parameter --------------------------------------------------- 5590 elif self.has_ml and args[start] in self.ml_vars \ 5591 and card in ['', 'MadLoop_card']: 5592 5593 if args[start] in self.conflict and card == '': 5594 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5595 logger.warning(text) 5596 return 5597 5598 if args[start+1] == 'default': 5599 value = self.MLcardDefault[args[start]] 5600 default = True 5601 else: 5602 value = args[start+1] 5603 default = False 5604 self.setML(args[start], value, default=default) 5605 self.MLcard.write(self.paths['ML'], 5606 commentdefault=True) 5607 5608 # Pythia8 Parameter --------------------------------------------------- 5609 elif self.has_PY8 and (card == 'pythia8_card' or (card == '' and \ 5610 args[start] in self.PY8Card)): 5611 5612 if args[start] in self.conflict and card == '': 5613 text = 'ambiguous name (present in more than one card). Please specify which card to edit' 5614 logger.warning(text) 5615 return 5616 5617 if args[start+1] == 'default': 5618 value = self.PY8CardDefault[args[start]] 5619 default = True 5620 else: 5621 value = ' '.join(args[start+1:]) 5622 default = False 5623 self.setPY8(args[start], value, default=default) 5624 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'), 5625 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 5626 print_only_visible=True) 5627 5628 #INVALID -------------------------------------------------------------- 5629 else: 5630 logger.warning('invalid set command %s ' % line) 5631 arg = args[start].lower() 5632 if self.has_PY8: 5633 close_opts = [name for name in self.PY8Card if name.lower().startswith(arg[:3]) or arg in name.lower()] 5634 if close_opts: 5635 logger.info('Did you mean one of the following PY8 options:\n%s' % '\t'.join(close_opts)) 5636 if self.run_card: 5637 close_opts = [name for name in self.run_card if name.lower().startswith(arg[:3]) or arg in name.lower()] 5638 if close_opts: 5639 logger.info('Did you mean one of the following run_card options:\n%s' % '\t'.join(close_opts)) 5640 5641 return
5642
5643 - def setM(self, block, name, value):
5644 5645 if isinstance(value, list) and len(value) == 1: 5646 value = value[0] 5647 5648 if block not in self.mw_card: 5649 logger.warning('block %s was not present in the current MadWeight card. We are adding it' % block) 5650 self.mw_card[block] = {} 5651 elif name not in self.mw_card[block]: 5652 logger.info('name %s was not present in the block %s for the current MadWeight card. We are adding it' % (name,block),'$MG:BOLD') 5653 if value == 'default': 5654 import madgraph.madweight.Cards as mwcards 5655 mw_default = mwcards.Card(self.paths['MadWeight_default']) 5656 try: 5657 value = mw_default[block][name] 5658 except KeyError: 5659 logger.info('removing id "%s" from Block "%s" '% (name, block),'$MG:BOLD') 5660 if name in self.mw_card[block]: 5661 del self.mw_card[block][name] 5662 return 5663 if value: 5664 logger.info('modify madweight_card information BLOCK "%s" with id "%s" set to %s', 5665 block, name, value, '$MG:BOLD') 5666 else: 5667 logger.warning("Invalid command: No value. To set default value. Use \"default\" as value") 5668 return 5669 5670 self.mw_card[block][name] = value
5671
5672 - def setR(self, name, value):
5673 5674 if self.mother_interface.inputfile: 5675 self.run_card.set(name, value, user=True, raiseerror=True) 5676 else: 5677 self.run_card.set(name, value, user=True) 5678 new_value = self.run_card.get(name) 5679 logger.info('modify parameter %s of the run_card.dat to %s' % (name, new_value),'$MG:BOLD')
5680 5681
5682 - def setML(self, name, value, default=False):
5683 5684 try: 5685 self.MLcard.set(name, value, user=True) 5686 except Exception, error: 5687 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error) 5688 return 5689 logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value),'$MG:BOLD') 5690 if default and name.lower() in self.MLcard.user_set: 5691 self.MLcard.user_set.remove(name.lower())
5692
5693 - def setPY8(self, name, value, default=False):
5694 try: 5695 self.PY8Card.userSet(name, value) 5696 except Exception, error: 5697 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error) 5698 return 5699 logger.info('modify parameter %s of the pythia8_card.dat to %s' % (name, value), '$MG:BOLD') 5700 if default and name.lower() in self.PY8Card.user_set: 5701 self.PY8Card.user_set.remove(name.lower())
5702
5703 - def setP(self, block, lhaid, value):
5704 if isinstance(value, str): 5705 value = value.lower() 5706 if value == 'default': 5707 default = param_card_mod.ParamCard(self.paths['param_default']) 5708 value = default[block].param_dict[lhaid].value 5709 5710 elif value in ['auto', 'auto@nlo']: 5711 if 'nlo' in value: 5712 value = 'Auto@NLO' 5713 else: 5714 value = 'Auto' 5715 if block != 'decay': 5716 logger.warning('Invalid input: \'Auto\' value only valid for DECAY') 5717 return 5718 elif value.startswith('scan'): 5719 if ':' not in value: 5720 logger.warning('Invalid input: \'scan\' mode requires a \':\' before the definition.') 5721 return 5722 tag = value.split(':')[0] 5723 tag = tag[4:].strip() 5724 if tag and not tag.isdigit(): 5725 logger.warning('Invalid input: scan tag need to be integer and not "%s"' % tag) 5726 return 5727 5728 5729 pass 5730 else: 5731 try: 5732 value = float(value) 5733 except ValueError: 5734 logger.warning('Invalid input: \'%s\' not valid intput.'% value) 5735 5736 logger.info('modify param_card information BLOCK %s with id %s set to %s' %\ 5737 (block, lhaid, value), '$MG:BOLD') 5738 self.param_card[block].param_dict[lhaid].value = value
5739
5740 - def check_card_consistency(self):
5741 """This is run on quitting the class. Apply here all the self-consistency 5742 rule that you want. Do the modification via the set command.""" 5743 5744 ######################################################################## 5745 # LO specific check 5746 ######################################################################## 5747 if isinstance(self.run_card,banner_mod.RunCardLO): 5748 5749 proc_charac = self.mother_interface.proc_characteristics 5750 if proc_charac['grouped_matrix'] and \ 5751 abs(self.run_card['lpp1']) == 1 == abs(self.run_card['lpp2']) and \ 5752 (self.run_card['nb_proton1'] != self.run_card['nb_proton2'] or 5753 self.run_card['nb_neutron1'] != self.run_card['nb_neutron2'] or 5754 self.run_card['mass_ion1'] != self.run_card['mass_ion2']): 5755 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\"." 5756 5757 # check the status of small width status from LO 5758 for param in self.param_card['decay']: 5759 width = param.value 5760 if width == 0 or isinstance(width,str): 5761 continue 5762 try: 5763 mass = self.param_card['mass'].get(param.lhacode).value 5764 except Exception: 5765 continue 5766 if isinstance(mass,str): 5767 continue 5768 5769 if mass: 5770 if abs(width/mass) < self.run_card['small_width_treatment']: 5771 logger.warning("Particle %s will use a fake width ( %s instead of %s ).\n" + 5772 "Cross-section will be rescaled according to NWA if needed." + 5773 "To force exact treatment reduce the value of 'small_width_treatment' parameter of the run_card", 5774 param.lhacode[0], abs(mass*self.run_card['small_width_treatment']), width) 5775 elif abs(width/mass) < 1e-12: 5776 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) 5777 if CommonRunCmd.sleep_for_error: 5778 time.sleep(5) 5779 CommonRunCmd.sleep_for_error = False 5780 5781 5782 ######################################################################## 5783 # NLO specific check 5784 ######################################################################## 5785 # For NLO run forbid any pdg specific cut on massless particle 5786 if isinstance(self.run_card,banner_mod.RunCardNLO): 5787 for pdg in set(self.run_card['pt_min_pdg'].keys()+self.run_card['pt_max_pdg'].keys()+ 5788 self.run_card['mxx_min_pdg'].keys()): 5789 5790 if int(pdg)<0: 5791 raise Exception, "For PDG specific cuts, always use positive PDG codes: the cuts are applied to both particles and anti-particles" 5792 if self.param_card.get_value('mass', int(pdg), default=0) ==0: 5793 raise Exception, "For NLO runs, you can use PDG specific cuts only for massive particles: (failed for %s)" % pdg 5794 5795 # if NLO reweighting is ON: ensure that we keep the rwgt information 5796 if 'reweight' in self.allow_arg and 'run' in self.allow_arg and \ 5797 isinstance(self.run_card,banner_mod.RunCardNLO) and \ 5798 not self.run_card['store_rwgt_info']: 5799 #check if a NLO reweighting is required 5800 re_pattern = re.compile(r'''^\s*change\s*mode\s* (LO\+NLO|LO|NLO|NLO_tree)\s*(?:#|$)''', re.M+re.I) 5801 text = open(self.paths['reweight']).read() 5802 options = re_pattern.findall(text) 5803 if any(o in ['NLO', 'LO+NLO'] for o in options): 5804 logger.info('NLO reweighting is on ON. Automatically set store_rwgt_info to True', '$MG:BOLD' ) 5805 self.do_set('run_card store_rwgt_info True') 5806 5807 # if external computation for the systematics are asked then switch 5808 #automatically the book-keeping of the weight for NLO 5809 if 'run' in self.allow_arg and \ 5810 self.run_card['systematics_program'] == 'systematics' and \ 5811 isinstance(self.run_card,banner_mod.RunCardNLO) and \ 5812 not self.run_card['store_rwgt_info']: 5813 logger.warning('To be able to run systematics program, we set store_rwgt_info to True') 5814 self.do_set('run_card store_rwgt_info True') 5815 5816 # @LO if PY6 shower => event_norm on sum 5817 if 'pythia_card.dat' in self.cards and 'run' in self.allow_arg: 5818 if self.run_card['event_norm'] != 'sum': 5819 logger.info('Pythia6 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' ) 5820 self.do_set('run_card event_norm sum') 5821 # @LO if PY6 shower => event_norm on sum 5822 elif 'pythia8_card.dat' in self.cards: 5823 if self.run_card['event_norm'] == 'sum': 5824 logger.info('Pythia8 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' ) 5825 self.do_set('run_card event_norm average') 5826 5827 # Check the extralibs flag. 5828 if self.has_shower and isinstance(self.run_card, banner_mod.RunCardNLO): 5829 modify_extralibs, modify_extrapaths = False,False 5830 extralibs = self.shower_card['extralibs'].split() 5831 extrapaths = self.shower_card['extrapaths'].split() 5832 # remove default stdhep/Fmcfio for recent shower 5833 if self.run_card['parton_shower'] in ['PYTHIA8', 'HERWIGPP', 'HW7']: 5834 if 'stdhep' in self.shower_card['extralibs']: 5835 extralibs.remove('stdhep') 5836 modify_extralibs = True 5837 if 'Fmcfio' in self.shower_card['extralibs']: 5838 extralibs.remove('Fmcfio') 5839 modify_extralibs = True 5840 if self.run_card['parton_shower'] == 'PYTHIA8': 5841 # First check sanity of PY8 5842 if not self.mother_interface.options['pythia8_path']: 5843 raise self.mother_interface.InvalidCmd, 'Pythia8 is not correctly specified to MadGraph5_aMC@NLO' 5844 executable = pjoin(self.mother_interface.options['pythia8_path'], 'bin', 'pythia8-config') 5845 if not os.path.exists(executable): 5846 raise self.mother.InvalidCmd, 'Pythia8 is not correctly specified to MadGraph5_aMC@NLO' 5847 5848 # 2. take the compilation flag of PY8 from pythia8-config 5849 libs , paths = [], [] 5850 p = misc.subprocess.Popen([executable, '--libs'], stdout=subprocess.PIPE) 5851 stdout, _ = p. communicate() 5852 libs = [x[2:] for x in stdout.split() if x.startswith('-l') or paths.append(x[2:])] 5853 5854 # Add additional user-defined compilation flags 5855 p = misc.subprocess.Popen([executable, '--config'], stdout=subprocess.PIPE) 5856 stdout, _ = p. communicate() 5857 for lib in ['-ldl','-lstdc++','-lc++']: 5858 if lib in stdout: 5859 libs.append(lib[2:]) 5860 5861 # This precompiler flag is in principle useful for the analysis if it writes HEPMC 5862 # events, but there is unfortunately no way for now to specify it in the shower_card. 5863 supports_HEPMCHACK = '-DHEPMC2HACK' in stdout 5864 5865 #3. ensure that those flag are in the shower card 5866 for L in paths: 5867 if L not in extrapaths: 5868 modify_extrapaths = True 5869 extrapaths.append(L) 5870 for l in libs: 5871 if l == 'boost_iostreams': 5872 #this one is problematic handles it. 5873 for L in paths + extrapaths: 5874 if misc.glob('*boost_iostreams*', L): 5875 break 5876 else: 5877 continue 5878 if l not in extralibs: 5879 modify_extralibs = True 5880 extralibs.append(l) 5881 # Apply the required modification 5882 if modify_extralibs: 5883 if extralibs: 5884 self.do_set('shower_card extralibs %s ' % ' '.join(extralibs)) 5885 else: 5886 self.do_set('shower_card extralibs None ') 5887 if modify_extrapaths: 5888 if extrapaths: 5889 self.do_set('shower_card extrapaths %s ' % ' '.join(extrapaths)) 5890 else: 5891 self.do_set('shower_card extrapaths None ') 5892 5893 # ensure that all cards are in sync 5894 for key in list(self.modified_card): 5895 self.write_card(key)
5896 5897
5898 - def reask(self, *args, **opt):
5899 5900 cmd.OneLinePathCompletion.reask(self,*args, **opt) 5901 if self.has_mw and not os.path.exists(pjoin(self.me_dir,'Cards','transfer_card.dat')): 5902 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
5903 5904 fail_due_to_format = 0 #parameter to avoid infinite loop
5905 - def postcmd(self, stop, line):
5906 5907 if line not in [None, '0', 'done', '']: 5908 ending_question = cmd.OneLinePathCompletion.postcmd(self,stop,line) 5909 else: 5910 ending_question = True 5911 5912 if ending_question: 5913 self.check_card_consistency() 5914 if self.param_consistency: 5915 try: 5916 self.do_update('dependent', timer=20) 5917 except MadGraph5Error, error: 5918 if 'Missing block:' in str(error): 5919 self.fail_due_to_format +=1 5920 if self.fail_due_to_format == 10: 5921 missing, unknow = str(error).split('\n')[-2:] 5922 logger.warning("Invalid param_card:\n%s\n%s\n" % (missing, unknow)) 5923 logger.info("Type \"update missing\" to use default value.\n ", '$MG:BOLD') 5924 self.value = False # to avoid that entering a command stop the question 5925 return self.reask(True) 5926 else: 5927 raise 5928 5929 return ending_question
5930 5931 5932 5933 5934
5935 - def do_update(self, line, timer=0):
5936 """ syntax: update dependent: Change the mass/width of particles which are not free parameter for the model. 5937 update missing: add to the current param_card missing blocks/parameters. 5938 update to_slha1: pass SLHA2 card to SLHA1 convention. (beta) 5939 update to_slha2: pass SLHA1 card to SLHA2 convention. (beta) 5940 update to_full [run_card] 5941 update XXX [where XXX correspond to a hidden block of the run_card] 5942 """ 5943 args = self.split_arg(line) 5944 if len(args)==0: 5945 logger.warning('miss an argument (dependent or missing). Please retry') 5946 return 5947 5948 if args[0] == 'dependent': 5949 if not self.mother_interface: 5950 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)') 5951 5952 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I) 5953 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M) 5954 param_text= open(self.paths['param']).read() 5955 5956 if pattern_scan.search(param_text): 5957 #for block, key in self.restricted_value: 5958 # self.param_card[block].get(key).value = -9.999e-99 5959 # self.param_card.write(self.paths['param']) 5960 return 5961 elif pattern_width.search(param_text): 5962 self.do_compute_widths('') 5963 self.param_card = param_card_mod.ParamCard(self.paths['param']) 5964 5965 # calling the routine doing the work 5966 self.update_dependent(self.mother_interface, self.me_dir, self.param_card, 5967 self.paths['param'], timer) 5968 5969 elif args[0] == 'missing': 5970 self.update_missing() 5971 return 5972 5973 elif args[0] == 'to_slha2': 5974 try: 5975 param_card_mod.convert_to_mg5card(self.paths['param']) 5976 logger.info('card updated') 5977 except Exception, error: 5978 logger.warning('failed to update to slha2 due to %s' % error) 5979 self.param_card = param_card_mod.ParamCard(self.paths['param']) 5980 elif args[0] == 'to_slha1': 5981 try: 5982 param_card_mod.convert_to_slha1(self.paths['param']) 5983 logger.info('card updated') 5984 except Exception, error: 5985 logger.warning('failed to update to slha1 due to %s' % error) 5986 self.param_card = param_card_mod.ParamCard(self.paths['param']) 5987 elif args[0] == 'to_full': 5988 return self.update_to_full(args[1:]) 5989 elif args[0] in self.update_block: 5990 self.run_card.display_block.append(args[0].lower()) 5991 self.modified_card.add('run') # delay writting of the run_card 5992 logger.info('add optional block %s to the run_card', args[0]) 5993 else: 5994 self.help_update() 5995 logger.warning('unvalid options for update command. Please retry')
5996 5997
5998 - def update_to_full(self, line):
5999 """ trigger via update to_full LINE""" 6000 6001 logger.info("update the run_card by including all the hidden parameter") 6002 self.run_card.write(self.paths['run'], self.paths['run_default'], write_hidden=True) 6003 if 'run' in self.modified_card: 6004 self.modified_card.remove('run')
6005
6006 - def write_card(self, name):
6007 """proxy on how to write any card""" 6008 6009 if hasattr(self, 'write_card_%s' % name): 6010 getattr(self, 'write_card_%s' % name)() 6011 if name in self.modified_card: 6012 self.modified_card.remove(name) 6013 else: 6014 raise Exception, "Need to add the associate writter proxy"
6015
6016 - def write_card_run(self):
6017 """ write the run_card """ 6018 self.run_card.write(self.paths['run'], self.paths['run_default'])
6019
6020 - def write_card_param(self):
6021 """ write the param_card """ 6022 self.param_card.write(self.paths['param'])
6023 6024 @staticmethod
6025 - def update_dependent(mecmd, me_dir, param_card, path ,timer=0):
6026 """static method which can also be called from outside the class 6027 usefull in presence of scan. 6028 return if the param_card was updated or not 6029 """ 6030 6031 if not param_card: 6032 return False 6033 6034 logger.info('Update the dependent parameter of the param_card.dat') 6035 modify = True 6036 class TimeOutError(Exception): 6037 pass
6038 def handle_alarm(signum, frame): 6039 raise TimeOutError 6040 signal.signal(signal.SIGALRM, handle_alarm) 6041 if timer: 6042 signal.alarm(timer) 6043 log_level=30 6044 else: 6045 log_level=20 6046 # Try to load the model in the limited amount of time allowed 6047 try: 6048 model = mecmd.get_model() 6049 signal.alarm(0) 6050 except TimeOutError: 6051 logger.warning('The model takes too long to load so we bypass the updating of dependent parameter.\n'+\ 6052 'This might create trouble for external program (like MadSpin/shower/...)\n'+\ 6053 'The update can be forced without timer by typing \'update dependent\' at the time of the card edition') 6054 modify =False 6055 except Exception,error: 6056 logger.debug(str(error)) 6057 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)') 6058 signal.alarm(0) 6059 else: 6060 restrict_card = pjoin(me_dir,'Source','MODEL','param_card_rule.dat') 6061 if not os.path.exists(restrict_card): 6062 restrict_card = None 6063 #restrict_card = None 6064 if model: 6065 modify = param_card.update_dependent(model, restrict_card, log_level) 6066 if modify and path: 6067 param_card.write(path) 6068 else: 6069 logger.warning('missing MG5aMC code. Fail to update dependent parameter. This might create trouble for program like MadSpin/shower/...') 6070 6071 if log_level==20: 6072 logger.info('param_card up to date.') 6073 6074 return modify 6075 6076 6077
6078 - def update_missing(self):
6079 6080 def check_block(self, blockname): 6081 add_entry = 0 6082 if blockname.lower() not in self.param_card_default: 6083 logger.info('unknow block %s: block will be ignored', blockname) 6084 return add_entry 6085 block = self.param_card_default[blockname] 6086 for key in block.keys(): 6087 if key not in input_in_block: 6088 param = block.get(key) 6089 if blockname != 'decay': 6090 text.append('\t%s\t%s # %s\n' % (' \t'.join([`i` for i in param.lhacode]), param.value, param.comment)) 6091 else: 6092 text.append('DECAY \t%s\t%s # %s\n' % (' \t'.join([`i` for i in param.lhacode]), param.value, param.comment)) 6093 add_entry += 1 6094 if add_entry: 6095 text.append('\n') 6096 if add_entry: 6097 logger.info("Adding %s parameter(s) to block %s", add_entry, blockname) 6098 return add_entry
6099 6100 # Add to the current param_card all the missing input at default value 6101 current_block = '' 6102 input_in_block = set() 6103 defined_blocks = set() 6104 decay = set() 6105 text = [] 6106 add_entry = 0 6107 for line in open(self.paths['param']): 6108 6109 new_block = re.findall(r'^\s*(block|decay)\s*(\w*)', line, re.I) 6110 if new_block: 6111 new_block = new_block[0] 6112 defined_blocks.add(new_block[1].lower()) 6113 if current_block: 6114 add_entry += check_block(self, current_block) 6115 6116 current_block= new_block[1] 6117 input_in_block = set() 6118 if new_block[0].lower() == 'decay': 6119 decay.add((int(new_block[1]),)) 6120 current_block = '' 6121 if new_block[1].lower() == 'qnumbers': 6122 current_block = '' 6123 6124 text.append(line) 6125 if not current_block: 6126 continue 6127 6128 #normal line. 6129 #strip comment 6130 line = line.split('#',1)[0] 6131 split = line.split() 6132 if not split: 6133 continue 6134 else: 6135 try: 6136 lhacode = [int(i) for i in split[:-1]] 6137 except: 6138 continue 6139 input_in_block.add(tuple(lhacode)) 6140 6141 if current_block: 6142 add_entry += check_block(self, current_block) 6143 6144 # special check for missing block 6145 for block in self.param_card_default: 6146 6147 if block.startswith(('qnumbers', 'decay')): 6148 continue 6149 6150 if block not in defined_blocks: 6151 nb_entry = len(self.param_card_default[block]) 6152 logger.info("Block %s was missing. Adding the %s associated parameter(s)", block,nb_entry) 6153 add_entry += nb_entry 6154 text.append(str(self.param_card_default[block])) 6155 6156 # special check for the decay 6157 input_in_block = decay 6158 add_entry += check_block(self, 'decay') 6159 6160 if add_entry: 6161 logger.info('write new param_card with %s new parameter(s).', add_entry, '$MG:BOLD') 6162 open(self.paths['param'],'w').write(''.join(text)) 6163 self.reload_card(self.paths['param']) 6164 else: 6165 logger.info('No missing parameter detected.', '$MG:BOLD') 6166 6167
6168 - def check_answer_consistency(self):
6169 """function called if the code reads a file""" 6170 self.check_card_consistency() 6171 self.do_update('dependent', timer=20)
6172
6173 - def help_set(self):
6174 '''help message for set''' 6175 6176 logger.info('********************* HELP SET ***************************') 6177 logger.info("syntax: set [run_card|param_card|...] NAME [VALUE|default]") 6178 logger.info("syntax: set [param_card] BLOCK ID(s) [VALUE|default]") 6179 logger.info('') 6180 logger.info('-- Edit the param_card/run_card/... and replace the value of the') 6181 logger.info(' parameter by the value VALUE.') 6182 logger.info(' ') 6183 logger.info('-- Example:') 6184 logger.info(' set run_card ebeam1 4000') 6185 logger.info(' set ebeam2 4000') 6186 logger.info(' set lpp1 0') 6187 logger.info(' set ptj default') 6188 logger.info('') 6189 logger.info(' set param_card mass 6 175') 6190 logger.info(' set mass 25 125.3') 6191 logger.info(' set mass mh 125') 6192 logger.info(' set mh 125') 6193 logger.info(' set decay 25 0.004') 6194 logger.info(' set decay wh 0.004') 6195 logger.info(' set vmix 2 1 2.326612e-01') 6196 logger.info('') 6197 logger.info(' set param_card default #return all parameter to default') 6198 logger.info(' set run_card default') 6199 logger.info('********************* HELP SET ***************************')
6200
6201 - def trigger(self, line):
6202 6203 line = line.strip() 6204 args = line.split() 6205 6206 if not args: 6207 return line 6208 if not hasattr(self, 'trigger_%s' % args[0]): 6209 return line 6210 6211 triggerfct = getattr(self, 'trigger_%s' % args[0]) 6212 6213 # run the trigger function 6214 outline = triggerfct(' '.join(args[1:])) 6215 if not outline: 6216 return 'repeat' 6217 return outline
6218
6219 - def default(self, line):
6220 """Default action if line is not recognized""" 6221 6222 # check if the line need to be modified by a trigger 6223 line = self.trigger(line) 6224 6225 # splitting the line 6226 line = line.strip() 6227 args = line.split() 6228 if line == '' and self.default_value is not None: 6229 self.value = self.default_value 6230 # check if input is a file 6231 elif hasattr(self, 'do_%s' % args[0]): 6232 self.do_set(' '.join(args[1:])) 6233 elif line.strip() != '0' and line.strip() != 'done' and \ 6234 str(line) != 'EOF' and line.strip() in self.allow_arg: 6235 self.open_file(line) 6236 self.value = 'repeat' 6237 elif os.path.isfile(line): 6238 self.copy_file(line) 6239 self.value = 'repeat' 6240 elif self.me_dir and os.path.exists(pjoin(self.me_dir, line)): 6241 self.copy_file(pjoin(self.me_dir,line)) 6242 self.value = 'repeat' 6243 elif line.strip().startswith(('http:','www', 'https')): 6244 self.value = 'repeat' 6245 import tempfile 6246 fsock, path = tempfile.mkstemp() 6247 try: 6248 text = urllib.urlopen(line.strip()) 6249 url = line.strip() 6250 except Exception: 6251 logger.error('fail to load the file') 6252 else: 6253 for line in text: 6254 os.write(fsock, line) 6255 os.close(fsock) 6256 self.copy_file(path, pathname=url) 6257 os.remove(path) 6258 6259 6260 else: 6261 self.value = line 6262 6263 return line
6264 6265
6266 - def do_decay(self, line):
6267 """edit the madspin_card to define the decay of the associate particle""" 6268 signal.alarm(0) # avoid timer if any 6269 path = self.paths['madspin'] 6270 6271 if 'madspin_card.dat' not in self.cards or not os.path.exists(path): 6272 logger.warning("Command decay not valid. Since MadSpin is not available.") 6273 return 6274 6275 if ">" not in line: 6276 logger.warning("invalid command for decay. Line ignored") 6277 return 6278 6279 if "-add" in line: 6280 # just to have to add the line to the end of the file 6281 particle = line.split('>')[0].strip() 6282 text = open(path).read() 6283 line = line.replace('--add', '').replace('-add','') 6284 logger.info("change madspin_card to add one decay to %s: %s" %(particle, line.strip()), '$MG:BOLD') 6285 if 'launch' in text: 6286 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1) 6287 else: 6288 text += '\ndecay %s\n launch \n' % line 6289 else: 6290 # Here we have to remove all the previous definition of the decay 6291 #first find the particle 6292 particle = line.split('>')[0].strip() 6293 logger.info("change madspin_card to define the decay of %s: %s" %(particle, line.strip()), '$MG:BOLD') 6294 particle = particle.replace('+','\+').replace('-','\-') 6295 decay_pattern = re.compile(r"^\s*decay\s+%s\s*>[\s\w+-~]*?$" % particle, re.I+re.M) 6296 text= open(path).read() 6297 text = decay_pattern.sub('', text) 6298 if 'launch' in text: 6299 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1) 6300 else: 6301 text += '\ndecay %s\n launch \n' % line 6302 6303 with open(path,'w') as fsock: 6304 fsock.write(text) 6305 self.reload_card(path)
6306 6307 6308
6309 - def do_compute_widths(self, line):
6310 signal.alarm(0) # avoid timer if any 6311 6312 # ensure that the card is in sync 6313 if 'param' in self.modified_card: 6314 self.write_card('param') 6315 self.modified_card.discard('param') 6316 6317 path = self.paths['param'] 6318 pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I) 6319 text = open(path).read() 6320 pdg_info = pattern.findall(text) 6321 has_nlo = any("@nlo"==nlo.lower() for _, nlo in pdg_info) 6322 pdg = [p for p,_ in pdg_info] 6323 6324 6325 line = '%s %s' % (line, ' '.join(pdg)) 6326 if not '--path' in line: 6327 line += ' --path=%s' % path 6328 if has_nlo: 6329 line += ' --nlo' 6330 6331 try: 6332 return self.mother_interface.do_compute_widths(line) 6333 except InvalidCmd, error: 6334 logger.error("Invalid command: %s " % error)
6335
6336 - def help_compute_widths(self):
6337 signal.alarm(0) # avoid timer if any 6338 return self.mother_interface.help_compute_widths()
6339
6340 - def help_decay(self):
6341 """help for command decay which modifies MadSpin_card""" 6342 6343 signal.alarm(0) # avoid timer if any 6344 print '--syntax: decay PROC [--add]' 6345 print ' ' 6346 print ' modify the madspin_card to modify the decay of the associate particle.' 6347 print ' and define it to PROC.' 6348 print ' if --add is present, just add a new decay for the associate particle.'
6349
6350 - def complete_compute_widths(self, text, line, begidx, endidx, **opts):
6351 prev_timer = signal.alarm(0) # avoid timer if any 6352 if prev_timer: 6353 nb_back = len(line) 6354 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 6355 self.stdout.write(line) 6356 self.stdout.flush() 6357 return self.mother_interface.complete_compute_widths(text, line, begidx, endidx,**opts)
6358 6359
6360 - def help_add(self):
6361 """help for add command""" 6362 6363 logger.info('********************* HELP ADD ***************************') 6364 logger.info( '-- syntax: add pythia8_card NAME VALUE') 6365 logger.info( " add a definition of name in the pythia8_card with the given value") 6366 logger.info( " Do not work for the param_card" ) 6367 logger.info('') 6368 return self.help_edit(prefix=False)
6369
6370 - def help_edit(self, prefix=True):
6371 """help for edit command""" 6372 6373 if prefix: logger.info('********************* HELP ADD|EDIT ***************************') 6374 logger.info( '-- syntax: add filename [OPTION] LINE') 6375 logger.info( '-- syntax: edit filename [OPTION] LINE') 6376 logger.info( ' add the given LINE to the end of the associate file (all file supported).') 6377 logger.info( '') 6378 logger.info( ' OPTION parameter allows to change the position where to write in the file') 6379 logger.info( ' --after_line=banner : write the line at the end of the banner') 6380 logger.info( ' --line_position=X : insert the line before line X (starts at 0)') 6381 logger.info( ' --line_position=afterlast : insert the line after the latest inserted/modified line.') 6382 logger.info( ' --after_line="<regular-expression>" write the line after the first line matching the regular expression') 6383 logger.info( ' --before_line="<regular-expression>" write the line before the first line matching the regular expression') 6384 logger.info( ' --replace_line="<regular-expression>" replace the line matching the regular expression') 6385 logger.info( ' --clean remove all previously existing line in the file') 6386 logger.info('') 6387 logger.info(' Note: all regular-expression will be prefixed by ^\s*') 6388 logger.info('') 6389 logger.info( ' example: edit reweight --after_line="change mode\b" change model heft') 6390 logger.info( ' edit madspin --after_line="banner" change model XXXX') 6391 logger.info('********************* HELP ADD|EDIT ***************************')
6392 6393
6394 - def complete_add(self, text, line, begidx, endidx, formatting=True):
6395 """ auto-completion for add command""" 6396 6397 prev_timer = signal.alarm(0) # avoid timer if any 6398 if prev_timer: 6399 nb_back = len(line) 6400 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 6401 self.stdout.write(line) 6402 self.stdout.flush() 6403 6404 split = line[:begidx].split() 6405 if len(split)==1: 6406 possibilities = {} 6407 cards = [c.rsplit('.',1)[0] for c in self.cards] 6408 possibilities['category of parameter (optional)'] = \ 6409 self.list_completion(text, cards) 6410 elif len(split) == 2: 6411 possibilities = {} 6412 options = ['--line_position=','--line_position=afterlast','--after_line=banner', '--after_line="','--before_line="'] 6413 possibilities['category of parameter (optional)'] = \ 6414 self.list_completion(text, options, line) 6415 else: 6416 return 6417 return self.deal_multiple_categories(possibilities, formatting)
6418
6419 - def do_add(self, line):
6420 """ syntax: add filename NAME VALUE 6421 syntax: add filename LINE""" 6422 6423 args = self.split_arg(line) 6424 if len(args) == 3 and args[0] in ['pythia8_card', 'pythia8_card.dat'] and self.has_PY8: 6425 name= args[1] 6426 value = args[2] 6427 self.PY8Card.userSet(name, value) 6428 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'), 6429 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'), 6430 print_only_visible=True) 6431 logger.info("add in the pythia8_card the parameter \"%s\" with value \"%s\"" % (name, value), '$MG:BOLD') 6432 elif len(args) > 0: 6433 if args[0] in self.cards: 6434 card = args[0] 6435 elif "%s.dat" % args[0] in self.cards: 6436 card = "%s.dat" % args[0] 6437 elif "%s_card.dat" % args[0] in self.cards: 6438 card = "%s_card.dat" % args[0] 6439 elif self.has_ml and args[0].lower() == "madloop": 6440 card = "MadLoopParams.dat" 6441 else: 6442 logger.error("unknow card %s. Please retry." % args[0]) 6443 return 6444 # ensure that the card is in sync 6445 if card in self.modified_card: 6446 self.write_card(card) 6447 self.modified_card.discard(card) 6448 6449 if card in self.paths: 6450 path = self.paths[card] 6451 elif os.path.exists(card): 6452 path = card 6453 elif os.path.exists(pjoin(self.me_dir,'Cards',card)): 6454 path = pjoin(self.me_dir,'Cards',card) 6455 else: 6456 raise Exception, 'unknow path' 6457 6458 # handling the various option on where to write the line 6459 if args[1] == '--clean': 6460 ff = open(path,'w') 6461 ff.write("# %s \n" % card) 6462 ff.write("%s \n" % line.split(None,2)[2]) 6463 ff.close() 6464 logger.info("writing the line in %s (empty file) the line: \"%s\"" %(card, line.split(None,2)[2] ),'$MG:BOLD') 6465 elif args[1].startswith('--line_position=afterlast'): 6466 #position in file determined by user 6467 text = open(path).read() 6468 split = text.split('\n') 6469 if self.last_editline_pos > 0: 6470 pos = self.last_editline_pos +1 6471 newline = line.split(None,2)[2] 6472 split.insert(pos, newline) 6473 ff = open(path,'w') 6474 ff.write('\n'.join(split)) 6475 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD') 6476 self.last_editline_pos = pos 6477 elif args[1].startswith('--line_position='): 6478 #position in file determined by user 6479 text = open(path).read() 6480 split = text.split('\n') 6481 pos = int(args[1].split('=',1)[1]) 6482 newline = line.split(None,2)[2] 6483 split.insert(pos, newline) 6484 ff = open(path,'w') 6485 ff.write('\n'.join(split)) 6486 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD') 6487 self.last_editline_pos = pos 6488 6489 elif args[1].startswith(('--after_line=banner','--after_line=\'banner\'','--after_line=\"banner\"')): 6490 # write the line at the first not commented line 6491 text = open(path).read() 6492 split = text.split('\n') 6493 for posline,l in enumerate(split): 6494 if not l.startswith('#'): 6495 break 6496 split.insert(posline, line.split(None,2)[2]) 6497 ff = open(path,'w') 6498 ff.write('\n'.join(split)) 6499 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD') 6500 self.last_editline_pos = posline 6501 6502 elif args[1].startswith('--replace_line='): 6503 # catch the line/regular expression and replace the associate line 6504 # if no line match go to check if args[2] has other instruction starting with -- 6505 text = open(path).read() 6506 split = text.split('\n') 6507 search_pattern=r'''replace_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6508 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1] 6509 for posline,l in enumerate(split): 6510 if re.search(pattern, l): 6511 break 6512 else: 6513 new_line = re.split(search_pattern,line)[-1].strip() 6514 if new_line.startswith(('--before_line=','--after_line')): 6515 return self.do_add('%s %s' % (args[0], new_line)) 6516 raise Exception, 'invalid regular expression: not found in file' 6517 # found the line position "posline" 6518 # need to check if the a fail savety is present 6519 new_line = re.split(search_pattern,line)[-1].strip() 6520 if new_line.startswith(('--before_line=','--after_line')): 6521 search_pattern=r'''(?:before|after)_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6522 new_line = re.split(search_pattern,new_line)[-1] 6523 # overwrite the previous line 6524 old_line = split[posline] 6525 split[posline] = new_line 6526 ff = open(path,'w') 6527 ff.write('\n'.join(split)) 6528 logger.info("Replacing the line \"%s\" [line %d of %s] by \"%s\"" % 6529 (old_line, posline, card, new_line ),'$MG:BOLD') 6530 self.last_editline_pos = posline 6531 6532 6533 elif args[1].startswith('--before_line='): 6534 # catch the line/regular expression and write before that line 6535 text = open(path).read() 6536 split = text.split('\n') 6537 search_pattern=r'''before_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6538 pattern = '^\s*' + re.search(search_pattern, line).group()[13:-1] 6539 for posline,l in enumerate(split): 6540 if re.search(pattern, l): 6541 break 6542 else: 6543 raise Exception, 'invalid regular expression: not found in file' 6544 split.insert(posline, re.split(search_pattern,line)[-1]) 6545 ff = open(path,'w') 6546 ff.write('\n'.join(split)) 6547 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD') 6548 self.last_editline_pos = posline 6549 6550 elif args[1].startswith('--after_line='): 6551 # catch the line/regular expression and write after that line 6552 text = open(path).read() 6553 split = text.split('\n') 6554 search_pattern = r'''after_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1''' 6555 pattern = '^\s*' + re.search(search_pattern, line).group()[12:-1] 6556 for posline,l in enumerate(split): 6557 if re.search(pattern, l): 6558 break 6559 else: 6560 posline=len(split) 6561 split.insert(posline+1, re.split(search_pattern,line)[-1]) 6562 ff = open(path,'w') 6563 ff.write('\n'.join(split)) 6564 6565 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline+1, card, line.split(None,2)[2] ),'$MG:BOLD') 6566 self.last_editline_pos = posline+1 6567 6568 else: 6569 ff = open(path,'a') 6570 ff.write("%s \n" % line.split(None,1)[1]) 6571 ff.close() 6572 logger.info("adding at the end of the file %s the line: \"%s\"" %(card, line.split(None,1)[1] ),'$MG:BOLD') 6573 self.last_editline_pos = -1 6574 6575 self.reload_card(path)
6576 6577 do_edit = do_add 6578 complete_edit = complete_add 6579
6580 - def help_asperge(self):
6581 """Help associated to the asperge command""" 6582 signal.alarm(0) 6583 6584 print '-- syntax: asperge [options]' 6585 print ' Call ASperGe to diagonalize all mass matrices in the model.' 6586 print ' This works only if the ASperGE module is part of the UFO model (a subdirectory).' 6587 print ' If you specify some names after the command (i.e. asperge m1 m2) then ASperGe will only' 6588 print ' diagonalize the associate mass matrices (here m1 and m2).'
6589
6590 - def complete_asperge(self, text, line, begidx, endidx, formatting=True):
6591 prev_timer = signal.alarm(0) # avoid timer if any 6592 if prev_timer: 6593 nb_back = len(line) 6594 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 6595 self.stdout.write(line) 6596 self.stdout.flush() 6597 blockname = self.pname2block.keys() 6598 # remove those that we know for sure are not mixing 6599 wrong = ['decay', 'mass', 'sminput'] 6600 valid = [k for k in blockname if 'mix' in k] 6601 potential = [k for k in blockname if k not in valid+wrong] 6602 output = {'Mixing matrices': self.list_completion(text, valid, line), 6603 'Other potential valid input': self.list_completion(text, potential, line)} 6604 6605 return self.deal_multiple_categories(output, formatting)
6606 6607
6608 - def do_asperge(self, line):
6609 """Running ASperGe""" 6610 signal.alarm(0) # avoid timer if any 6611 6612 # ensure that the card is in sync 6613 if 'param' in self.modified_card: 6614 self.write_card('param') 6615 self.modified_card.discard('param') 6616 6617 6618 path = pjoin(self.me_dir,'bin','internal','ufomodel','ASperGE') 6619 if not os.path.exists(path): 6620 logger.error('ASperge has not been detected in the current model, therefore it will not be run.') 6621 return 6622 elif not os.path.exists(pjoin(path,'ASperGe')): 6623 logger.info('ASperGe has been detected but is not compiled. Running the compilation now.') 6624 try: 6625 misc.compile(cwd=path,shell=True) 6626 except MadGraph5Error, error: 6627 logger.error('''ASperGe failed to compile. Note that gsl is needed 6628 for this compilation to go trough. More information on how to install this package on 6629 http://www.gnu.org/software/gsl/ 6630 Full compilation log is available at %s''' % pjoin(self.me_dir, 'ASperge_compilation.log')) 6631 open(pjoin(self.me_dir, 'ASperge_compilation.log'),'w').write(str(error)) 6632 return 6633 6634 opts = line.split() 6635 card = self.paths['param'] 6636 logger.info('running ASperGE') 6637 returncode = misc.call([pjoin(path,'ASperGe'), card, '%s.new' % card] + opts) 6638 if returncode: 6639 logger.error('ASperGE fails with status %s' % returncode) 6640 else: 6641 logger.info('AsPerGe creates the file succesfully') 6642 files.mv(card, '%s.beforeasperge' % card) 6643 files.mv('%s.new' % card, card)
6644 6645 6646
6647 - def copy_file(self, path, pathname=None):
6648 """detect the type of the file and overwritte the current file""" 6649 6650 if not pathname: 6651 pathname = path 6652 6653 if path.endswith('.lhco'): 6654 #logger.info('copy %s as Events/input.lhco' % (path)) 6655 #files.cp(path, pjoin(self.mother_interface.me_dir, 'Events', 'input.lhco' )) 6656 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir)) 6657 return 6658 elif path.endswith('.lhco.gz'): 6659 #logger.info('copy %s as Events/input.lhco.gz' % (path)) 6660 #files.cp(path, pjoin(self.mother_interface.me_dir, 'Events', 'input.lhco.gz' )) 6661 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir)) 6662 return 6663 else: 6664 card_name = self.detect_card_type(path) 6665 6666 if card_name == 'unknown': 6667 logger.warning('Fail to determine the type of the file. Not copied') 6668 if card_name != 'banner': 6669 logger.info('copy %s as %s' % (pathname, card_name)) 6670 files.cp(path, self.paths[card_name.rsplit('_',1)[0]]) 6671 self.reload_card(self.paths[card_name.rsplit('_',1)[0]]) 6672 elif card_name == 'banner': 6673 banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False) 6674 logger.info('Splitting the banner in it\'s component') 6675 if not self.mode == 'auto': 6676 self.mother_interface.keep_cards(self.cards) 6677 for card_name in self.cards: 6678 self.reload_card(pjoin(self.me_dir, 'Cards', card_name))
6679
6680 - def detect_card_type(self, path):
6681 """detect card type""" 6682 6683 return CommonRunCmd.detect_card_type(path)
6684
6685 - def open_file(self, answer):
6686 """open the file""" 6687 6688 try: 6689 me_dir = self.mother_interface.me_dir 6690 except: 6691 me_dir = None 6692 6693 if answer.isdigit(): 6694 if answer == '9': 6695 answer = 'plot' 6696 else: 6697 answer = self.cards[int(answer)-self.integer_bias] 6698 6699 if 'madweight' in answer: 6700 answer = answer.replace('madweight', 'MadWeight') 6701 elif 'MadLoopParams' in answer: 6702 answer = self.paths['ML'] 6703 elif 'pythia8_card' in answer: 6704 answer = self.paths['pythia8'] 6705 if os.path.exists(answer): 6706 path = answer 6707 else: 6708 if not '.dat' in answer and not '.lhco' in answer: 6709 if answer != 'trigger': 6710 path = self.paths[answer] 6711 else: 6712 path = self.paths['delphes'] 6713 elif not '.lhco' in answer: 6714 if '_' in answer: 6715 path = self.paths['_'.join(answer.split('_')[:-1])] 6716 else: 6717 path = pjoin(me_dir, 'Cards', answer) 6718 else: 6719 path = pjoin(me_dir, self.mw_card['mw_run']['inputfile']) 6720 if not os.path.exists(path): 6721 logger.info('Path in MW_card not existing') 6722 path = pjoin(me_dir, 'Events', answer) 6723 #security 6724 path = path.replace('_card_card','_card') 6725 6726 if answer in self.modified_card: 6727 self.write_card(answer) 6728 elif os.path.basename(answer.replace('_card.dat','')) in self.modified_card: 6729 self.write_card(os.path.basename(answer.replace('_card.dat',''))) 6730 6731 try: 6732 self.mother_interface.exec_cmd('open %s' % path) 6733 except InvalidCmd, error: 6734 if str(error) != 'No default path for this file': 6735 raise 6736 if answer == 'transfer_card.dat': 6737 logger.warning('You have to specify a transfer function first!') 6738 elif answer == 'input.lhco': 6739 path = pjoin(me_dir,'Events', 'input.lhco') 6740 ff = open(path,'w') 6741 ff.write('''No LHCO information imported at current time. 6742 To import a lhco file: Close this file and type the path of your file. 6743 You can also copy/paste, your event file here.''') 6744 ff.close() 6745 self.open_file(path) 6746 else: 6747 raise 6748 self.reload_card(path)
6749
6750 - def reload_card(self, path):
6751 """reload object to have it in sync""" 6752 6753 if path == self.paths['param']: 6754 try: 6755 self.param_card = param_card_mod.ParamCard(path) 6756 except (param_card_mod.InvalidParamCard, ValueError) as e: 6757 logger.error('Current param_card is not valid. We are going to use the default one.') 6758 logger.error('problem detected: %s' % e) 6759 logger.error('Please re-open the file and fix the problem.') 6760 logger.warning('using the \'set\' command without opening the file will discard all your manual change') 6761 elif path == self.paths['run']: 6762 self.run_card = banner_mod.RunCard(path) 6763 elif path == self.paths['shower']: 6764 self.shower_card = shower_card_mod.ShowerCard(path) 6765 elif path == self.paths['ML']: 6766 self.MLcard = banner_mod.MadLoopParam(path) 6767 elif path == self.paths['pythia8']: 6768 # Use the read function so that modified/new parameters are correctly 6769 # set as 'user_set' 6770 if not self.PY8Card: 6771 self.PY8Card = self.PY8Card_class(self.paths['pythia8_default']) 6772 6773 self.PY8Card.read(self.paths['pythia8'], setter='user') 6774 self.py8_vars = [k.lower() for k in self.PY8Card.keys()] 6775 elif path == self.paths['MadWeight']: 6776 try: 6777 import madgraph.madweight.Cards as mwcards 6778 except: 6779 import internal.madweight.Cards as mwcards 6780 self.mw_card = mwcards.Card(path) 6781 else: 6782 logger.debug('not keep in sync: %s', path) 6783 return path 6784
6785 6786 # A decorator function to handle in a nice way scan/auto width 6787 -def scanparamcardhandling(input_path=lambda obj: pjoin(obj.me_dir, 'Cards', 'param_card.dat'), 6788 store_for_scan=lambda obj: obj.store_scan_result, 6789 get_run_name=lambda obj: obj.run_name, 6790 set_run_name=lambda obj: obj.set_run_name, 6791 result_path=lambda obj: pjoin(obj.me_dir, 'Events', 'scan_%s.txt' ), 6792 ignoreerror=ZeroResult, 6793 iteratorclass=param_card_mod.ParamCardIterator, 6794 summaryorder=lambda obj: lambda:None, 6795 check_card=lambda obj: CommonRunCmd.static_check_param_card, 6796 ):
6797 """ This is a decorator for customizing/using scan over the param_card (or technically other) 6798 This should be use like this: 6799 6800 @scanparamcardhandling(arguments) 6801 def run_launch(self, *args, **opts) 6802 6803 possible arguments are listed above and should be function who takes a single 6804 argument the instance of intereset. those return 6805 input_path -> function that return the path of the card to read 6806 store_for_scan -> function that return a dict of entry to keep in memory 6807 get_run_name -> function that return the string with the current run_name 6808 set_run_name -> function that return the function that allow the set the next run_name 6809 result_path -> function that return the path of the summary result to write 6810 ignoreerror -> one class of error which are not for the error 6811 IteratorClass -> class to use for the iterator 6812 summaryorder -> function that return the function to call to get the order 6813 6814 advanced: 6815 check_card -> function that return the function to read the card and init stuff (compute auto-width/init self.iterator/...) 6816 This function should define the self.param_card_iterator if a scan exists 6817 and the one calling the auto-width functionalities/... 6818 6819 All the function are taking a single argument (an instance of the class on which the decorator is used) 6820 and they can either return themself a function or a string. 6821 6822 Note: 6823 1. the link to auto-width is not fully trivial due to the model handling 6824 a. If you inherit from CommonRunCmd (or if the self.mother is). Then 6825 everything should be automatic. 6826 6827 b. If you do not you can/should create the funtion self.get_model(). 6828 Which returns the appropriate MG model (like the one from import_ufo.import_model) 6829 6830 c. You can also have full control by defining your own do_compute_widths(self, line) 6831 functions. 6832 """ 6833 class restore_iterator(object): 6834 """ensure that the original card is always restore even for crash""" 6835 def __init__(self, iterator, path): 6836 self.iterator = iterator 6837 self.path = path
6838 6839 def __enter__(self): 6840 return self.iterator 6841 6842 def __exit__(self, ctype, value, traceback ): 6843 self.iterator.write(self.path) 6844 6845 def decorator(original_fct): 6846 def new_fct(obj, *args, **opts): 6847 6848 if isinstance(input_path, str): 6849 card_path = input_path 6850 else: 6851 card_path = input_path(obj) 6852 6853 # 6854 # This is the function that 6855 # 1. compute the widths 6856 # 2. define the scan iterator 6857 # 3. raise some warning 6858 # 4. update dependent parameter (off by default but for scan) 6859 # if scan is found object.param_card_iterator should be define by the function 6860 check_card(obj)(card_path, obj, iterator_class=iteratorclass) 6861 6862 param_card_iterator = None 6863 if obj.param_card_iterator: 6864 param_card_iterator = obj.param_card_iterator 6865 obj.param_card_iterator = [] # ensure that the code does not re-trigger a scan 6866 6867 if not param_card_iterator: 6868 #first run of the function 6869 original_fct(obj, *args, **opts) 6870 return 6871 6872 with restore_iterator(param_card_iterator, card_path): 6873 # this with statement ensure that the original card is restore 6874 # whatever happens inside those block 6875 6876 if not hasattr(obj, 'allow_notification_center'): 6877 obj.allow_notification_center = False 6878 with misc.TMP_variable(obj, 'allow_notification_center', False): 6879 orig_name = get_run_name(obj) 6880 next_name = orig_name 6881 #next_name = param_card_iterator.get_next_name(orig_name) 6882 set_run_name(obj)(next_name) 6883 # run for the first time 6884 original_fct(obj, *args, **opts) 6885 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path) 6886 for card in param_card_iterator: 6887 card.write(card_path) 6888 # still have to check for the auto-wdith 6889 check_card(obj)(card_path, obj, dependent=True) 6890 next_name = param_card_iterator.get_next_name(next_name) 6891 set_run_name(obj)(next_name) 6892 try: 6893 original_fct(obj, *args, **opts) 6894 except ignoreerror, error: 6895 param_card_iterator.store_entry(next_name, {'exception': error}) 6896 else: 6897 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path) 6898 6899 #param_card_iterator.write(card_path) #-> this is done by the with statement 6900 name = misc.get_scan_name(orig_name, next_name) 6901 path = result_path(obj) % name 6902 logger.info("write scan results in %s" % path ,'$MG:BOLD') 6903 order = summaryorder(obj)() 6904 param_card_iterator.write_summary(path, order=order) 6905 return new_fct 6906 return decorator 6907