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