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