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