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