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