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

Source Code for Module madgraph.interface.common_run_interface

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