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