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