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