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