Package madgraph :: Package various :: Module misc
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.misc

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