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 #=============================================================================== 579 # mute_logger (designed to work as with statement) 580 #=============================================================================== 581 -class MuteLogger(object):
582 """mute_logger (designed to work as with statement), 583 files allow to redirect the output of the log to a given file. 584 """ 585
586 - def __init__(self, names, levels, files=None, **opt):
587 assert isinstance(names, list) 588 assert isinstance(names, list) 589 590 self.names = names 591 self.levels = levels 592 if isinstance(files, list): 593 self.files = files 594 else: 595 self.files = [files] * len(names) 596 self.logger_saved_info = {} 597 self.opts = opt
598
599 - def __enter__(self):
600 old_levels = [] 601 for name, level, path in zip(self.names, self.levels, self.files): 602 if path: 603 self.setup_logFile_for_logger(path, name, **self.opts) 604 log_module = logging.getLogger(name) 605 old_levels.append(log_module.level) 606 log_module = logging.getLogger(name) 607 log_module.setLevel(level) 608 self.levels = old_levels
609
610 - def __exit__(self, ctype, value, traceback ):
611 for name, level, path in zip(self.names, self.levels, self.files): 612 613 if path: 614 if 'keep' in self.opts and not self.opts['keep']: 615 self.restore_logFile_for_logger(name, level, path=path) 616 else: 617 self.restore_logFile_for_logger(name, level) 618 else: 619 log_module = logging.getLogger(name) 620 log_module.setLevel(level)
621
622 - def setup_logFile_for_logger(self, path, full_logname, **opts):
623 """ Setup the logger by redirecting them all to logfiles in tmp """ 624 625 logs = full_logname.split('.') 626 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\ 627 range(len(full_logname.split('.')))] 628 for logname in lognames: 629 try: 630 os.remove(path) 631 except Exception, error: 632 pass 633 my_logger = logging.getLogger(logname) 634 hdlr = logging.FileHandler(path) 635 # I assume below that the orders of the handlers in my_logger.handlers 636 # remains the same after having added/removed the FileHandler 637 self.logger_saved_info[logname] = [hdlr, my_logger.handlers] 638 #for h in my_logger.handlers: 639 # h.setLevel(logging.CRITICAL) 640 for old_hdlr in list(my_logger.handlers): 641 my_logger.removeHandler(old_hdlr) 642 my_logger.addHandler(hdlr) 643 #my_logger.setLevel(level) 644 my_logger.debug('Log of %s' % logname)
645
646 - def restore_logFile_for_logger(self, full_logname, level, path=None, **opts):
647 """ Setup the logger by redirecting them all to logfiles in tmp """ 648 649 logs = full_logname.split('.') 650 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\ 651 range(len(full_logname.split('.')))] 652 for logname in lognames: 653 if path: 654 try: 655 os.remove(path) 656 except Exception, error: 657 pass 658 my_logger = logging.getLogger(logname) 659 if logname in self.logger_saved_info: 660 my_logger.removeHandler(self.logger_saved_info[logname][0]) 661 for old_hdlr in self.logger_saved_info[logname][1]: 662 my_logger.addHandler(old_hdlr) 663 else: 664 my_logger.setLevel(level)
665 666 #for i, h in enumerate(my_logger.handlers): 667 # h.setLevel(cls.logger_saved_info[logname][2][i]) 668 669 nb_open =0
670 @contextlib.contextmanager 671 -def stdchannel_redirected(stdchannel, dest_filename):
672 """ 673 A context manager to temporarily redirect stdout or stderr 674 675 e.g.: 676 677 678 with stdchannel_redirected(sys.stderr, os.devnull): 679 if compiler.has_function('clock_gettime', libraries=['rt']): 680 libraries.append('rt') 681 """ 682 683 try: 684 oldstdchannel = os.dup(stdchannel.fileno()) 685 dest_file = open(dest_filename, 'w') 686 os.dup2(dest_file.fileno(), stdchannel.fileno()) 687 yield 688 finally: 689 if oldstdchannel is not None: 690 os.dup2(oldstdchannel, stdchannel.fileno()) 691 os.close(oldstdchannel) 692 if dest_file is not None: 693 dest_file.close()
694
695 -def get_open_fds():
696 ''' 697 return the number of open file descriptors for current process 698 699 .. warning: will only work on UNIX-like os-es. 700 ''' 701 import subprocess 702 import os 703 704 pid = os.getpid() 705 procs = subprocess.check_output( 706 [ "lsof", '-w', '-Ff', "-p", str( pid ) ] ) 707 nprocs = filter( 708 lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(), 709 procs.split( '\n' ) ) 710 711 return nprocs
712
713 -def detect_if_cpp_compiler_is_clang(cpp_compiler):
714 """ Detects whether the specified C++ compiler is clang.""" 715 716 try: 717 p = Popen([cpp_compiler, '--version'], stdout=subprocess.PIPE, 718 stderr=subprocess.PIPE) 719 output, error = p.communicate() 720 except Exception, error: 721 # Cannot probe the compiler, assume not clang then 722 return False 723 return 'LLVM' in output
724
725 -def detect_cpp_std_lib_dependence(cpp_compiler):
726 """ Detects if the specified c++ compiler will normally link against the C++ 727 standard library -lc++ or -libstdc++.""" 728 729 is_clang = detect_if_cpp_compiler_is_clang(cpp_compiler) 730 if is_clang: 731 try: 732 import platform 733 v, _,_ = platform.mac_ver() 734 if not v: 735 # We will not attempt to support clang elsewhere than on macs, so 736 # we venture a guess here. 737 return '-lc++' 738 else: 739 v = float(v.rsplit('.')[1]) 740 if v >= 9: 741 return '-lc++' 742 else: 743 return '-lstdc++' 744 except: 745 return '-lstdc++' 746 return '-lstdc++'
747
748 -def detect_current_compiler(path, compiler_type='fortran'):
749 """find the current compiler for the current directory""" 750 751 # comp = re.compile("^\s*FC\s*=\s*(\w+)\s*") 752 # The regular expression below allows for compiler definition with absolute path 753 if compiler_type == 'fortran': 754 comp = re.compile("^\s*FC\s*=\s*([\w\/\\.\-]+)\s*") 755 elif compiler_type == 'cpp': 756 comp = re.compile("^\s*CXX\s*=\s*([\w\/\\.\-]+)\s*") 757 else: 758 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type 759 760 for line in open(path): 761 if comp.search(line): 762 compiler = comp.search(line).groups()[0] 763 return compiler 764 elif compiler_type == 'fortran' and line.startswith('DEFAULT_F_COMPILER'): 765 return line.split('=')[1].strip() 766 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'): 767 return line.split('=')[1].strip()
768
769 -def find_makefile_in_dir(directory):
770 """ return a list of all file starting with makefile in the given directory""" 771 772 out=[] 773 #list mode 774 if type(directory)==list: 775 for name in directory: 776 out+=find_makefile_in_dir(name) 777 return out 778 779 #single mode 780 for name in os.listdir(directory): 781 if os.path.isdir(directory+'/'+name): 782 out+=find_makefile_in_dir(directory+'/'+name) 783 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('makefile'): 784 out.append(directory+'/'+name) 785 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('make_opt'): 786 out.append(directory+'/'+name) 787 return out
788
789 -def rm_old_compile_file():
790 791 # remove all the .o files 792 os.path.walk('.', rm_file_extension, '.o') 793 794 # remove related libraries 795 libraries = ['libblocks.a', 'libgeneric_mw.a', 'libMWPS.a', 'libtools.a', 'libdhelas3.a', 796 'libdsample.a', 'libgeneric.a', 'libmodel.a', 'libpdf.a', 'libdhelas3.so', 'libTF.a', 797 'libdsample.so', 'libgeneric.so', 'libmodel.so', 'libpdf.so'] 798 lib_pos='./lib' 799 [os.remove(os.path.join(lib_pos, lib)) for lib in libraries \ 800 if os.path.exists(os.path.join(lib_pos, lib))]
801
802 803 -def format_time(n_secs):
804 m, s = divmod(n_secs, 60) 805 h, m = divmod(m, 60) 806 d, h = divmod(h, 24) 807 if d > 0: 808 return "%d day%s,%dh%02dm%02ds" % (d,'' if d<=1 else 's',h, m, s) 809 elif h > 0: 810 return "%dh%02dm%02ds" % (h, m, s) 811 elif m > 0: 812 return "%dm%02ds" % (m, s) 813 else: 814 return "%d second%s" % (s, '' if s<=1 else 's')
815
816 -def rm_file_extension( ext, dirname, names):
817 818 [os.remove(os.path.join(dirname, name)) for name in names if name.endswith(ext)]
819
820 821 822 -def multiple_replacer(*key_values):
823 replace_dict = dict(key_values) 824 replacement_function = lambda match: replace_dict[match.group(0)] 825 pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M) 826 return lambda string: pattern.sub(replacement_function, string)
827
828 -def multiple_replace(string, *key_values):
829 return multiple_replacer(*key_values)(string)
830
831 # Control 832 -def check_system_error(value=1):
833 def deco_check(f): 834 def deco_f(arg, *args, **opt): 835 try: 836 return f(arg, *args, **opt) 837 except OSError, error: 838 logger.debug('try to recover from %s' % error) 839 if isinstance(arg, list): 840 prog = arg[0] 841 else: 842 prog = arg[0] 843 844 # Permission denied 845 if error.errno == 13: 846 if os.path.exists(prog): 847 os.system('chmod +x %s' % prog) 848 elif 'cwd' in opt and opt['cwd'] and \ 849 os.path.isfile(pjoin(opt['cwd'],arg[0])): 850 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0])) 851 return f(arg, *args, **opt) 852 # NO such file or directory 853 elif error.errno == 2: 854 # raise a more meaningfull error message 855 raise Exception, '%s fails with no such file or directory' \ 856 % arg 857 else: 858 raise
859 return deco_f 860 return deco_check 861
862 863 @check_system_error() 864 -def call(arg, *args, **opt):
865 """nice way to call an external program with nice error treatment""" 866 try: 867 return subprocess.call(arg, *args, **opt) 868 except OSError: 869 arg[0] = './%s' % arg[0] 870 return subprocess.call(arg, *args, **opt)
871
872 @check_system_error() 873 -def Popen(arg, *args, **opt):
874 """nice way to call an external program with nice error treatment""" 875 return subprocess.Popen(arg, *args, **opt)
876
877 @multiple_try() 878 -def mult_try_open(filepath, *args, **opt):
879 """try to open a file with multiple try to ensure that filesystem is sync""" 880 return open(filepath, *args, ** opt)
881
882 ################################################################################ 883 # TAIL FUNCTION 884 ################################################################################ 885 -def tail(f, n, offset=None):
886 """Reads a n lines from f with an offset of offset lines. The return 887 value is a tuple in the form ``lines``. 888 """ 889 avg_line_length = 74 890 to_read = n + (offset or 0) 891 892 while 1: 893 try: 894 f.seek(-(avg_line_length * to_read), 2) 895 except IOError: 896 # woops. apparently file is smaller than what we want 897 # to step back, go to the beginning instead 898 f.seek(0) 899 pos = f.tell() 900 lines = f.read().splitlines() 901 if len(lines) >= to_read or pos == 0: 902 return lines[-to_read:offset and -offset or None] 903 avg_line_length *= 1.3 904 avg_line_length = int(avg_line_length)
905
906 -def mkfifo(fifo_path):
907 """ makes a piping fifo (First-in First-out) file and nicely intercepts 908 error in case the file format of the target drive doesn't suppor tit.""" 909 910 try: 911 os.mkfifo(fifo_path) 912 except: 913 raise OSError('MadGraph5_aMCatNLO could not create a fifo file at:\n'+ 914 ' %s\n'%fifo_path+'Make sure that this file does not exist already'+ 915 ' and that the file format of the target drive supports fifo file (i.e not NFS).')
916
917 ################################################################################ 918 # LAST LINE FUNCTION 919 ################################################################################ 920 -def get_last_line(fsock):
921 """return the last line of a file""" 922 923 return tail(fsock, 1)[0]
924
925 -class BackRead(file):
926 """read a file returning the lines in reverse order for each call of readline() 927 This actually just reads blocks (4096 bytes by default) of data from the end of 928 the file and returns last line in an internal buffer.""" 929 930
931 - def readline(self):
932 """ readline in a backward way """ 933 934 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size): 935 self.blkcount = self.blkcount + 1 936 line = self.data[0] 937 try: 938 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 939 self.data = (self.read(self.blksize) + line).split('\n') 940 except IOError: # can't seek before the beginning of the file 941 self.seek(0) 942 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line 943 self.data = data.split('\n') 944 945 if len(self.data) == 0: 946 return "" 947 948 line = self.data.pop() 949 return line + '\n'
950
951 - def __init__(self, filepos, blksize=4096):
952 """initialize the internal structures""" 953 954 # get the file size 955 self.size = os.stat(filepos)[6] 956 # how big of a block to read from the file... 957 self.blksize = blksize 958 # how many blocks we've read 959 self.blkcount = 1 960 file.__init__(self, filepos, 'rb') 961 # if the file is smaller than the blocksize, read a block, 962 # otherwise, read the whole thing... 963 if self.size > self.blksize: 964 self.seek(-self.blksize * self.blkcount, 2) # read from end of file 965 self.data = self.read(self.blksize).split('\n') 966 # strip the last item if it's empty... a byproduct of the last line having 967 # a newline at the end of it 968 if not self.data[-1]: 969 self.data.pop()
970
971 - def next(self):
972 line = self.readline() 973 if line: 974 return line 975 else: 976 raise StopIteration
977
978 979 -def write_PS_input(filePath, PS):
980 """ Write out in file filePath the PS point to be read by the MadLoop.""" 981 try: 982 PSfile = open(filePath, 'w') 983 # Add a newline in the end as the implementation fortran 'read' 984 # command on some OS is problematic if it ends directly with the 985 # floating point number read. 986 987 PSfile.write('\n'.join([' '.join(['%.16E'%pi for pi in p]) \ 988 for p in PS])+'\n') 989 PSfile.close() 990 except Exception: 991 raise MadGraph5Error, 'Could not write out the PS point to file %s.'\ 992 %str(filePath)
993
994 -def format_timer(running_time):
995 """ return a nicely string representing the time elapsed.""" 996 if running_time < 2e-2: 997 running_time = running_time = 'current time: %02dh%02d' % (time.localtime().tm_hour, time.localtime().tm_min) 998 elif running_time < 10: 999 running_time = ' %.2gs ' % running_time 1000 elif 60 > running_time >= 10: 1001 running_time = ' %.3gs ' % running_time 1002 elif 3600 > running_time >= 60: 1003 running_time = ' %im %is ' % (running_time // 60, int(running_time % 60)) 1004 else: 1005 running_time = ' %ih %im ' % (running_time // 3600, (running_time//60 % 60)) 1006 return running_time
1007
1008 1009 #=============================================================================== 1010 # TMP_directory (designed to work as with statement) 1011 #=============================================================================== 1012 -class TMP_directory(object):
1013 """create a temporary directory and ensure this one to be cleaned. 1014 """ 1015
1016 - def __init__(self, suffix='', prefix='tmp', dir=None):
1017 self.nb_try_remove = 0 1018 import tempfile 1019 self.path = tempfile.mkdtemp(suffix, prefix, dir)
1020 1021
1022 - def __exit__(self, ctype, value, traceback ):
1023 #True only for debugging: 1024 if False and isinstance(value, Exception): 1025 sprint("Directory %s not cleaned. This directory can be removed manually" % self.path) 1026 return False 1027 try: 1028 shutil.rmtree(self.path) 1029 except OSError: 1030 self.nb_try_remove += 1 1031 if self.nb_try_remove < 3: 1032 time.sleep(10) 1033 self.__exit__(ctype, value, traceback) 1034 else: 1035 logger.warning("Directory %s not completely cleaned. This directory can be removed manually" % self.path)
1036
1037 - def __enter__(self):
1038 return self.path
1039
1040 -class TMP_variable(object):
1041 """create a temporary directory and ensure this one to be cleaned. 1042 """ 1043
1044 - def __init__(self, cls, attribute, value):
1045 1046 self.cls = cls 1047 self.attribute = attribute 1048 if isinstance(attribute, list): 1049 self.old_value = [] 1050 for key, onevalue in zip(attribute, value): 1051 self.old_value.append(getattr(cls, key)) 1052 setattr(self.cls, key, onevalue) 1053 else: 1054 self.old_value = getattr(cls, attribute) 1055 setattr(self.cls, self.attribute, value)
1056
1057 - def __exit__(self, ctype, value, traceback ):
1058 1059 if isinstance(self.attribute, list): 1060 for key, old_value in zip(self.attribute, self.old_value): 1061 setattr(self.cls, key, old_value) 1062 else: 1063 setattr(self.cls, self.attribute, self.old_value)
1064
1065 - def __enter__(self):
1066 return self.old_value
1067
1068 # 1069 # GUNZIP/GZIP 1070 # 1071 -def gunzip(path, keep=False, stdout=None):
1072 """ a standard replacement for os.system('gunzip -f %s.gz ' % event_path)""" 1073 1074 if not path.endswith(".gz"): 1075 if os.path.exists("%s.gz" % path): 1076 path = "%s.gz" % path 1077 else: 1078 raise Exception, "%(path)s does not finish by .gz and the file %(path)s.gz does not exists" %\ 1079 {"path": path} 1080 1081 1082 #for large file (>1G) it is faster and safer to use a separate thread 1083 if os.path.getsize(path) > 1e8: 1084 if stdout: 1085 os.system('gunzip -c %s > %s' % (path, stdout)) 1086 else: 1087 os.system('gunzip %s' % path) 1088 return 0 1089 1090 if not stdout: 1091 stdout = path[:-3] 1092 try: 1093 gfile = ziplib.open(path, "r") 1094 except IOError: 1095 raise 1096 else: 1097 try: 1098 open(stdout,'w').write(gfile.read()) 1099 except IOError: 1100 # this means that the file is actually not gzip 1101 if stdout == path: 1102 return 1103 else: 1104 files.cp(path, stdout) 1105 1106 if not keep: 1107 os.remove(path) 1108 return 0
1109
1110 -def gzip(path, stdout=None, error=True, forceexternal=False):
1111 """ a standard replacement for os.system('gzip %s ' % path)""" 1112 1113 #for large file (>1G) it is faster and safer to use a separate thread 1114 if os.path.getsize(path) > 1e9 or forceexternal: 1115 call(['gzip', '-f', path]) 1116 if stdout: 1117 if not stdout.endswith(".gz"): 1118 stdout = "%s.gz" % stdout 1119 shutil.move('%s.gz' % path, stdout) 1120 return 1121 1122 if not stdout: 1123 stdout = "%s.gz" % path 1124 elif not stdout.endswith(".gz"): 1125 stdout = "%s.gz" % stdout 1126 1127 try: 1128 ziplib.open(stdout,"w").write(open(path).read()) 1129 except OverflowError: 1130 gzip(path, stdout, error=error, forceexternal=True) 1131 except Exception: 1132 if error: 1133 raise 1134 else: 1135 os.remove(path)
1136
1137 # 1138 # Global function to open supported file types 1139 # 1140 -class open_file(object):
1141 """ a convinient class to open a file """ 1142 1143 web_browser = None 1144 eps_viewer = None 1145 text_editor = None 1146 configured = False 1147
1148 - def __init__(self, filename):
1149 """open a file""" 1150 1151 # Check that the class is correctly configure 1152 if not self.configured: 1153 self.configure() 1154 1155 try: 1156 extension = filename.rsplit('.',1)[1] 1157 except IndexError: 1158 extension = '' 1159 1160 1161 # dispatch method 1162 if extension in ['html','htm','php']: 1163 self.open_program(self.web_browser, filename, background=True) 1164 elif extension in ['ps','eps']: 1165 self.open_program(self.eps_viewer, filename, background=True) 1166 else: 1167 self.open_program(self.text_editor,filename, mac_check=False)
1168 # mac_check to False avoid to use open cmd in mac 1169 1170 @classmethod
1171 - def configure(cls, configuration=None):
1172 """ configure the way to open the file """ 1173 1174 cls.configured = True 1175 1176 # start like this is a configuration for mac 1177 cls.configure_mac(configuration) 1178 if sys.platform == 'darwin': 1179 return # done for MAC 1180 1181 # on Mac some default (eps/web) might be kept on None. This is not 1182 #suitable for LINUX which doesn't have open command. 1183 1184 # first for eps_viewer 1185 if not cls.eps_viewer: 1186 cls.eps_viewer = cls.find_valid(['evince','gv', 'ggv'], 'eps viewer') 1187 1188 # Second for web browser 1189 if not cls.web_browser: 1190 cls.web_browser = cls.find_valid( 1191 ['firefox', 'chrome', 'safari','opera'], 1192 'web browser')
1193 1194 @classmethod
1195 - def configure_mac(cls, configuration=None):
1196 """ configure the way to open a file for mac """ 1197 1198 if configuration is None: 1199 configuration = {'text_editor': None, 1200 'eps_viewer':None, 1201 'web_browser':None} 1202 1203 for key in configuration: 1204 if key == 'text_editor': 1205 # Treat text editor ONLY text base editor !! 1206 if configuration[key]: 1207 program = configuration[key].split()[0] 1208 if not which(program): 1209 logger.warning('Specified text editor %s not valid.' % \ 1210 configuration[key]) 1211 else: 1212 # All is good 1213 cls.text_editor = configuration[key] 1214 continue 1215 #Need to find a valid default 1216 if os.environ.has_key('EDITOR'): 1217 cls.text_editor = os.environ['EDITOR'] 1218 else: 1219 cls.text_editor = cls.find_valid( 1220 ['vi', 'emacs', 'vim', 'gedit', 'nano'], 1221 'text editor') 1222 1223 elif key == 'eps_viewer': 1224 if configuration[key]: 1225 cls.eps_viewer = configuration[key] 1226 continue 1227 # else keep None. For Mac this will use the open command. 1228 elif key == 'web_browser': 1229 if configuration[key]: 1230 cls.web_browser = configuration[key] 1231 continue
1232 # else keep None. For Mac this will use the open command. 1233 1234 @staticmethod
1235 - def find_valid(possibility, program='program'):
1236 """find a valid shell program in the list""" 1237 1238 for p in possibility: 1239 if which(p): 1240 logger.info('Using default %s \"%s\". ' % (program, p) + \ 1241 'Set another one in ./input/mg5_configuration.txt') 1242 return p 1243 1244 logger.info('No valid %s found. ' % program + \ 1245 'Please set in ./input/mg5_configuration.txt') 1246 return None
1247 1248
1249 - def open_program(self, program, file_path, mac_check=True, background=False):
1250 """ open a file with a given program """ 1251 1252 if mac_check==True and sys.platform == 'darwin': 1253 return self.open_mac_program(program, file_path) 1254 1255 # Shell program only 1256 if program: 1257 arguments = program.split() # allow argument in program definition 1258 arguments.append(file_path) 1259 1260 if not background: 1261 subprocess.call(arguments) 1262 else: 1263 import thread 1264 thread.start_new_thread(subprocess.call,(arguments,)) 1265 else: 1266 logger.warning('Not able to open file %s since no program configured.' % file_path + \ 1267 'Please set one in ./input/mg5_configuration.txt')
1268
1269 - def open_mac_program(self, program, file_path):
1270 """ open a text with the text editor """ 1271 1272 if not program: 1273 # Ask to mac manager 1274 os.system('open %s' % file_path) 1275 elif which(program): 1276 # shell program 1277 arguments = program.split() # Allow argument in program definition 1278 arguments.append(file_path) 1279 subprocess.call(arguments) 1280 else: 1281 # not shell program 1282 os.system('open -a %s %s' % (program, file_path))
1283
1284 -def get_HEPTools_location_setter(HEPToolsDir,type):
1285 """ Checks whether mg5dir/HEPTools/<type> (which is 'lib', 'bin' or 'include') 1286 is in the environment paths of the user. If not, it returns a preamble that 1287 sets it before calling the exectuable, for example: 1288 <preamble> ./my_exe 1289 with <preamble> -> DYLD_LIBRARY_PATH=blabla:$DYLD_LIBRARY_PATH""" 1290 1291 assert(type in ['bin','include','lib']) 1292 1293 target_env_var = 'PATH' if type in ['bin','include'] else \ 1294 ('DYLD_LIBRARY_PATH' if sys.platform=='darwin' else 'LD_LIBRARY_PATH') 1295 1296 target_path = os.path.abspath(pjoin(HEPToolsDir,type)) 1297 1298 if target_env_var not in os.environ or \ 1299 target_path not in os.environ[target_env_var].split(os.pathsep): 1300 return "%s=%s:$%s "%(target_env_var,target_path,target_env_var) 1301 else: 1302 return ''
1303
1304 -def get_shell_type():
1305 """ Try and guess what shell type does the user use.""" 1306 try: 1307 if os.environ['SHELL'].endswith('bash'): 1308 return 'bash' 1309 elif os.environ['SHELL'].endswith('tcsh'): 1310 return 'tcsh' 1311 else: 1312 # If unknown, return None 1313 return None 1314 except KeyError: 1315 return None
1316
1317 -def is_executable(path):
1318 """ check if a path is executable""" 1319 try: 1320 return os.access(path, os.X_OK) 1321 except Exception: 1322 return False
1323
1324 -class OptionParser(optparse.OptionParser):
1325 """Option Peaser which raise an error instead as calling exit""" 1326
1327 - def exit(self, status=0, msg=None):
1328 if msg: 1329 raise InvalidCmd, msg 1330 else: 1331 raise InvalidCmd
1332
1333 -def sprint(*args, **opt):
1334 """Returns the current line number in our program.""" 1335 1336 if not __debug__: 1337 return 1338 1339 use_print = False 1340 import inspect 1341 if opt.has_key('cond') and not opt['cond']: 1342 return 1343 1344 if opt.has_key('log'): 1345 log = opt['log'] 1346 else: 1347 log = logging.getLogger('madgraph') 1348 if opt.has_key('level'): 1349 level = opt['level'] 1350 else: 1351 level = logging.getLogger('madgraph').level 1352 if level == 0: 1353 use_print = True 1354 #print "madgraph level",level 1355 #if level == 20: 1356 # level = 10 #avoid info level 1357 #print "use", level 1358 if opt.has_key('wait'): 1359 wait = bool(opt['wait']) 1360 else: 1361 wait = False 1362 1363 lineno = inspect.currentframe().f_back.f_lineno 1364 fargs = inspect.getframeinfo(inspect.currentframe().f_back) 1365 filename, lineno = fargs[:2] 1366 #file = inspect.currentframe().f_back.co_filename 1367 #print type(file) 1368 try: 1369 source = inspect.getsourcelines(inspect.currentframe().f_back) 1370 line = source[0][lineno-source[1]] 1371 line = re.findall(r"misc\.sprint\(\s*(.*)\)\s*($|#)", line)[0][0] 1372 if line.startswith("'") and line.endswith("'") and line.count(",") ==0: 1373 line= '' 1374 elif line.startswith("\"") and line.endswith("\"") and line.count(",") ==0: 1375 line= '' 1376 elif line.startswith(("\"","'")) and len(args)==1 and "%" in line: 1377 line= '' 1378 except Exception: 1379 line='' 1380 1381 if line: 1382 intro = ' %s = \033[0m' % line 1383 else: 1384 intro = '' 1385 1386 1387 if not use_print: 1388 log.log(level, ' '.join([intro]+[str(a) for a in args]) + \ 1389 ' \033[1;30m[%s at line %s]\033[0m' % (os.path.basename(filename), lineno)) 1390 else: 1391 print ' '.join([intro]+[str(a) for a in args]) + \ 1392 ' \033[1;30m[%s at line %s]\033[0m' % (os.path.basename(filename), lineno) 1393 1394 if wait: 1395 raw_input('press_enter to continue') 1396 1397 return
1398
1399 ################################################################################ 1400 # function to check if two float are approximatively equal 1401 ################################################################################ 1402 -def equal(a,b,sig_fig=6, zero_limit=True):
1403 """function to check if two float are approximatively equal""" 1404 import math 1405 1406 if isinstance(sig_fig, int): 1407 if not a or not b: 1408 if zero_limit: 1409 if zero_limit is not True: 1410 power = zero_limit 1411 else: 1412 power = sig_fig + 1 1413 else: 1414 return a == b 1415 else: 1416 power = sig_fig - int(math.log10(abs(a))) + 1 1417 1418 return ( a==b or abs(int(a*10**power) - int(b*10**power)) < 10) 1419 else: 1420 return abs(a-b) < sig_fig
1421
1422 ################################################################################ 1423 # class to change directory with the "with statement" 1424 # Exemple: 1425 # with chdir(path) as path: 1426 # pass 1427 ################################################################################ 1428 -class chdir:
1429 - def __init__(self, newPath):
1430 self.newPath = newPath
1431
1432 - def __enter__(self):
1433 self.savedPath = os.getcwd() 1434 os.chdir(self.newPath)
1435
1436 - def __exit__(self, etype, value, traceback):
1437 os.chdir(self.savedPath)
1438
1439 ################################################################################ 1440 # Timeout FUNCTION 1441 ################################################################################ 1442 1443 -def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
1444 '''This function will spwan a thread and run the given function using the args, kwargs and 1445 return the given default value if the timeout_duration is exceeded 1446 ''' 1447 import threading 1448 class InterruptableThread(threading.Thread): 1449 def __init__(self): 1450 threading.Thread.__init__(self) 1451 self.result = default
1452 def run(self): 1453 try: 1454 self.result = func(*args, **kwargs) 1455 except Exception,error: 1456 print error 1457 self.result = default 1458 it = InterruptableThread() 1459 it.start() 1460 it.join(timeout_duration) 1461 return it.result 1462
1463 1464 ################################################################################ 1465 # TAIL FUNCTION 1466 ################################################################################ 1467 -class digest:
1468
1469 - def test_all(self):
1470 try: 1471 return self.test_hashlib() 1472 except Exception: 1473 pass 1474 try: 1475 return self.test_md5() 1476 except Exception: 1477 pass 1478 try: 1479 return self.test_zlib() 1480 except Exception: 1481 pass
1482
1483 - def test_hashlib(self):
1484 import hashlib 1485 def digest(text): 1486 """using mg5 for the hash""" 1487 t = hashlib.md5() 1488 t.update(text) 1489 return t.hexdigest()
1490 return digest
1491
1492 - def test_md5(self):
1493 import md5 1494 def digest(text): 1495 """using mg5 for the hash""" 1496 t = md5.md5() 1497 t.update(text) 1498 return t.hexdigest()
1499 return digest 1500
1501 - def test_zlib(self):
1502 import zlib 1503 def digest(text): 1504 return zlib.adler32(text)
1505 1506 digest = digest().test_all()
1507 1508 #=============================================================================== 1509 # Helper class for timing and RAM flashing of subprocesses. 1510 #=============================================================================== 1511 -class ProcessTimer:
1512 - def __init__(self,*args,**opts):
1513 self.cmd_args = args 1514 self.cmd_opts = opts 1515 self.execution_state = False
1516
1517 - def execute(self):
1518 self.max_vms_memory = 0 1519 self.max_rss_memory = 0 1520 1521 self.t1 = None 1522 self.t0 = time.time() 1523 self.p = subprocess.Popen(*self.cmd_args,**self.cmd_opts) 1524 self.execution_state = True
1525
1526 - def poll(self):
1527 if not self.check_execution_state(): 1528 return False 1529 1530 self.t1 = time.time() 1531 # I redirect stderr to void, because from MacOX snow leopard onward, this 1532 # ps -p command writes a million times the following stupid warning 1533 # dyld: DYLD_ environment variables being ignored because main executable (/bin/ps) is setuid or setgid 1534 flash = subprocess.Popen("ps -p %i -o rss"%self.p.pid, 1535 shell=True,stdout=subprocess.PIPE,stderr=open(os.devnull,"w")) 1536 stdout_list = flash.communicate()[0].split('\n') 1537 rss_memory = int(stdout_list[1]) 1538 # for now we ignore vms 1539 vms_memory = 0 1540 1541 # This is the neat version using psutil 1542 # try: 1543 # pp = psutil.Process(self.p.pid) 1544 # 1545 # # obtain a list of the subprocess and all its descendants 1546 # descendants = list(pp.get_children(recursive=True)) 1547 # descendants = descendants + [pp] 1548 # 1549 # rss_memory = 0 1550 # vms_memory = 0 1551 # 1552 # # calculate and sum up the memory of the subprocess and all its descendants 1553 # for descendant in descendants: 1554 # try: 1555 # mem_info = descendant.get_memory_info() 1556 # 1557 # rss_memory += mem_info[0] 1558 # vms_memory += mem_info[1] 1559 # except psutil.error.NoSuchProcess: 1560 # # sometimes a subprocess descendant will have terminated between the time 1561 # # we obtain a list of descendants, and the time we actually poll this 1562 # # descendant's memory usage. 1563 # pass 1564 # 1565 # except psutil.error.NoSuchProcess: 1566 # return self.check_execution_state() 1567 1568 self.max_vms_memory = max(self.max_vms_memory,vms_memory) 1569 self.max_rss_memory = max(self.max_rss_memory,rss_memory) 1570 1571 return self.check_execution_state()
1572
1573 - def is_running(self):
1574 # Version with psutil 1575 # return psutil.pid_exists(self.p.pid) and self.p.poll() == None 1576 return self.p.poll() == None
1577
1578 - def check_execution_state(self):
1579 if not self.execution_state: 1580 return False 1581 if self.is_running(): 1582 return True 1583 self.executation_state = False 1584 self.t1 = time.time() 1585 return False
1586
1587 - def close(self,kill=False):
1588 1589 if self.p.poll() == None: 1590 if kill: 1591 self.p.kill() 1592 else: 1593 self.p.terminate()
1594
1595 # Again a neater handling with psutil 1596 # try: 1597 # pp = psutil.Process(self.p.pid) 1598 # if kill: 1599 # pp.kill() 1600 # else: 1601 # pp.terminate() 1602 # except psutil.error.NoSuchProcess: 1603 # pass 1604 1605 ## Define apple_notify (in a way which is system independent 1606 -class Applenotification(object):
1607
1608 - def __init__(self):
1609 self.init = False 1610 self.working = True
1611
1612 - def load_notification(self):
1613 try: 1614 import Foundation 1615 import objc 1616 self.NSUserNotification = objc.lookUpClass('NSUserNotification') 1617 self.NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter') 1618 except: 1619 self.working=False 1620 self.working=True
1621
1622 - def __call__(self,subtitle, info_text, userInfo={}):
1623 1624 if not self.init: 1625 self.load_notification() 1626 if not self.working: 1627 return 1628 try: 1629 notification = self.NSUserNotification.alloc().init() 1630 notification.setTitle_('MadGraph5_aMC@NLO') 1631 notification.setSubtitle_(subtitle) 1632 notification.setInformativeText_(info_text) 1633 try: 1634 notification.setUserInfo_(userInfo) 1635 except: 1636 pass 1637 self.NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification) 1638 except: 1639 pass
1640 1641 1642 1643 apple_notify = Applenotification()
1644 1645 -class EasterEgg(object):
1646 1647 done_notification = False 1648 message_aprilfirst =\ 1649 {'error': ['Be careful, a cat is eating a lot of fish today. This makes the code unstable.', 1650 'Really, this sounds fishy.', 1651 '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?"', 1652 "Why does Heisenberg detest driving cars? Because, every time he looks at the speedometer he gets lost!", 1653 "May the mass times acceleration be with you.", 1654 "NOTE: This product may actually be nine-dimensional. If this is the case, functionality is not affected by the extra five dimensions.", 1655 "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.", 1656 'The fish are out of jokes. See you next year for more!'], 1657 'loading': ['Hi %(user)s, You are Loading Madgraph. Please be patient, we are doing the work.'], 1658 'quit': ['Thanks %(user)s for using MadGraph5_aMC@NLO, even on April 1st!'] 1659 } 1660
1661 - def __init__(self, msgtype):
1662 1663 try: 1664 now = time.localtime() 1665 date = now.tm_mday, now.tm_mon 1666 if date in [(1,4)]: 1667 if msgtype in EasterEgg.message_aprilfirst: 1668 choices = EasterEgg.message_aprilfirst[msgtype] 1669 if len(choices) == 0: 1670 return 1671 elif len(choices) == 1: 1672 msg = choices[0] 1673 else: 1674 import random 1675 msg = choices[random.randint(0,len(choices)-2)] 1676 EasterEgg.message_aprilfirst[msgtype].remove(msg) 1677 1678 else: 1679 return 1680 if MADEVENT: 1681 return 1682 1683 import os 1684 import pwd 1685 username =pwd.getpwuid( os.getuid() )[ 0 ] 1686 msg = msg % {'user': username} 1687 if sys.platform == "darwin": 1688 self.call_apple(msg) 1689 else: 1690 self.call_linux(msg) 1691 except Exception, error: 1692 sprint(error) 1693 pass
1694
1695 - def __call__(self, msg):
1696 try: 1697 self.call_apple(msg) 1698 except: 1699 pass
1700
1701 - def call_apple(self, msg):
1702 1703 #1. control if the volume is on or not 1704 p = subprocess.Popen("osascript -e 'get volume settings'", stdout=subprocess.PIPE, shell=True) 1705 output, _ = p.communicate() 1706 #output volume:25, input volume:71, alert volume:100, output muted:true 1707 info = dict([[a.strip() for a in l.split(':',1)] for l in output.strip().split(',')]) 1708 muted = False 1709 if 'output muted' in info and info['output muted'] == 'true': 1710 muted = True 1711 elif 'output volume' in info and info['output volume'] == '0': 1712 muted = True 1713 1714 if muted: 1715 if not EasterEgg.done_notification: 1716 apple_notify('On April first','turn up your volume!') 1717 EasterEgg.done_notification = True 1718 else: 1719 os.system('say %s' % msg)
1720 1721
1722 - def call_linux(self, msg):
1723 # check for fishing path 1724 fishPath = madgraph.MG5DIR+"/input/.cowgraph.cow" 1725 if os.path.exists(fishPath): 1726 fishPath = " -f " + fishPath 1727 #sprint("got fishPath: ",fishPath) 1728 1729 # check for fishing pole 1730 fishPole = which('cowthink') 1731 if not os.path.exists(fishPole): 1732 if os.path.exists(which('cowsay')): 1733 fishPole = which('cowsay') 1734 else: 1735 return 1736 1737 # go fishing 1738 fishCmd = fishPole + fishPath + " " + msg 1739 os.system(fishCmd)
1740 1741 1742 if __debug__: 1743 try: 1744 import os 1745 import pwd 1746 username =pwd.getpwuid( os.getuid() )[ 0 ] 1747 if 'hirschi' in username or 'vryonidou' in username and __debug__: 1748 EasterEgg('loading') 1749 except: 1750 pass
1751 1752 1753 -def get_older_version(v1, v2):
1754 """ return v2 if v1>v2 1755 return v1 if v1<v2 1756 return v1 if v1=v2 1757 return v1 if v2 is not in 1.2.3.4.5 format 1758 return v2 if v1 is not in 1.2.3.4.5 format 1759 """ 1760 from itertools import izip_longest 1761 for a1, a2 in izip_longest(v1, v2, fillvalue=0): 1762 try: 1763 a1= int(a1) 1764 except: 1765 return v2 1766 try: 1767 a2= int(a2) 1768 except: 1769 return v1 1770 if a1 > a2: 1771 return v2 1772 elif a1 < a2: 1773 return v1 1774 return v1
1775 1776 1777 1778 plugin_support = {}
1779 -def is_plugin_supported(obj):
1780 global plugin_support 1781 1782 name = obj.__name__ 1783 if name in plugin_support: 1784 return plugin_support[name] 1785 1786 # get MG5 version 1787 if '__mg5amcnlo__' in plugin_support: 1788 mg5_ver = plugin_support['__mg5amcnlo__'] 1789 else: 1790 info = get_pkg_info() 1791 mg5_ver = info['version'].split('.') 1792 try: 1793 min_ver = obj.minimal_mg5amcnlo_version 1794 max_ver = obj.maximal_mg5amcnlo_version 1795 val_ver = obj.latest_validated_version 1796 except: 1797 logger.error("Plugin %s misses some required info to be valid. It is therefore discarded" % name) 1798 plugin_support[name] = False 1799 return 1800 1801 if get_older_version(min_ver, mg5_ver) == min_ver and \ 1802 get_older_version(mg5_ver, max_ver) == mg5_ver: 1803 plugin_support[name] = True 1804 if get_older_version(mg5_ver, val_ver) == val_ver: 1805 logger.warning("""Plugin %s has marked as NOT being validated with this version. 1806 It has been validated for the last time with version: %s""", 1807 name, '.'.join(str(i) for i in val_ver)) 1808 else: 1809 if __debug__: 1810 logger.error("Plugin %s seems not supported by this version of MG5aMC. Keep it active (please update status)" % name) 1811 plugin_support[name] = True 1812 else: 1813 logger.error("Plugin %s is not supported by this version of MG5aMC." % name) 1814 plugin_support[name] = False 1815 return plugin_support[name]
1816
1817 1818 #decorator 1819 -def set_global(loop=False, unitary=True, mp=False, cms=False):
1820 from functools import wraps 1821 import aloha 1822 import aloha.aloha_lib as aloha_lib 1823 def deco_set(f): 1824 @wraps(f) 1825 def deco_f_set(*args, **opt): 1826 old_loop = aloha.loop_mode 1827 old_gauge = aloha.unitary_gauge 1828 old_mp = aloha.mp_precision 1829 old_cms = aloha.complex_mass 1830 aloha.loop_mode = loop 1831 aloha.unitary_gauge = unitary 1832 aloha.mp_precision = mp 1833 aloha.complex_mass = cms 1834 aloha_lib.KERNEL.clean() 1835 try: 1836 out = f(*args, **opt) 1837 except: 1838 aloha.loop_mode = old_loop 1839 aloha.unitary_gauge = old_gauge 1840 aloha.mp_precision = old_mp 1841 aloha.complex_mass = old_cms 1842 raise 1843 aloha.loop_mode = old_loop 1844 aloha.unitary_gauge = old_gauge 1845 aloha.mp_precision = old_mp 1846 aloha.complex_mass = old_cms 1847 aloha_lib.KERNEL.clean() 1848 return out
1849 return deco_f_set 1850 return deco_set 1851
1852 1853 1854 1855 -def plugin_import(module, error_msg, fcts=[]):
1856 """convenient way to import a plugin file/function""" 1857 1858 try: 1859 _temp = __import__('PLUGIN.%s' % module, globals(), locals(), fcts, -1) 1860 except ImportError: 1861 try: 1862 _temp = __import__('MG5aMC_PLUGIN.%s' % module, globals(), locals(), fcts, -1) 1863 except ImportError: 1864 raise MadGraph5Error, error_msg 1865 1866 if not fcts: 1867 return _temp 1868 elif len(fcts) == 1: 1869 return getattr(_temp,fcts[0]) 1870 else: 1871 return [getattr(_temp,name) for name in fcts]
1872
1873 -def from_plugin_import(plugin_path, target_type, keyname=None, warning=False, 1874 info=None):
1875 """return the class associated with keyname for a given plugin class 1876 if keyname is None, return all the name associated""" 1877 1878 validname = [] 1879 for plugpath in plugin_path: 1880 plugindirname = os.path.basename(plugpath) 1881 for plug in os.listdir(plugpath): 1882 if os.path.exists(pjoin(plugpath, plug, '__init__.py')): 1883 try: 1884 with stdchannel_redirected(sys.stdout, os.devnull): 1885 __import__('%s.%s' % (plugindirname,plug)) 1886 except Exception, error: 1887 if warning: 1888 logger.warning("error detected in plugin: %s.", plug) 1889 logger.warning("%s", error) 1890 continue 1891 plugin = sys.modules['%s.%s' % (plugindirname,plug)] 1892 if hasattr(plugin, target_type): 1893 if not is_plugin_supported(plugin): 1894 continue 1895 if keyname is None: 1896 validname += getattr(plugin, target_type).keys() 1897 else: 1898 if keyname in getattr(plugin, target_type): 1899 if not info: 1900 logger.info('Using from plugin %s mode %s' % (plug, keyname), '$MG:color:BLACK') 1901 else: 1902 logger.info(info % {'plug': plug, 'key':keyname}, '$MG:color:BLACK') 1903 return getattr(plugin, target_type)[keyname] 1904 1905 if not keyname: 1906 return validname
1907 1908 1909 1910 1911 python_lhapdf=None
1912 -def import_python_lhapdf(lhapdfconfig):
1913 """load the python module of lhapdf return None if it can not be loaded""" 1914 1915 #save the result to have it faster and avoid the segfault at the second try if lhapdf is not compatible 1916 global python_lhapdf 1917 if python_lhapdf: 1918 if python_lhapdf == -1: 1919 return None 1920 else: 1921 return python_lhapdf 1922 1923 use_lhapdf=False 1924 try: 1925 lhapdf_libdir=subprocess.Popen([lhapdfconfig,'--libdir'],\ 1926 stdout=subprocess.PIPE).stdout.read().strip() 1927 except: 1928 use_lhapdf=False 1929 return False 1930 else: 1931 try: 1932 candidates=[dirname for dirname in os.listdir(lhapdf_libdir) \ 1933 if os.path.isdir(os.path.join(lhapdf_libdir,dirname))] 1934 except OSError: 1935 candidates=[] 1936 for candidate in candidates: 1937 if os.path.isfile(os.path.join(lhapdf_libdir,candidate,'site-packages','lhapdf.so')): 1938 sys.path.insert(0,os.path.join(lhapdf_libdir,candidate,'site-packages')) 1939 try: 1940 import lhapdf 1941 use_lhapdf=True 1942 break 1943 except ImportError: 1944 sys.path.pop(0) 1945 continue 1946 if not use_lhapdf: 1947 try: 1948 candidates=[dirname for dirname in os.listdir(lhapdf_libdir+'64') \ 1949 if os.path.isdir(os.path.join(lhapdf_libdir+'64',dirname))] 1950 except OSError: 1951 candidates=[] 1952 for candidate in candidates: 1953 if os.path.isfile(os.path.join(lhapdf_libdir+'64',candidate,'site-packages','lhapdf.so')): 1954 sys.path.insert(0,os.path.join(lhapdf_libdir+'64',candidate,'site-packages')) 1955 try: 1956 import lhapdf 1957 use_lhapdf=True 1958 break 1959 except ImportError: 1960 sys.path.pop(0) 1961 continue 1962 if not use_lhapdf: 1963 try: 1964 import lhapdf 1965 use_lhapdf=True 1966 except ImportError: 1967 print 'fail' 1968 logger.warning("Failed to access python version of LHAPDF: "\ 1969 "If the python interface to LHAPDF is available on your system, try "\ 1970 "adding its location to the PYTHONPATH environment variable and the"\ 1971 "LHAPDF library location to LD_LIBRARY_PATH (linux) or DYLD_LIBRARY_PATH (mac os x).") 1972 1973 if use_lhapdf: 1974 python_lhapdf = lhapdf 1975 python_lhapdf.setVerbosity(0) 1976 else: 1977 python_lhapdf = None 1978 return python_lhapdf
1979
1980 -def newtonmethod(f, df, x0, error=1e-10,maxiter=10000):
1981 """implement newton method for solving f(x)=0, df is the derivate""" 1982 x = x0 1983 iter=0 1984 while abs(f(x)) > error: 1985 iter+=1 1986 x = x - f(x)/df(x) 1987 if iter ==maxiter: 1988 sprint('fail to solve equation') 1989 raise Exception 1990 return x
1991 1992 1993 1994 ############################### TRACQER FOR OPEN FILE 1995 #openfiles = set() 1996 #oldfile = __builtin__.file 1997 # 1998 #class newfile(oldfile): 1999 # done = 0 2000 # def __init__(self, *args): 2001 # self.x = args[0] 2002 # if 'matplotlib' in self.x: 2003 # raise Exception 2004 # print "### OPENING %s ### %s " % (str(self.x) , time.time()-start) 2005 # oldfile.__init__(self, *args) 2006 # openfiles.add(self) 2007 # 2008 # def close(self): 2009 # print "### CLOSING %s ### %s" % (str(self.x), time.time()-start) 2010 # oldfile.close(self) 2011 # openfiles.remove(self) 2012 #oldopen = __builtin__.open 2013 #def newopen(*args): 2014 # return newfile(*args) 2015 #__builtin__.file = newfile 2016 #__builtin__.open = newopen 2017