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

Source Code for Module madgraph.interface.common_run_interface

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