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