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

Source Code for Module madgraph.interface.common_run_interface

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