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

Source Code for Module madgraph.interface.common_run_interface

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