Package madgraph :: Package various :: Module misc
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.misc

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2009 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   
  16  """A set of functions performing routine administrative I/O tasks.""" 
  17   
  18  import contextlib 
  19  import itertools 
  20  import logging 
  21  import os 
  22  import re 
  23  import signal 
  24  import subprocess 
  25  import sys 
  26  import StringIO 
  27  import sys 
  28  import optparse 
  29  import time 
  30  import shutil 
  31  import traceback 
  32  import gzip as ziplib 
  33   
  34  try: 
  35      # Use in MadGraph 
  36      import madgraph 
  37  except Exception, error: 
  38      # Use in MadEvent 
  39      import internal 
  40      from internal import MadGraph5Error, InvalidCmd 
  41      import internal.files as files 
  42      MADEVENT = True     
  43  else: 
  44      from madgraph import MadGraph5Error, InvalidCmd 
  45      import madgraph.iolibs.files as files 
  46      MADEVENT = False 
  47   
  48       
  49  logger = logging.getLogger('cmdprint.ext_program') 
  50  logger_stderr = logging.getLogger('madevent.misc') 
  51  pjoin = os.path.join 
52 53 #=============================================================================== 54 # parse_info_str 55 #=============================================================================== 56 -def parse_info_str(fsock):
57 """Parse a newline separated list of "param=value" as a dictionnary 58 """ 59 60 info_dict = {} 61 pattern = re.compile("(?P<name>\w*)\s*=\s*(?P<value>.*)", 62 re.IGNORECASE | re.VERBOSE) 63 for entry in fsock: 64 entry = entry.strip() 65 if len(entry) == 0: continue 66 m = pattern.match(entry) 67 if m is not None: 68 info_dict[m.group('name')] = m.group('value') 69 else: 70 raise IOError, "String %s is not a valid info string" % entry 71 72 return info_dict
73
74 75 -def glob(name, path=''):
76 """call to glob.glob with automatic security on path""" 77 import glob as glob_module 78 path = re.sub('(?P<name>\?|\*|\[|\])', '[\g<name>]', path) 79 return glob_module.glob(pjoin(path, name))
80
81 #=============================================================================== 82 # mute_logger (designed to be a decorator) 83 #=============================================================================== 84 -def mute_logger(names=['madgraph','ALOHA','cmdprint','madevent'], levels=[50,50,50,50]):
85 """change the logger level and restore those at their initial value at the 86 end of the function decorated.""" 87 def control_logger(f): 88 def restore_old_levels(names, levels): 89 for name, level in zip(names, levels): 90 log_module = logging.getLogger(name) 91 log_module.setLevel(level)
92 93 def f_with_no_logger(self, *args, **opt): 94 old_levels = [] 95 for name, level in zip(names, levels): 96 log_module = logging.getLogger(name) 97 old_levels.append(log_module.level) 98 log_module.setLevel(level) 99 try: 100 out = f(self, *args, **opt) 101 restore_old_levels(names, old_levels) 102 return out 103 except: 104 restore_old_levels(names, old_levels) 105 raise 106 107 return f_with_no_logger 108 return control_logger 109
110 #=============================================================================== 111 # get_pkg_info 112 #=============================================================================== 113 -def get_pkg_info(info_str=None):
114 """Returns the current version information of the MadGraph5_aMC@NLO package, 115 as written in the VERSION text file. If the file cannot be found, 116 a dictionary with empty values is returned. As an option, an info 117 string can be passed to be read instead of the file content. 118 """ 119 120 if info_str: 121 info_dict = parse_info_str(StringIO.StringIO(info_str)) 122 123 elif MADEVENT: 124 info_dict ={} 125 info_dict['version'] = open(pjoin(internal.__path__[0],'..','..','MGMEVersion.txt')).read().strip() 126 info_dict['date'] = '20xx-xx-xx' 127 else: 128 info_dict = files.read_from_file(os.path.join(madgraph.__path__[0], 129 "VERSION"), 130 parse_info_str, 131 print_error=False) 132 133 return info_dict
134
135 #=============================================================================== 136 # get_time_info 137 #=============================================================================== 138 -def get_time_info():
139 """Returns the present time info for use in MG5 command history header. 140 """ 141 142 creation_time = time.asctime() 143 time_info = {'time': creation_time, 144 'fill': ' ' * (26 - len(creation_time))} 145 146 return time_info
147
148 #=============================================================================== 149 # Find the subdirectory which includes the files ending with a given extension 150 #=============================================================================== 151 -def find_includes_path(start_path, extension):
152 """Browse the subdirectories of the path 'start_path' and returns the first 153 one found which contains at least one file ending with the string extension 154 given in argument.""" 155 156 if not os.path.isdir(start_path): 157 return None 158 subdirs=[pjoin(start_path,dir) for dir in os.listdir(start_path)] 159 for subdir in subdirs: 160 if os.path.isfile(subdir): 161 if os.path.basename(subdir).endswith(extension): 162 return start_path 163 elif os.path.isdir(subdir): 164 path = find_includes_path(subdir, extension) 165 if path: 166 return path 167 return None
168
169 #=============================================================================== 170 # Given the path of a ninja installation, this function determines if it 171 # supports quadruple precision or not. 172 #=============================================================================== 173 -def get_ninja_quad_prec_support(ninja_lib_path):
174 """ Get whether ninja supports quad prec in different ways""" 175 176 # First try with the ninja-config executable if present 177 ninja_config = os.path.abspath(pjoin( 178 ninja_lib_path,os.pardir,'bin','ninja-config')) 179 if os.path.exists(ninja_config): 180 try: 181 p = Popen([ninja_config, '-quadsupport'], stdout=subprocess.PIPE, 182 stderr=subprocess.PIPE) 183 output, error = p.communicate() 184 return 'TRUE' in output.upper() 185 except Exception: 186 pass 187 188 # If no ninja-config is present, then simply use the presence of 189 # 'quadninja' in the include 190 return False
191
192 #=============================================================================== 193 # find a executable 194 #=============================================================================== 195 -def which(program):
196 def is_exe(fpath): 197 return os.path.exists(fpath) and os.access(\ 198 os.path.realpath(fpath), os.X_OK)
199 200 if not program: 201 return None 202 203 fpath, fname = os.path.split(program) 204 if fpath: 205 if is_exe(program): 206 return program 207 else: 208 for path in os.environ["PATH"].split(os.pathsep): 209 exe_file = os.path.join(path, program) 210 if is_exe(exe_file): 211 return exe_file 212 return None 213
214 -def has_f2py():
215 has_f2py = False 216 if which('f2py'): 217 has_f2py = True 218 elif sys.version_info[1] == 6: 219 if which('f2py-2.6'): 220 has_f2py = True 221 elif which('f2py2.6'): 222 has_f2py = True 223 else: 224 if which('f2py-2.7'): 225 has_f2py = True 226 elif which('f2py2.7'): 227 has_f2py = True 228 return has_f2py
229
230 #=============================================================================== 231 # Activate dependencies if possible. Mainly for tests 232 #=============================================================================== 233 234 -def deactivate_dependence(dependency, cmd=None, log = None):
235 """ Make sure to turn off some dependency of MG5aMC. """ 236 237 def tell(msg): 238 if log == 'stdout': 239 print msg 240 elif callable(log): 241 log(msg)
242 243 244 if dependency in ['pjfry','golem','samurai','ninja','collier']: 245 if cmd.options[dependency] not in ['None',None,'']: 246 tell("Deactivating MG5_aMC dependency '%s'"%dependency) 247 cmd.options[dependency] = None 248
249 -def activate_dependence(dependency, cmd=None, log = None, MG5dir=None):
250 """ Checks whether the specfieid MG dependency can be activated if it was 251 not turned off in MG5 options.""" 252 253 def tell(msg): 254 if log == 'stdout': 255 print msg 256 elif callable(log): 257 log(msg)
258 259 if cmd is None: 260 cmd = MGCmd.MasterCmd() 261 262 if dependency=='pjfry': 263 if cmd.options['pjfry'] in ['None',None,''] or \ 264 (cmd.options['pjfry'] == 'auto' and which_lib('libpjfry.a') is None) or\ 265 which_lib(pjoin(cmd.options['pjfry'],'libpjfry.a')) is None: 266 tell("Installing PJFry...") 267 cmd.do_install('PJFry') 268 269 if dependency=='golem': 270 if cmd.options['golem'] in ['None',None,''] or\ 271 (cmd.options['golem'] == 'auto' and which_lib('libgolem.a') is None) or\ 272 which_lib(pjoin(cmd.options['golem'],'libgolem.a')) is None: 273 tell("Installing Golem95...") 274 cmd.do_install('Golem95') 275 276 if dependency=='samurai': 277 raise MadGraph5Error, 'Samurai cannot yet be automatically installed.' 278 279 if dependency=='ninja': 280 if cmd.options['ninja'] in ['None',None,''] or\ 281 (cmd.options['ninja'] == './HEPTools/lib' and not MG5dir is None and\ 282 which_lib(pjoin(MG5dir,cmd.options['ninja'],'libninja.a')) is None): 283 tell("Installing ninja...") 284 cmd.do_install('ninja') 285 286 if dependency=='collier': 287 if cmd.options['collier'] in ['None',None,''] or\ 288 (cmd.options['collier'] == 'auto' and which_lib('libcollier.a') is None) or\ 289 which_lib(pjoin(cmd.options['collier'],'libcollier.a')) is None: 290 tell("Installing COLLIER...") 291 cmd.do_install('collier') 292
293 #=============================================================================== 294 # find a library 295 #=============================================================================== 296 -def which_lib(lib):
297 def is_lib(fpath): 298 return os.path.exists(fpath) and os.access(fpath, os.R_OK)
299 300 if not lib: 301 return None 302 303 fpath, fname = os.path.split(lib) 304 if fpath: 305 if is_lib(lib): 306 return lib 307 else: 308 locations = sum([os.environ[env_path].split(os.pathsep) for env_path in 309 ["DYLD_LIBRARY_PATH","LD_LIBRARY_PATH","LIBRARY_PATH","PATH"] 310 if env_path in os.environ],[]) 311 for path in locations: 312 lib_file = os.path.join(path, lib) 313 if is_lib(lib_file): 314 return lib_file 315 return None 316
317 #=============================================================================== 318 # Return Nice display for a random variable 319 #=============================================================================== 320 -def nice_representation(var, nb_space=0):
321 """ Return nice information on the current variable """ 322 323 #check which data to put: 324 info = [('type',type(var)),('str', var)] 325 if hasattr(var, 'func_doc'): 326 info.append( ('DOC', var.func_doc) ) 327 if hasattr(var, '__doc__'): 328 info.append( ('DOC', var.__doc__) ) 329 if hasattr(var, '__dict__'): 330 info.append( ('ATTRIBUTE', var.__dict__.keys() )) 331 332 spaces = ' ' * nb_space 333 334 outstr='' 335 for name, value in info: 336 outstr += '%s%3s : %s\n' % (spaces,name, value) 337 338 return outstr
339 340 # 341 # Decorator for re-running a crashing function automatically. 342 # 343 wait_once = False
344 -def multiple_try(nb_try=5, sleep=20):
345 346 def deco_retry(f): 347 def deco_f_retry(*args, **opt): 348 for i in range(nb_try): 349 try: 350 return f(*args, **opt) 351 except KeyboardInterrupt: 352 raise 353 except Exception, error: 354 global wait_once 355 if not wait_once: 356 text = """Start waiting for update. (more info in debug mode)""" 357 logger.info(text) 358 logger_stderr.debug('fail to do %s function with %s args. %s try on a max of %s (%s waiting time)' % 359 (str(f), ', '.join([str(a) for a in args]), i+1, nb_try, sleep * (i+1))) 360 logger_stderr.debug('error is %s' % str(error)) 361 if __debug__: logger_stderr.debug('and occurred at :'+traceback.format_exc()) 362 wait_once = True 363 time.sleep(sleep * (i+1)) 364 365 if __debug__: 366 raise 367 raise error.__class__, '[Fail %i times] \n %s ' % (i+1, error)
368 return deco_f_retry 369 return deco_retry 370
371 #=============================================================================== 372 # helper for scan. providing a nice formatted string for the scan name 373 #=============================================================================== 374 -def get_scan_name(first, last):
375 """return a name of the type xxxx[A-B]yyy 376 where xxx and yyy are the common part between the two names. 377 """ 378 379 # find the common string at the beginning 380 base = [first[i] for i in range(len(first)) if first[:i+1] == last[:i+1]] 381 # remove digit even if in common 382 while base and base[0].isdigit(): 383 base = base[1:] 384 # find the common string at the end 385 end = [first[-(i+1)] for i in range(len(first)) if first[-(i+1):] == last[-(i+1):]] 386 # remove digit even if in common 387 while end and end[-1].isdigit(): 388 end = end[:-1] 389 end.reverse() 390 #convert to string 391 base, end = ''.join(base), ''.join(end) 392 if end: 393 name = "%s[%s-%s]%s" % (base, first[len(base):-len(end)], last[len(base):-len(end)],end) 394 else: 395 name = "%s[%s-%s]%s" % (base, first[len(base):], last[len(base):],end) 396 return name
397
398 #=============================================================================== 399 # Compiler which returns smart output error in case of trouble 400 #=============================================================================== 401 -def compile(arg=[], cwd=None, mode='fortran', job_specs = True, nb_core=1 ,**opt):
402 """compile a given directory""" 403 404 if 'nocompile' in opt: 405 if opt['nocompile'] == True: 406 if not arg: 407 return 408 if cwd: 409 executable = pjoin(cwd, arg[0]) 410 else: 411 executable = arg[0] 412 if os.path.exists(executable): 413 return 414 del opt['nocompile'] 415 416 cmd = ['make'] 417 try: 418 if nb_core > 1: 419 cmd.append('-j%s' % nb_core) 420 cmd += arg 421 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 422 stderr=subprocess.STDOUT, cwd=cwd, **opt) 423 (out, err) = p.communicate() 424 except OSError, error: 425 if cwd and not os.path.exists(cwd): 426 raise OSError, 'Directory %s doesn\'t exists. Impossible to run make' % cwd 427 else: 428 error_text = "Impossible to compile %s directory\n" % cwd 429 error_text += "Trying to launch make command returns:\n" 430 error_text += " " + str(error) + "\n" 431 error_text += "In general this means that your computer is not able to compile." 432 if sys.platform == "darwin": 433 error_text += "Note that MacOSX doesn\'t have gmake/gfortan install by default.\n" 434 error_text += "Xcode3 contains those required programs" 435 raise MadGraph5Error, error_text 436 437 if p.returncode: 438 # Check that makefile exists 439 if not cwd: 440 cwd = os.getcwd() 441 all_file = [f.lower() for f in os.listdir(cwd)] 442 if 'makefile' not in all_file and '-f' not in arg: 443 raise OSError, 'no makefile present in %s' % os.path.realpath(cwd) 444 445 if mode == 'fortran' and not (which('g77') or which('gfortran')): 446 error_msg = 'A fortran compiler (g77 or gfortran) is required to create this output.\n' 447 error_msg += 'Please install g77 or gfortran on your computer and retry.' 448 raise MadGraph5Error, error_msg 449 elif mode == 'cpp' and not which('g++'): 450 error_msg ='A C++ compiler (g++) is required to create this output.\n' 451 error_msg += 'Please install g++ (which is part of the gcc package) on your computer and retry.' 452 raise MadGraph5Error, error_msg 453 454 # Check if this is due to the need of gfortran 4.6 for quadruple precision 455 if any(tag.upper() in out.upper() for tag in ['real(kind=16)','real*16', 456 'complex*32']) and mode == 'fortran' and not \ 457 ''.join(get_gfortran_version().split('.')) >= '46': 458 if not which('gfortran'): 459 raise MadGraph5Error, 'The fortran compiler gfortran v4.6 or later '+\ 460 'is required to compile %s.\nPlease install it and retry.'%cwd 461 else: 462 logger_stderr.error('ERROR, you could not compile %s because'%cwd+\ 463 ' your version of gfortran is older than 4.6. MadGraph5_aMC@NLO will carry on,'+\ 464 ' but will not be able to compile an executable.') 465 return p.returncode 466 # Other reason 467 error_text = 'A compilation Error occurs ' 468 if cwd: 469 error_text += 'when trying to compile %s.\n' % cwd 470 error_text += 'The compilation fails with the following output message:\n' 471 error_text += ' '+out.replace('\n','\n ')+'\n' 472 error_text += 'Please try to fix this compilations issue and retry.\n' 473 error_text += 'Help might be found at https://answers.launchpad.net/mg5amcnlo.\n' 474 error_text += 'If you think that this is a bug, you can report this at https://bugs.launchpad.net/mg5amcnlo' 475 raise MadGraph5Error, error_text 476 return p.returncode
477
478 -def get_gfortran_version(compiler='gfortran'):
479 """ Returns the gfortran version as a string. 480 Returns '0' if it failed.""" 481 try: 482 p = Popen([compiler, '-dumpversion'], stdout=subprocess.PIPE, 483 stderr=subprocess.PIPE) 484 output, error = p.communicate() 485 version_finder=re.compile(r"(?P<version>(\d.)*\d)") 486 version = version_finder.search(output).group('version') 487 return version 488 except Exception: 489 return '0'
490
491 -def mod_compilator(directory, new='gfortran', current=None, compiler_type='gfortran'):
492 #define global regular expression 493 if type(directory)!=list: 494 directory=[directory] 495 496 #search file 497 file_to_change=find_makefile_in_dir(directory) 498 if compiler_type == 'gfortran': 499 comp_re = re.compile('^(\s*)FC\s*=\s*(.+)\s*$') 500 var = 'FC' 501 elif compiler_type == 'cpp': 502 comp_re = re.compile('^(\s*)CXX\s*=\s*(.+)\s*$') 503 var = 'CXX' 504 else: 505 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type 506 507 mod = False 508 for name in file_to_change: 509 lines = open(name,'r').read().split('\n') 510 for iline, line in enumerate(lines): 511 result = comp_re.match(line) 512 if result: 513 if new != result.group(2) and '$' not in result.group(2): 514 mod = True 515 lines[iline] = result.group(1) + var + "=" + new 516 elif compiler_type == 'gfortran' and line.startswith('DEFAULT_F_COMPILER'): 517 lines[iline] = "DEFAULT_F_COMPILER = %s" % new 518 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'): 519 lines[iline] = "DEFAULT_CPP_COMPILER = %s" % new 520 521 if mod: 522 open(name,'w').write('\n'.join(lines)) 523 # reset it to change the next file 524 mod = False
525
526 #=============================================================================== 527 # mute_logger (designed to work as with statement) 528 #=============================================================================== 529 -class MuteLogger(object):
530 """mute_logger (designed to work as with statement), 531 files allow to redirect the output of the log to a given file. 532 """ 533
534 - def __init__(self, names, levels, files=None, **opt):
535 assert isinstance(names, list) 536 assert isinstance(names, list) 537 538 self.names = names 539 self.levels = levels 540 if isinstance(files, list): 541 self.files = files 542 else: 543 self.files = [files] * len(names) 544 self.logger_saved_info = {} 545 self.opts = opt
546
547 - def __enter__(self):
548 old_levels = [] 549 for name, level, path in zip(self.names, self.levels, self.files): 550 if path: 551 self.setup_logFile_for_logger(path, name, **self.opts) 552 log_module = logging.getLogger(name) 553 old_levels.append(log_module.level) 554 log_module = logging.getLogger(name) 555 log_module.setLevel(level) 556 self.levels = old_levels
557
558 - def __exit__(self, ctype, value, traceback ):
559 for name, level, path in zip(self.names, self.levels, self.files): 560 561 if path: 562 if 'keep' in self.opts and not self.opts['keep']: 563 self.restore_logFile_for_logger(name, level, path=path) 564 else: 565 self.restore_logFile_for_logger(name, level) 566 else: 567 log_module = logging.getLogger(name) 568 log_module.setLevel(level)
569
570 - def setup_logFile_for_logger(self, path, full_logname, **opts):
571 """ Setup the logger by redirecting them all to logfiles in tmp """ 572 573 logs = full_logname.split('.') 574 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\ 575 range(len(full_logname.split('.')))] 576 for logname in lognames: 577 try: 578 os.remove(path) 579 except Exception, error: 580 pass 581 my_logger = logging.getLogger(logname) 582 hdlr = logging.FileHandler(path) 583 # I assume below that the orders of the handlers in my_logger.handlers 584 # remains the same after having added/removed the FileHandler 585 self.logger_saved_info[logname] = [hdlr, my_logger.handlers] 586 #for h in my_logger.handlers: 587 # h.setLevel(logging.CRITICAL) 588 for old_hdlr in list(my_logger.handlers): 589 my_logger.removeHandler(old_hdlr) 590 my_logger.addHandler(hdlr) 591 #my_logger.setLevel(level) 592 my_logger.debug('Log of %s' % logname)
593
594 - def restore_logFile_for_logger(self, full_logname, level, path=None, **opts):
595 """ Setup the logger by redirecting them all to logfiles in tmp """ 596 597 logs = full_logname.split('.') 598 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\ 599 range(len(full_logname.split('.')))] 600 for logname in lognames: 601 if path: 602 try: 603 os.remove(path) 604 except Exception, error: 605 pass 606 my_logger = logging.getLogger(logname) 607 if logname in self.logger_saved_info: 608 my_logger.removeHandler(self.logger_saved_info[logname][0]) 609 for old_hdlr in self.logger_saved_info[logname][1]: 610 my_logger.addHandler(old_hdlr) 611 else: 612 my_logger.setLevel(level)
613 614 #for i, h in enumerate(my_logger.handlers): 615 # h.setLevel(cls.logger_saved_info[logname][2][i]) 616 617 nb_open =0
618 @contextlib.contextmanager 619 -def stdchannel_redirected(stdchannel, dest_filename):
620 """ 621 A context manager to temporarily redirect stdout or stderr 622 623 e.g.: 624 625 626 with stdchannel_redirected(sys.stderr, os.devnull): 627 if compiler.has_function('clock_gettime', libraries=['rt']): 628 libraries.append('rt') 629 """ 630 631 try: 632 oldstdchannel = os.dup(stdchannel.fileno()) 633 dest_file = open(dest_filename, 'w') 634 os.dup2(dest_file.fileno(), stdchannel.fileno()) 635 yield 636 finally: 637 if oldstdchannel is not None: 638 os.dup2(oldstdchannel, stdchannel.fileno()) 639 os.close(oldstdchannel) 640 if dest_file is not None: 641 dest_file.close()
642
643 -def get_open_fds():
644 ''' 645 return the number of open file descriptors for current process 646 647 .. warning: will only work on UNIX-like os-es. 648 ''' 649 import subprocess 650 import os 651 652 pid = os.getpid() 653 procs = subprocess.check_output( 654 [ "lsof", '-w', '-Ff', "-p", str( pid ) ] ) 655 nprocs = filter( 656 lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(), 657 procs.split( '\n' ) ) 658 659 return nprocs
660
661 -def detect_if_cpp_compiler_is_clang(cpp_compiler):
662 """ Detects whether the specified C++ compiler is clang.""" 663 664 try: 665 p = Popen([cpp_compiler, '--version'], stdout=subprocess.PIPE, 666 stderr=subprocess.PIPE) 667 output, error = p.communicate() 668 except Exception, error: 669 # Cannot probe the compiler, assume not clang then 670 return False 671 return 'LLVM' in output
672
673 -def detect_cpp_std_lib_dependence(cpp_compiler):
674 """ Detects if the specified c++ compiler will normally link against the C++ 675 standard library -lc++ or -libstdc++.""" 676 677 is_clang = detect_if_cpp_compiler_is_clang(cpp_compiler) 678 if is_clang: 679 try: 680 import platform 681 v, _,_ = platform.mac_ver() 682 if not v: 683 # We will not attempt to support clang elsewhere than on macs, so 684 # we venture a guess here. 685 return '-lc++' 686 else: 687 v = float(v.rsplit('.')[1]) 688 if v >= 9: 689 return '-lc++' 690 else: 691 return '-lstdc++' 692 except: 693 return '-lstdc++' 694 return '-lstdc++'
695
696 -def detect_current_compiler(path, compiler_type='fortran'):
697 """find the current compiler for the current directory""" 698 699 # comp = re.compile("^\s*FC\s*=\s*(\w+)\s*") 700 # The regular expression below allows for compiler definition with absolute path 701 if compiler_type == 'fortran': 702 comp = re.compile("^\s*FC\s*=\s*([\w\/\\.\-]+)\s*") 703 elif compiler_type == 'cpp': 704 comp = re.compile("^\s*CXX\s*=\s*([\w\/\\.\-]+)\s*") 705 else: 706 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type 707 708 for line in open(path): 709 if comp.search(line): 710 compiler = comp.search(line).groups()[0] 711 return compiler 712 elif compiler_type == 'fortran' and line.startswith('DEFAULT_F_COMPILER'): 713 return line.split('=')[1].strip() 714 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'): 715 return line.split('=')[1].strip()
716
717 -def find_makefile_in_dir(directory):
718 """ return a list of all file starting with makefile in the given directory""" 719 720 out=[] 721 #list mode 722 if type(directory)==list: 723 for name in directory: 724 out+=find_makefile_in_dir(name) 725 return out 726 727 #single mode 728 for name in os.listdir(directory): 729 if os.path.isdir(directory+'/'+name): 730 out+=find_makefile_in_dir(directory+'/'+name) 731 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('makefile'): 732 out.append(directory+'/'+name) 733 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('make_opt'): 734 out.append(directory+'/'+name) 735 return out
736
737 -def rm_old_compile_file():
738 739 # remove all the .o files 740 os.path.walk('.', rm_file_extension, '.o') 741 742 # remove related libraries 743 libraries = ['libblocks.a', 'libgeneric_mw.a', 'libMWPS.a', 'libtools.a', 'libdhelas3.a', 744 'libdsample.a', 'libgeneric.a', 'libmodel.a', 'libpdf.a', 'libdhelas3.so', 'libTF.a', 745 'libdsample.so', 'libgeneric.so', 'libmodel.so', 'libpdf.so'] 746 lib_pos='./lib' 747 [os.remove(os.path.join(lib_pos, lib)) for lib in libraries \ 748 if os.path.exists(os.path.join(lib_pos, lib))]
749
750 751 -def format_time(n_secs):
752 m, s = divmod(n_secs, 60) 753 h, m = divmod(m, 60) 754 d, h = divmod(h, 24) 755 if d > 0: 756 return "%d day%s,%dh%02dm%02ds" % (d,'' if d<=1 else 's',h, m, s) 757 elif h > 0: 758 return "%dh%02dm%02ds" % (h, m, s) 759 elif m > 0: 760 return "%dm%02ds" % (m, s) 761 else: 762 return "%d second%s" % (s, '' if s<=1 else 's')
763
764 -def rm_file_extension( ext, dirname, names):
765 766 [os.remove(os.path.join(dirname, name)) for name in names if name.endswith(ext)]
767
768 769 770 -def multiple_replacer(*key_values):
771 replace_dict = dict(key_values) 772 replacement_function = lambda match: replace_dict[match.group(0)] 773 pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M) 774 return lambda string: pattern.sub(replacement_function, string)
775
776 -def multiple_replace(string, *key_values):
777 return multiple_replacer(*key_values)(string)
778
779 # Control 780 -def check_system_error(value=1):
781 def deco_check(f): 782 def deco_f(arg, *args, **opt): 783 try: 784 return f(arg, *args, **opt) 785 except OSError, error: 786 logger.debug('try to recover from %s' % error) 787 if isinstance(arg, list): 788 prog = arg[0] 789 else: 790 prog = arg[0] 791 792 # Permission denied 793 if error.errno == 13: 794 if os.path.exists(prog): 795 os.system('chmod +x %s' % prog) 796 elif 'cwd' in opt and opt['cwd'] and \ 797 os.path.isfile(pjoin(opt['cwd'],arg[0])): 798 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0])) 799 return f(arg, *args, **opt) 800 # NO such file or directory 801 elif error.errno == 2: 802 # raise a more meaningfull error message 803 raise Exception, '%s fails with no such file or directory' \ 804 % arg 805 else: 806 raise
807 return deco_f 808 return deco_check 809
810 811 @check_system_error() 812 -def call(arg, *args, **opt):
813 """nice way to call an external program with nice error treatment""" 814 try: 815 return subprocess.call(arg, *args, **opt) 816 except OSError: 817 arg[0] = './%s' % arg[0] 818 return subprocess.call(arg, *args, **opt)
819
820 @check_system_error() 821 -def Popen(arg, *args, **opt):
822 """nice way to call an external program with nice error treatment""" 823 return subprocess.Popen(arg, *args, **opt)
824
825 @multiple_try() 826 -def mult_try_open(filepath, *args, **opt):
827 """try to open a file with multiple try to ensure that filesystem is sync""" 828 return open(filepath, *args, ** opt)
829
830 ################################################################################ 831 # TAIL FUNCTION 832 ################################################################################ 833 -def tail(f, n, offset=None):
834 """Reads a n lines from f with an offset of offset lines. The return 835 value is a tuple in the form ``lines``. 836 """ 837 avg_line_length = 74 838 to_read = n + (offset or 0) 839 840 while 1: 841 try: 842 f.seek(-(avg_line_length * to_read), 2) 843 except IOError: 844 # woops. apparently file is smaller than what we want 845 # to step back, go to the beginning instead 846 f.seek(0) 847 pos = f.tell() 848 lines = f.read().splitlines() 849 if len(lines) >= to_read or pos == 0: 850 return lines[-to_read:offset and -offset or None] 851 avg_line_length *= 1.3 852 avg_line_length = int(avg_line_length)
853
854 -def mkfifo(fifo_path):
855 """ makes a piping fifo (First-in First-out) file and nicely intercepts 856 error in case the file format of the target drive doesn't suppor tit.""" 857 858 try: 859 os.mkfifo(fifo_path) 860 except: 861 raise OSError('MadGraph5_aMCatNLO could not create a fifo file at:\n'+ 862 ' %s\n'%fifo_path+'Make sure that this file does not exist already'+ 863 ' and that the file format of the target drive supports fifo file (i.e not NFS).')
864
865 ################################################################################ 866 # LAST LINE FUNCTION 867 ################################################################################ 868 -def get_last_line(fsock):
869 """return the last line of a file""" 870 871 return tail(fsock, 1)[0]
872
873 -class BackRead(file):
874 """read a file returning the lines in reverse order for each call of readline() 875 This actually just reads blocks (4096 bytes by default) of data from the end of 876 the file and returns last line in an internal buffer.""" 877 878
879 - def readline(self):
880 """ readline in a backward way """ 881 882 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size): 883 self.blkcount = self.blkcount + 1 884 line = self.data[0] 885 try: 886 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 887 self.data = (self.read(self.blksize) + line).split('\n') 888 except IOError: # can't seek before the beginning of the file 889 self.seek(0) 890 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line 891 self.data = data.split('\n') 892 893 if len(self.data) == 0: 894 return "" 895 896 line = self.data.pop() 897 return line + '\n'
898
899 - def __init__(self, filepos, blksize=4096):
900 """initialize the internal structures""" 901 902 # get the file size 903 self.size = os.stat(filepos)[6] 904 # how big of a block to read from the file... 905 self.blksize = blksize 906 # how many blocks we've read 907 self.blkcount = 1 908 file.__init__(self, filepos, 'rb') 909 # if the file is smaller than the blocksize, read a block, 910 # otherwise, read the whole thing... 911 if self.size > self.blksize: 912 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 913 self.data = self.read(self.blksize).split('\n') 914 # strip the last item if it's empty... a byproduct of the last line having 915 # a newline at the end of it 916 if not self.data[-1]: 917 self.data.pop()
918
919 - def next(self):
920 line = self.readline() 921 if line: 922 return line 923 else: 924 raise StopIteration
925
926 927 -def write_PS_input(filePath, PS):
928 """ Write out in file filePath the PS point to be read by the MadLoop.""" 929 try: 930 PSfile = open(filePath, 'w') 931 # Add a newline in the end as the implementation fortran 'read' 932 # command on some OS is problematic if it ends directly with the 933 # floating point number read. 934 935 PSfile.write('\n'.join([' '.join(['%.16E'%pi for pi in p]) \ 936 for p in PS])+'\n') 937 PSfile.close() 938 except Exception: 939 raise MadGraph5Error, 'Could not write out the PS point to file %s.'\ 940 %str(filePath)
941
942 -def format_timer(running_time):
943 """ return a nicely string representing the time elapsed.""" 944 if running_time < 2e-2: 945 running_time = running_time = 'current time: %02dh%02d' % (time.localtime().tm_hour, time.localtime().tm_min) 946 elif running_time < 10: 947 running_time = ' %.2gs ' % running_time 948 elif 60 > running_time >= 10: 949 running_time = ' %.3gs ' % running_time 950 elif 3600 > running_time >= 60: 951 running_time = ' %im %is ' % (running_time // 60, int(running_time % 60)) 952 else: 953 running_time = ' %ih %im ' % (running_time // 3600, (running_time//60 % 60)) 954 return running_time
955
956 957 #=============================================================================== 958 # TMP_directory (designed to work as with statement) 959 #=============================================================================== 960 -class TMP_directory(object):
961 """create a temporary directory and ensure this one to be cleaned. 962 """ 963
964 - def __init__(self, suffix='', prefix='tmp', dir=None):
965 self.nb_try_remove = 0 966 import tempfile 967 self.path = tempfile.mkdtemp(suffix, prefix, dir)
968 969
970 - def __exit__(self, ctype, value, traceback ):
971 #True only for debugging: 972 if False and isinstance(value, Exception): 973 sprint("Directory %s not cleaned. This directory can be removed manually" % self.path) 974 return False 975 try: 976 shutil.rmtree(self.path) 977 except OSError: 978 self.nb_try_remove += 1 979 if self.nb_try_remove < 3: 980 time.sleep(10) 981 self.__exit__(ctype, value, traceback) 982 else: 983 logger.warning("Directory %s not completely cleaned. This directory can be removed manually" % self.path)
984
985 - def __enter__(self):
986 return self.path
987
988 -class TMP_variable(object):
989 """create a temporary directory and ensure this one to be cleaned. 990 """ 991
992 - def __init__(self, cls, attribute, value):
993 994 self.cls = cls 995 self.attribute = attribute 996 if isinstance(attribute, list): 997 self.old_value = [] 998 for key, onevalue in zip(attribute, value): 999 self.old_value.append(getattr(cls, key)) 1000 setattr(self.cls, key, onevalue) 1001 else: 1002 self.old_value = getattr(cls, attribute) 1003 setattr(self.cls, self.attribute, value)
1004
1005 - def __exit__(self, ctype, value, traceback ):
1006 1007 if isinstance(self.attribute, list): 1008 for key, old_value in zip(self.attribute, self.old_value): 1009 setattr(self.cls, key, old_value) 1010 else: 1011 setattr(self.cls, self.attribute, self.old_value)
1012
1013 - def __enter__(self):
1014 return self.old_value
1015
1016 # 1017 # GUNZIP/GZIP 1018 # 1019 -def gunzip(path, keep=False, stdout=None):
1020 """ a standard replacement for os.system('gunzip -f %s.gz ' % event_path)""" 1021 1022 if not path.endswith(".gz"): 1023 if os.path.exists("%s.gz" % path): 1024 path = "%s.gz" % path 1025 else: 1026 raise Exception, "%(path)s does not finish by .gz and the file %(path)s.gz does not exists" %\ 1027 {"path": path} 1028 1029 1030 #for large file (>1G) it is faster and safer to use a separate thread 1031 if os.path.getsize(path) > 1e8: 1032 if stdout: 1033 os.system('gunzip -c %s > %s' % (path, stdout)) 1034 else: 1035 os.system('gunzip %s' % path) 1036 return 0 1037 1038 if not stdout: 1039 stdout = path[:-3] 1040 try: 1041 gfile = ziplib.open(path, "r") 1042 except IOError: 1043 raise 1044 else: 1045 try: 1046 open(stdout,'w').write(gfile.read()) 1047 except IOError: 1048 # this means that the file is actually not gzip 1049 if stdout == path: 1050 return 1051 else: 1052 files.cp(path, stdout) 1053 1054 if not keep: 1055 os.remove(path) 1056 return 0
1057
1058 -def gzip(path, stdout=None, error=True, forceexternal=False):
1059 """ a standard replacement for os.system('gzip %s ' % path)""" 1060 1061 #for large file (>1G) it is faster and safer to use a separate thread 1062 if os.path.getsize(path) > 1e9 or forceexternal: 1063 call(['gzip', '-f', path]) 1064 if stdout: 1065 if not stdout.endswith(".gz"): 1066 stdout = "%s.gz" % stdout 1067 shutil.move('%s.gz' % path, stdout) 1068 return 1069 1070 if not stdout: 1071 stdout = "%s.gz" % path 1072 elif not stdout.endswith(".gz"): 1073 stdout = "%s.gz" % stdout 1074 1075 try: 1076 ziplib.open(stdout,"w").write(open(path).read()) 1077 except OverflowError: 1078 gzip(path, stdout, error=error, forceexternal=True) 1079 except Exception: 1080 if error: 1081 raise 1082 else: 1083 os.remove(path)
1084
1085 # 1086 # Global function to open supported file types 1087 # 1088 -class open_file(object):
1089 """ a convinient class to open a file """ 1090 1091 web_browser = None 1092 eps_viewer = None 1093 text_editor = None 1094 configured = False 1095
1096 - def __init__(self, filename):
1097 """open a file""" 1098 1099 # Check that the class is correctly configure 1100 if not self.configured: 1101 self.configure() 1102 1103 try: 1104 extension = filename.rsplit('.',1)[1] 1105 except IndexError: 1106 extension = '' 1107 1108 1109 # dispatch method 1110 if extension in ['html','htm','php']: 1111 self.open_program(self.web_browser, filename, background=True) 1112 elif extension in ['ps','eps']: 1113 self.open_program(self.eps_viewer, filename, background=True) 1114 else: 1115 self.open_program(self.text_editor,filename, mac_check=False)
1116 # mac_check to False avoid to use open cmd in mac 1117 1118 @classmethod
1119 - def configure(cls, configuration=None):
1120 """ configure the way to open the file """ 1121 1122 cls.configured = True 1123 1124 # start like this is a configuration for mac 1125 cls.configure_mac(configuration) 1126 if sys.platform == 'darwin': 1127 return # done for MAC 1128 1129 # on Mac some default (eps/web) might be kept on None. This is not 1130 #suitable for LINUX which doesn't have open command. 1131 1132 # first for eps_viewer 1133 if not cls.eps_viewer: 1134 cls.eps_viewer = cls.find_valid(['evince','gv', 'ggv'], 'eps viewer') 1135 1136 # Second for web browser 1137 if not cls.web_browser: 1138 cls.web_browser = cls.find_valid( 1139 ['firefox', 'chrome', 'safari','opera'], 1140 'web browser')
1141 1142 @classmethod
1143 - def configure_mac(cls, configuration=None):
1144 """ configure the way to open a file for mac """ 1145 1146 if configuration is None: 1147 configuration = {'text_editor': None, 1148 'eps_viewer':None, 1149 'web_browser':None} 1150 1151 for key in configuration: 1152 if key == 'text_editor': 1153 # Treat text editor ONLY text base editor !! 1154 if configuration[key]: 1155 program = configuration[key].split()[0] 1156 if not which(program): 1157 logger.warning('Specified text editor %s not valid.' % \ 1158 configuration[key]) 1159 else: 1160 # All is good 1161 cls.text_editor = configuration[key] 1162 continue 1163 #Need to find a valid default 1164 if os.environ.has_key('EDITOR'): 1165 cls.text_editor = os.environ['EDITOR'] 1166 else: 1167 cls.text_editor = cls.find_valid( 1168 ['vi', 'emacs', 'vim', 'gedit', 'nano'], 1169 'text editor') 1170 1171 elif key == 'eps_viewer': 1172 if configuration[key]: 1173 cls.eps_viewer = configuration[key] 1174 continue 1175 # else keep None. For Mac this will use the open command. 1176 elif key == 'web_browser': 1177 if configuration[key]: 1178 cls.web_browser = configuration[key] 1179 continue
1180 # else keep None. For Mac this will use the open command. 1181 1182 @staticmethod
1183 - def find_valid(possibility, program='program'):
1184 """find a valid shell program in the list""" 1185 1186 for p in possibility: 1187 if which(p): 1188 logger.info('Using default %s \"%s\". ' % (program, p) + \ 1189 'Set another one in ./input/mg5_configuration.txt') 1190 return p 1191 1192 logger.info('No valid %s found. ' % program + \ 1193 'Please set in ./input/mg5_configuration.txt') 1194 return None
1195 1196
1197 - def open_program(self, program, file_path, mac_check=True, background=False):
1198 """ open a file with a given program """ 1199 1200 if mac_check==True and sys.platform == 'darwin': 1201 return self.open_mac_program(program, file_path) 1202 1203 # Shell program only 1204 if program: 1205 arguments = program.split() # allow argument in program definition 1206 arguments.append(file_path) 1207 1208 if not background: 1209 subprocess.call(arguments) 1210 else: 1211 import thread 1212 thread.start_new_thread(subprocess.call,(arguments,)) 1213 else: 1214 logger.warning('Not able to open file %s since no program configured.' % file_path + \ 1215 'Please set one in ./input/mg5_configuration.txt')
1216
1217 - def open_mac_program(self, program, file_path):
1218 """ open a text with the text editor """ 1219 1220 if not program: 1221 # Ask to mac manager 1222 os.system('open %s' % file_path) 1223 elif which(program): 1224 # shell program 1225 arguments = program.split() # Allow argument in program definition 1226 arguments.append(file_path) 1227 subprocess.call(arguments) 1228 else: 1229 # not shell program 1230 os.system('open -a %s %s' % (program, file_path))
1231
1232 -def get_HEPTools_location_setter(HEPToolsDir,type):
1233 """ Checks whether mg5dir/HEPTools/<type> (which is 'lib', 'bin' or 'include') 1234 is in the environment paths of the user. If not, it returns a preamble that 1235 sets it before calling the exectuable, for example: 1236 <preamble> ./my_exe 1237 with <preamble> -> DYLD_LIBRARY_PATH=blabla:$DYLD_LIBRARY_PATH""" 1238 1239 assert(type in ['bin','include','lib']) 1240 1241 target_env_var = 'PATH' if type in ['bin','include'] else \ 1242 ('DYLD_LIBRARY_PATH' if sys.platform=='darwin' else 'LD_LIBRARY_PATH') 1243 1244 target_path = os.path.abspath(pjoin(HEPToolsDir,type)) 1245 1246 if target_env_var not in os.environ or \ 1247 target_path not in os.environ[target_env_var].split(os.pathsep): 1248 return "%s=%s:$%s "%(target_env_var,target_path,target_env_var) 1249 else: 1250 return ''
1251
1252 -def get_shell_type():
1253 """ Try and guess what shell type does the user use.""" 1254 try: 1255 if os.environ['SHELL'].endswith('bash'): 1256 return 'bash' 1257 elif os.environ['SHELL'].endswith('tcsh'): 1258 return 'tcsh' 1259 else: 1260 # If unknown, return None 1261 return None 1262 except KeyError: 1263 return None
1264
1265 -def is_executable(path):
1266 """ check if a path is executable""" 1267 try: 1268 return os.access(path, os.X_OK) 1269 except Exception: 1270 return False
1271
1272 -class OptionParser(optparse.OptionParser):
1273 """Option Peaser which raise an error instead as calling exit""" 1274
1275 - def exit(self, status=0, msg=None):
1276 if msg: 1277 raise InvalidCmd, msg 1278 else: 1279 raise InvalidCmd
1280
1281 -def sprint(*args, **opt):
1282 """Returns the current line number in our program.""" 1283 1284 if not __debug__: 1285 return 1286 1287 use_print = False 1288 import inspect 1289 if opt.has_key('cond') and not opt['cond']: 1290 return 1291 1292 if opt.has_key('log'): 1293 log = opt['log'] 1294 else: 1295 log = logging.getLogger('madgraph') 1296 if opt.has_key('level'): 1297 level = opt['level'] 1298 else: 1299 level = logging.getLogger('madgraph').level 1300 if level == 0: 1301 use_print = True 1302 #print "madgraph level",level 1303 #if level == 20: 1304 # level = 10 #avoid info level 1305 #print "use", level 1306 if opt.has_key('wait'): 1307 wait = bool(opt['wait']) 1308 else: 1309 wait = False 1310 1311 lineno = inspect.currentframe().f_back.f_lineno 1312 fargs = inspect.getframeinfo(inspect.currentframe().f_back) 1313 filename, lineno = fargs[:2] 1314 #file = inspect.currentframe().f_back.co_filename 1315 #print type(file) 1316 try: 1317 source = inspect.getsourcelines(inspect.currentframe().f_back) 1318 line = source[0][lineno-source[1]] 1319 line = re.findall(r"misc\.sprint\(\s*(.*)\)\s*($|#)", line)[0][0] 1320 if line.startswith("'") and line.endswith("'") and line.count(",") ==0: 1321 line= '' 1322 elif line.startswith("\"") and line.endswith("\"") and line.count(",") ==0: 1323 line= '' 1324 elif line.startswith(("\"","'")) and len(args)==1 and "%" in line: 1325 line= '' 1326 except Exception: 1327 line='' 1328 1329 if line: 1330 intro = ' %s = \033[0m' % line 1331 else: 1332 intro = '' 1333 1334 1335 if not use_print: 1336 log.log(level, ' '.join([intro]+[str(a) for a in args]) + \ 1337 ' \033[1;30m[%s at line %s]\033[0m' % (os.path.basename(filename), lineno)) 1338 else: 1339 print ' '.join([intro]+[str(a) for a in args]) + \ 1340 ' \033[1;30m[%s at line %s]\033[0m' % (os.path.basename(filename), lineno) 1341 1342 if wait: 1343 raw_input('press_enter to continue') 1344 1345 return
1346
1347 ################################################################################ 1348 # function to check if two float are approximatively equal 1349 ################################################################################ 1350 -def equal(a,b,sig_fig=6, zero_limit=True):
1351 """function to check if two float are approximatively equal""" 1352 import math 1353 1354 if not a or not b: 1355 if zero_limit: 1356 power = sig_fig + 1 1357 else: 1358 return a == b 1359 else: 1360 power = sig_fig - int(math.log10(abs(a))) + 1 1361 1362 return ( a==b or abs(int(a*10**power) - int(b*10**power)) < 10)
1363
1364 ################################################################################ 1365 # class to change directory with the "with statement" 1366 # Exemple: 1367 # with chdir(path) as path: 1368 # pass 1369 ################################################################################ 1370 -class chdir:
1371 - def __init__(self, newPath):
1372 self.newPath = newPath
1373
1374 - def __enter__(self):
1375 self.savedPath = os.getcwd() 1376 os.chdir(self.newPath)
1377
1378 - def __exit__(self, etype, value, traceback):
1379 os.chdir(self.savedPath)
1380
1381 ################################################################################ 1382 # Timeout FUNCTION 1383 ################################################################################ 1384 1385 -def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
1386 '''This function will spwan a thread and run the given function using the args, kwargs and 1387 return the given default value if the timeout_duration is exceeded 1388 ''' 1389 import threading 1390 class InterruptableThread(threading.Thread): 1391 def __init__(self): 1392 threading.Thread.__init__(self) 1393 self.result = default
1394 def run(self): 1395 try: 1396 self.result = func(*args, **kwargs) 1397 except Exception,error: 1398 print error 1399 self.result = default 1400 it = InterruptableThread() 1401 it.start() 1402 it.join(timeout_duration) 1403 return it.result 1404
1405 1406 ################################################################################ 1407 # TAIL FUNCTION 1408 ################################################################################ 1409 -class digest:
1410
1411 - def test_all(self):
1412 try: 1413 return self.test_hashlib() 1414 except Exception: 1415 pass 1416 try: 1417 return self.test_md5() 1418 except Exception: 1419 pass 1420 try: 1421 return self.test_zlib() 1422 except Exception: 1423 pass
1424
1425 - def test_hashlib(self):
1426 import hashlib 1427 def digest(text): 1428 """using mg5 for the hash""" 1429 t = hashlib.md5() 1430 t.update(text) 1431 return t.hexdigest()
1432 return digest
1433
1434 - def test_md5(self):
1435 import md5 1436 def digest(text): 1437 """using mg5 for the hash""" 1438 t = md5.md5() 1439 t.update(text) 1440 return t.hexdigest()
1441 return digest 1442
1443 - def test_zlib(self):
1444 import zlib 1445 def digest(text): 1446 return zlib.adler32(text)
1447 1448 digest = digest().test_all()
1449 1450 #=============================================================================== 1451 # Helper class for timing and RAM flashing of subprocesses. 1452 #=============================================================================== 1453 -class ProcessTimer:
1454 - def __init__(self,*args,**opts):
1455 self.cmd_args = args 1456 self.cmd_opts = opts 1457 self.execution_state = False
1458
1459 - def execute(self):
1460 self.max_vms_memory = 0 1461 self.max_rss_memory = 0 1462 1463 self.t1 = None 1464 self.t0 = time.time() 1465 self.p = subprocess.Popen(*self.cmd_args,**self.cmd_opts) 1466 self.execution_state = True
1467
1468 - def poll(self):
1469 if not self.check_execution_state(): 1470 return False 1471 1472 self.t1 = time.time() 1473 # I redirect stderr to void, because from MacOX snow leopard onward, this 1474 # ps -p command writes a million times the following stupid warning 1475 # dyld: DYLD_ environment variables being ignored because main executable (/bin/ps) is setuid or setgid 1476 flash = subprocess.Popen("ps -p %i -o rss"%self.p.pid, 1477 shell=True,stdout=subprocess.PIPE,stderr=open(os.devnull,"w")) 1478 stdout_list = flash.communicate()[0].split('\n') 1479 rss_memory = int(stdout_list[1]) 1480 # for now we ignore vms 1481 vms_memory = 0 1482 1483 # This is the neat version using psutil 1484 # try: 1485 # pp = psutil.Process(self.p.pid) 1486 # 1487 # # obtain a list of the subprocess and all its descendants 1488 # descendants = list(pp.get_children(recursive=True)) 1489 # descendants = descendants + [pp] 1490 # 1491 # rss_memory = 0 1492 # vms_memory = 0 1493 # 1494 # # calculate and sum up the memory of the subprocess and all its descendants 1495 # for descendant in descendants: 1496 # try: 1497 # mem_info = descendant.get_memory_info() 1498 # 1499 # rss_memory += mem_info[0] 1500 # vms_memory += mem_info[1] 1501 # except psutil.error.NoSuchProcess: 1502 # # sometimes a subprocess descendant will have terminated between the time 1503 # # we obtain a list of descendants, and the time we actually poll this 1504 # # descendant's memory usage. 1505 # pass 1506 # 1507 # except psutil.error.NoSuchProcess: 1508 # return self.check_execution_state() 1509 1510 self.max_vms_memory = max(self.max_vms_memory,vms_memory) 1511 self.max_rss_memory = max(self.max_rss_memory,rss_memory) 1512 1513 return self.check_execution_state()
1514
1515 - def is_running(self):
1516 # Version with psutil 1517 # return psutil.pid_exists(self.p.pid) and self.p.poll() == None 1518 return self.p.poll() == None
1519
1520 - def check_execution_state(self):
1521 if not self.execution_state: 1522 return False 1523 if self.is_running(): 1524 return True 1525 self.executation_state = False 1526 self.t1 = time.time() 1527 return False
1528
1529 - def close(self,kill=False):
1530 1531 if self.p.poll() == None: 1532 if kill: 1533 self.p.kill() 1534 else: 1535 self.p.terminate()
1536 1537 # Again a neater handling with psutil 1538 # try: 1539 # pp = psutil.Process(self.p.pid) 1540 # if kill: 1541 # pp.kill() 1542 # else: 1543 # pp.terminate() 1544 # except psutil.error.NoSuchProcess: 1545 # pass 1546 1547 ## Define apple_notify (in a way which is system independent 1548 try: 1549 import Foundation 1550 import objc 1551 NSUserNotification = objc.lookUpClass('NSUserNotification') 1552 NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
1553 1554 - def apple_notify(subtitle, info_text, userInfo={}):
1555 try: 1556 notification = NSUserNotification.alloc().init() 1557 notification.setTitle_('MadGraph5_aMC@NLO') 1558 notification.setSubtitle_(subtitle) 1559 notification.setInformativeText_(info_text) 1560 notification.setUserInfo_(userInfo) 1561 NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification) 1562 except: 1563 pass
1564 except:
1565 - def apple_notify(subtitle, info_text, userInfo={}):
1566 return
1567 ## End apple notify
1568 1569 1570 -def get_older_version(v1, v2):
1571 """ return v2 if v1>v2 1572 return v1 if v1<v2 1573 return v1 if v1=v2 1574 return v1 if v2 is not in 1.2.3.4.5 format 1575 return v2 if v1 is not in 1.2.3.4.5 format 1576 """ 1577 from itertools import izip_longest 1578 for a1, a2 in izip_longest(v1, v2, fillvalue=0): 1579 try: 1580 a1= int(a1) 1581 except: 1582 return v2 1583 try: 1584 a2= int(a2) 1585 except: 1586 return v1 1587 if a1 > a2: 1588 return v2 1589 elif a1 < a2: 1590 return v1 1591 return v1
1592 1593 1594 1595 plugin_support = {}
1596 -def is_plugin_supported(obj):
1597 global plugin_support 1598 1599 name = obj.__name__ 1600 if name in plugin_support: 1601 return plugin_support[name] 1602 1603 # get MG5 version 1604 if '__mg5amcnlo__' in plugin_support: 1605 mg5_ver = plugin_support['__mg5amcnlo__'] 1606 else: 1607 info = get_pkg_info() 1608 mg5_ver = info['version'].split('.') 1609 try: 1610 min_ver = obj.minimal_mg5amcnlo_version 1611 max_ver = obj.maximal_mg5amcnlo_version 1612 val_ver = obj.latest_validated_version 1613 except: 1614 logger.error("Plugin %s misses some required info to be valid. It is therefore discarded" % name) 1615 plugin_support[name] = False 1616 return 1617 1618 if get_older_version(min_ver, mg5_ver) == min_ver and \ 1619 get_older_version(mg5_ver, max_ver) == mg5_ver: 1620 plugin_support[name] = True 1621 if get_older_version(mg5_ver, val_ver) == val_ver: 1622 logger.warning("""Plugin %s has marked as NOT being validated with this version. 1623 It has been validated for the last time with version: %s""", 1624 name, '.'.join(str(i) for i in val_ver)) 1625 else: 1626 logger.error("Plugin %s is not supported by this version of MG5aMC." % name) 1627 plugin_support[name] = False 1628 return plugin_support[name]
1629
1630 1631 #decorator 1632 -def set_global(loop=False, unitary=True, mp=False, cms=False):
1633 from functools import wraps 1634 import aloha 1635 import aloha.aloha_lib as aloha_lib 1636 def deco_set(f): 1637 @wraps(f) 1638 def deco_f_set(*args, **opt): 1639 old_loop = aloha.loop_mode 1640 old_gauge = aloha.unitary_gauge 1641 old_mp = aloha.mp_precision 1642 old_cms = aloha.complex_mass 1643 aloha.loop_mode = loop 1644 aloha.unitary_gauge = unitary 1645 aloha.mp_precision = mp 1646 aloha.complex_mass = cms 1647 aloha_lib.KERNEL.clean() 1648 try: 1649 out = f(*args, **opt) 1650 except: 1651 aloha.loop_mode = old_loop 1652 aloha.unitary_gauge = old_gauge 1653 aloha.mp_precision = old_mp 1654 aloha.complex_mass = old_cms 1655 raise 1656 aloha.loop_mode = old_loop 1657 aloha.unitary_gauge = old_gauge 1658 aloha.mp_precision = old_mp 1659 aloha.complex_mass = old_cms 1660 aloha_lib.KERNEL.clean() 1661 return out
1662 return deco_f_set 1663 return deco_set 1664 1665 1666 1667 1668 1669 1670 1671 python_lhapdf=None
1672 -def import_python_lhapdf(lhapdfconfig):
1673 """load the python module of lhapdf return None if it can not be loaded""" 1674 1675 #save the result to have it faster and avoid the segfault at the second try if lhapdf is not compatible 1676 global python_lhapdf 1677 if python_lhapdf: 1678 if python_lhapdf == -1: 1679 return None 1680 else: 1681 return python_lhapdf 1682 1683 use_lhapdf=False 1684 try: 1685 lhapdf_libdir=subprocess.Popen([lhapdfconfig,'--libdir'],\ 1686 stdout=subprocess.PIPE).stdout.read().strip() 1687 except: 1688 use_lhapdf=False 1689 return False 1690 else: 1691 try: 1692 candidates=[dirname for dirname in os.listdir(lhapdf_libdir) \ 1693 if os.path.isdir(os.path.join(lhapdf_libdir,dirname))] 1694 except OSError: 1695 candidates=[] 1696 for candidate in candidates: 1697 if os.path.isfile(os.path.join(lhapdf_libdir,candidate,'site-packages','lhapdf.so')): 1698 sys.path.insert(0,os.path.join(lhapdf_libdir,candidate,'site-packages')) 1699 try: 1700 import lhapdf 1701 use_lhapdf=True 1702 break 1703 except ImportError: 1704 sys.path.pop(0) 1705 continue 1706 if not use_lhapdf: 1707 try: 1708 candidates=[dirname for dirname in os.listdir(lhapdf_libdir+'64') \ 1709 if os.path.isdir(os.path.join(lhapdf_libdir+'64',dirname))] 1710 except OSError: 1711 candidates=[] 1712 for candidate in candidates: 1713 if os.path.isfile(os.path.join(lhapdf_libdir+'64',candidate,'site-packages','lhapdf.so')): 1714 sys.path.insert(0,os.path.join(lhapdf_libdir+'64',candidate,'site-packages')) 1715 try: 1716 import lhapdf 1717 use_lhapdf=True 1718 break 1719 except ImportError: 1720 sys.path.pop(0) 1721 continue 1722 if not use_lhapdf: 1723 try: 1724 import lhapdf 1725 use_lhapdf=True 1726 except ImportError: 1727 print 'fail' 1728 logger.warning("Failed to access python version of LHAPDF: "\ 1729 "If the python interface to LHAPDF is available on your system, try "\ 1730 "adding its location to the PYTHONPATH environment variable and the"\ 1731 "LHAPDF library location to LD_LIBRARY_PATH (linux) or DYLD_LIBRARY_PATH (mac os x).") 1732 1733 if use_lhapdf: 1734 python_lhapdf = lhapdf 1735 python_lhapdf.setVerbosity(0) 1736 else: 1737 python_lhapdf = None 1738 return python_lhapdf
1739