1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """A set of functions performing routine administrative I/O tasks."""
17
18 import contextlib
19 import logging
20 import os
21 import re
22 import signal
23 import subprocess
24 import sys
25 import StringIO
26 import sys
27 import optparse
28 import time
29 import shutil
30 import traceback
31 import gzip as ziplib
32
33 try:
34
35 import madgraph
36 except Exception, error:
37
38 import internal
39 from internal import MadGraph5Error, InvalidCmd
40 import internal.files as files
41 MADEVENT = True
42 else:
43 from madgraph import MadGraph5Error, InvalidCmd
44 import madgraph.iolibs.files as files
45 MADEVENT = False
46
47
48
49 logger = logging.getLogger('cmdprint.ext_program')
50 logger_stderr = logging.getLogger('madevent.misc')
51 pjoin = os.path.join
59 """ Check the consistency of the mg5amc_py8_interface installed with
60 the current MG5 and Pythia8 versions. """
61
62 return None
63
64 if not options['pythia8_path']:
65 return None
66
67 if not options['mg5amc_py8_interface_path']:
68 return \
69 """
70 A Pythia8 path is specified via the option 'pythia8_path' but no path for option
71 'mg5amc_py8_interface_path' is specified. This means that Pythia8 cannot be used
72 leading order simulations with MadEvent.
73 Consider installing the MG5_aMC-PY8 interface with the following command:
74 MG5_aMC>install mg5amc_py8_interface
75 """
76
77
78 MG5_version_on_install = open(pjoin(options['mg5amc_py8_interface_path'],
79 'MG5AMC_VERSION_ON_INSTALL')).read().replace('\n','')
80 if MG5_version_on_install == 'UNSPECIFIED':
81 MG5_version_on_install = None
82 PY8_version_on_install = open(pjoin(options['mg5amc_py8_interface_path'],
83 'PYTHIA8_VERSION_ON_INSTALL')).read().replace('\n','')
84 MG5_curr_version = get_pkg_info()['version']
85 try:
86 p = subprocess.Popen(['./get_pythia8_version.py',options['pythia8_path']],
87 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
88 cwd=options['mg5amc_py8_interface_path'])
89 (out, err) = p.communicate()
90 out = out.replace('\n','')
91 PY8_curr_version = out
92
93
94 float(out)
95 except:
96 PY8_curr_version = None
97
98 if not MG5_version_on_install is None and not MG5_curr_version is None:
99 if MG5_version_on_install != MG5_curr_version:
100 return \
101 """
102 The current version of MG5_aMC (v%s) is different than the one active when
103 installing the 'mg5amc_py8_interface_path' (which was MG5aMC v%s).
104 Please consider refreshing the installation of this interface with the command:
105 MG5_aMC>install mg5amc_py8_interface
106 """%(MG5_curr_version, MG5_version_on_install)
107
108 if not PY8_version_on_install is None and not PY8_curr_version is None:
109 if PY8_version_on_install != PY8_curr_version:
110 return \
111 """
112 The current version of Pythia8 (v%s) is different than the one active when
113 installing the 'mg5amc_py8_interface' tool (which was Pythia8 v%s).
114 Please consider refreshing the installation of this interface with the command:
115 MG5_aMC>install mg5amc_py8_interface
116 """%(PY8_curr_version,PY8_version_on_install)
117
118 return None
119
126 """Parse a newline separated list of "param=value" as a dictionnary
127 """
128
129 info_dict = {}
130 pattern = re.compile("(?P<name>\w*)\s*=\s*(?P<value>.*)",
131 re.IGNORECASE | re.VERBOSE)
132 for entry in fsock:
133 entry = entry.strip()
134 if len(entry) == 0: continue
135 m = pattern.match(entry)
136 if m is not None:
137 info_dict[m.group('name')] = m.group('value')
138 else:
139 raise IOError, "String %s is not a valid info string" % entry
140
141 return info_dict
142
143
144 -def glob(name, path=''):
145 """call to glob.glob with automatic security on path"""
146 import glob as glob_module
147 path = re.sub('(?P<name>\?|\*|\[|\])', '[\g<name>]', path)
148 return glob_module.glob(pjoin(path, name))
149
150
151
152
153 -def mute_logger(names=['madgraph','ALOHA','cmdprint','madevent'], levels=[50,50,50,50]):
154 """change the logger level and restore those at their initial value at the
155 end of the function decorated."""
156 def control_logger(f):
157 def restore_old_levels(names, levels):
158 for name, level in zip(names, levels):
159 log_module = logging.getLogger(name)
160 log_module.setLevel(level)
161
162 def f_with_no_logger(self, *args, **opt):
163 old_levels = []
164 for name, level in zip(names, levels):
165 log_module = logging.getLogger(name)
166 old_levels.append(log_module.level)
167 log_module.setLevel(level)
168 try:
169 out = f(self, *args, **opt)
170 restore_old_levels(names, old_levels)
171 return out
172 except:
173 restore_old_levels(names, old_levels)
174 raise
175
176 return f_with_no_logger
177 return control_logger
178
183 """Returns the current version information of the MadGraph5_aMC@NLO package,
184 as written in the VERSION text file. If the file cannot be found,
185 a dictionary with empty values is returned. As an option, an info
186 string can be passed to be read instead of the file content.
187 """
188
189 if info_str:
190 info_dict = parse_info_str(StringIO.StringIO(info_str))
191
192 elif MADEVENT:
193 info_dict ={}
194 info_dict['version'] = open(pjoin(internal.__path__[0],'..','..','MGMEVersion.txt')).read().strip()
195 info_dict['date'] = '20xx-xx-xx'
196 else:
197 info_dict = files.read_from_file(os.path.join(madgraph.__path__[0],
198 "VERSION"),
199 parse_info_str,
200 print_error=False)
201
202 return info_dict
203
208 """Returns the present time info for use in MG5 command history header.
209 """
210
211 creation_time = time.asctime()
212 time_info = {'time': creation_time,
213 'fill': ' ' * (26 - len(creation_time))}
214
215 return time_info
216
221 """Browse the subdirectories of the path 'start_path' and returns the first
222 one found which contains at least one file ending with the string extension
223 given in argument."""
224
225 subdirs=[pjoin(start_path,dir) for dir in os.listdir(start_path)]
226 for subdir in subdirs:
227 if os.path.isfile(subdir):
228 if os.path.basename(subdir).endswith(extension):
229 return start_path
230 elif os.path.isdir(subdir):
231 path = find_includes_path(subdir, extension)
232 if path:
233 return path
234 return None
235
241 """ Get whether ninja supports quad prec in different ways"""
242
243
244 ninja_config = os.path.abspath(pjoin(
245 ninja_lib_path,os.pardir,'bin','ninja-config'))
246 if os.path.exists(ninja_config):
247 try:
248 p = Popen([ninja_config, '-quadsupport'], stdout=subprocess.PIPE,
249 stderr=subprocess.PIPE)
250 output, error = p.communicate()
251 return 'TRUE' in output.upper()
252 except Exception:
253 pass
254
255
256
257 return False
258
259
260
261
262 -def which(program):
263 def is_exe(fpath):
264 return os.path.exists(fpath) and os.access(\
265 os.path.realpath(fpath), os.X_OK)
266
267 if not program:
268 return None
269
270 fpath, fname = os.path.split(program)
271 if fpath:
272 if is_exe(program):
273 return program
274 else:
275 for path in os.environ["PATH"].split(os.pathsep):
276 exe_file = os.path.join(path, program)
277 if is_exe(exe_file):
278 return exe_file
279 return None
280
296
302 """ Make sure to turn off some dependency of MG5aMC. """
303
304 def tell(msg):
305 if log == 'stdout':
306 print msg
307 elif callable(log):
308 log(msg)
309
310
311 if dependency in ['pjfry','golem','samurai','ninja']:
312 if cmd.options[dependency] not in ['None',None,'']:
313 tell("Deactivating MG5_aMC dependency '%s'"%dependency)
314 cmd.options[dependency] = None
315
317 """ Checks whether the specfieid MG dependency can be activated if it was
318 not turned off in MG5 options."""
319
320 def tell(msg):
321 if log == 'stdout':
322 print msg
323 elif callable(log):
324 log(msg)
325
326 if cmd is None:
327 cmd = MGCmd.MasterCmd()
328
329 if dependency=='pjfry':
330 if cmd.options['pjfry'] in ['None',None,''] or \
331 (cmd.options['pjfry'] == 'auto' and which_lib('libpjfry.a') is None) or\
332 which_lib(pjoin(cmd.options['pjfry'],'libpjfry.a')) is None:
333 tell("Installing PJFry...")
334 cmd.do_install('PJFry')
335
336 if dependency=='golem':
337 if cmd.options['golem'] in ['None',None,''] or\
338 (cmd.options['golem'] == 'auto' and which_lib('libgolem.a') is None) or\
339 which_lib(pjoin(cmd.options['golem'],'libgolem.a')) is None:
340 tell("Installing Golem95...")
341 cmd.do_install('Golem95')
342
343 if dependency=='samurai':
344 raise MadGraph5Error, 'Samurai cannot yet be automatically installed.'
345
346 if dependency=='ninja':
347 if cmd.options['ninja'] in ['None',None,''] or\
348 (cmd.options['ninja'] == './HEPTools/lib' and not MG5dir is None and\
349 which_lib(pjoin(MG5dir,cmd.options['ninja'],'libninja.a')) is None):
350 tell("Installing ninja...")
351 cmd.do_install('ninja')
352
357 def is_lib(fpath):
358 return os.path.exists(fpath) and os.access(fpath, os.R_OK)
359
360 if not lib:
361 return None
362
363 fpath, fname = os.path.split(lib)
364 if fpath:
365 if is_lib(lib):
366 return lib
367 else:
368 locations = sum([os.environ[env_path].split(os.pathsep) for env_path in
369 ["DYLD_LIBRARY_PATH","LD_LIBRARY_PATH","LIBRARY_PATH","PATH"]
370 if env_path in os.environ],[])
371 for path in locations:
372 lib_file = os.path.join(path, lib)
373 if is_lib(lib_file):
374 return lib_file
375 return None
376
381 """ Return nice information on the current variable """
382
383
384 info = [('type',type(var)),('str', var)]
385 if hasattr(var, 'func_doc'):
386 info.append( ('DOC', var.func_doc) )
387 if hasattr(var, '__doc__'):
388 info.append( ('DOC', var.__doc__) )
389 if hasattr(var, '__dict__'):
390 info.append( ('ATTRIBUTE', var.__dict__.keys() ))
391
392 spaces = ' ' * nb_space
393
394 outstr=''
395 for name, value in info:
396 outstr += '%s%3s : %s\n' % (spaces,name, value)
397
398 return outstr
399
400
401
402
403 wait_once = False
405
406 def deco_retry(f):
407 def deco_f_retry(*args, **opt):
408 for i in range(nb_try):
409 try:
410 return f(*args, **opt)
411 except KeyboardInterrupt:
412 raise
413 except Exception, error:
414 global wait_once
415 if not wait_once:
416 text = """Start waiting for update. (more info in debug mode)"""
417 logger.info(text)
418 logger_stderr.debug('fail to do %s function with %s args. %s try on a max of %s (%s waiting time)' %
419 (str(f), ', '.join([str(a) for a in args]), i+1, nb_try, sleep * (i+1)))
420 logger_stderr.debug('error is %s' % str(error))
421 if __debug__: logger_stderr.debug('and occurred at :'+traceback.format_exc())
422 wait_once = True
423 time.sleep(sleep * (i+1))
424
425 if __debug__:
426 raise
427 raise error.__class__, '[Fail %i times] \n %s ' % (i+1, error)
428 return deco_f_retry
429 return deco_retry
430
435 """return a name of the type xxxx[A-B]yyy
436 where xxx and yyy are the common part between the two names.
437 """
438
439
440 base = [first[i] for i in range(len(first)) if first[:i+1] == last[:i+1]]
441
442 while base and base[0].isdigit():
443 base = base[1:]
444
445 end = [first[-(i+1)] for i in range(len(first)) if first[-(i+1):] == last[-(i+1):]]
446
447 while end and end[-1].isdigit():
448 end = end[:-1]
449 end.reverse()
450
451 base, end = ''.join(base), ''.join(end)
452 if end:
453 name = "%s[%s-%s]%s" % (base, first[len(base):-len(end)], last[len(base):-len(end)],end)
454 else:
455 name = "%s[%s-%s]%s" % (base, first[len(base):], last[len(base):],end)
456 return name
457
458
459
460
461 -def compile(arg=[], cwd=None, mode='fortran', job_specs = True, nb_core=1 ,**opt):
462 """compile a given directory"""
463
464 if 'nocompile' in opt:
465 if opt['nocompile'] == True:
466 if not arg:
467 return
468 if cwd:
469 executable = pjoin(cwd, arg[0])
470 else:
471 executable = arg[0]
472 if os.path.exists(executable):
473 return
474 del opt['nocompile']
475
476 cmd = ['make']
477 try:
478 if nb_core > 1:
479 cmd.append('-j%s' % nb_core)
480 cmd += arg
481 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
482 stderr=subprocess.STDOUT, cwd=cwd, **opt)
483 (out, err) = p.communicate()
484 except OSError, error:
485 if cwd and not os.path.exists(cwd):
486 raise OSError, 'Directory %s doesn\'t exists. Impossible to run make' % cwd
487 else:
488 error_text = "Impossible to compile %s directory\n" % cwd
489 error_text += "Trying to launch make command returns:\n"
490 error_text += " " + str(error) + "\n"
491 error_text += "In general this means that your computer is not able to compile."
492 if sys.platform == "darwin":
493 error_text += "Note that MacOSX doesn\'t have gmake/gfortan install by default.\n"
494 error_text += "Xcode3 contains those required programs"
495 raise MadGraph5Error, error_text
496
497 if p.returncode:
498
499 if not cwd:
500 cwd = os.getcwd()
501 all_file = [f.lower() for f in os.listdir(cwd)]
502 if 'makefile' not in all_file:
503 raise OSError, 'no makefile present in %s' % os.path.realpath(cwd)
504
505 if mode == 'fortran' and not (which('g77') or which('gfortran')):
506 error_msg = 'A fortran compiler (g77 or gfortran) is required to create this output.\n'
507 error_msg += 'Please install g77 or gfortran on your computer and retry.'
508 raise MadGraph5Error, error_msg
509 elif mode == 'cpp' and not which('g++'):
510 error_msg ='A C++ compiler (g++) is required to create this output.\n'
511 error_msg += 'Please install g++ (which is part of the gcc package) on your computer and retry.'
512 raise MadGraph5Error, error_msg
513
514
515 if any(tag.upper() in out.upper() for tag in ['real(kind=16)','real*16',
516 'complex*32']) and mode == 'fortran' and not \
517 ''.join(get_gfortran_version().split('.')) >= '46':
518 if not which('gfortran'):
519 raise MadGraph5Error, 'The fortran compiler gfortran v4.6 or later '+\
520 'is required to compile %s.\nPlease install it and retry.'%cwd
521 else:
522 logger_stderr.error('ERROR, you could not compile %s because'%cwd+\
523 ' your version of gfortran is older than 4.6. MadGraph5_aMC@NLO will carry on,'+\
524 ' but will not be able to compile an executable.')
525 return p.returncode
526
527 error_text = 'A compilation Error occurs '
528 if cwd:
529 error_text += 'when trying to compile %s.\n' % cwd
530 error_text += 'The compilation fails with the following output message:\n'
531 error_text += ' '+out.replace('\n','\n ')+'\n'
532 error_text += 'Please try to fix this compilations issue and retry.\n'
533 error_text += 'Help might be found at https://answers.launchpad.net/mg5amcnlo.\n'
534 error_text += 'If you think that this is a bug, you can report this at https://bugs.launchpad.net/mg5amcnlo'
535 raise MadGraph5Error, error_text
536 return p.returncode
537
539 """ Returns the gfortran version as a string.
540 Returns '0' if it failed."""
541 try:
542 p = Popen([compiler, '-dumpversion'], stdout=subprocess.PIPE,
543 stderr=subprocess.PIPE)
544 output, error = p.communicate()
545 version_finder=re.compile(r"(?P<version>(\d.)*\d)")
546 version = version_finder.search(output).group('version')
547 return version
548 except Exception:
549 return '0'
550
551 -def mod_compilator(directory, new='gfortran', current=None, compiler_type='gfortran'):
552
553 if type(directory)!=list:
554 directory=[directory]
555
556
557 file_to_change=find_makefile_in_dir(directory)
558 if compiler_type == 'gfortran':
559 comp_re = re.compile('^(\s*)FC\s*=\s*(.+)\s*$')
560 var = 'FC'
561 elif compiler_type == 'cpp':
562 comp_re = re.compile('^(\s*)CXX\s*=\s*(.+)\s*$')
563 var = 'CXX'
564 else:
565 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type
566
567 mod = False
568 for name in file_to_change:
569 lines = open(name,'r').read().split('\n')
570 for iline, line in enumerate(lines):
571 result = comp_re.match(line)
572 if result:
573 if new != result.group(2) and '$' not in result.group(2):
574 mod = True
575 lines[iline] = result.group(1) + var + "=" + new
576 elif compiler_type == 'gfortran' and line.startswith('DEFAULT_F_COMPILER'):
577 lines[iline] = "DEFAULT_F_COMPILER = %s" % new
578 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'):
579 lines[iline] = "DEFAULT_CPP_COMPILER = %s" % new
580
581 if mod:
582 open(name,'w').write('\n'.join(lines))
583
584 mod = False
585
590 """mute_logger (designed to work as with statement),
591 files allow to redirect the output of the log to a given file.
592 """
593
594 - def __init__(self, names, levels, files=None, **opt):
595 assert isinstance(names, list)
596 assert isinstance(names, list)
597
598 self.names = names
599 self.levels = levels
600 if isinstance(files, list):
601 self.files = files
602 else:
603 self.files = [files] * len(names)
604 self.logger_saved_info = {}
605 self.opts = opt
606
617
618 - def __exit__(self, ctype, value, traceback ):
627
629 """ Setup the logger by redirecting them all to logfiles in tmp """
630
631 logs = full_logname.split('.')
632 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\
633 range(len(full_logname.split('.')))]
634 for logname in lognames:
635 try:
636 os.remove(path)
637 except Exception, error:
638 pass
639 my_logger = logging.getLogger(logname)
640 hdlr = logging.FileHandler(path)
641
642
643 self.logger_saved_info[logname] = [hdlr, my_logger.handlers]
644
645
646 for old_hdlr in list(my_logger.handlers):
647 my_logger.removeHandler(old_hdlr)
648 my_logger.addHandler(hdlr)
649
650 my_logger.debug('Log of %s' % logname)
651
653 """ Setup the logger by redirecting them all to logfiles in tmp """
654
655 logs = full_logname.split('.')
656 lognames = [ '.'.join(logs[:(len(logs)-i)]) for i in\
657 range(len(full_logname.split('.')))]
658 for logname in lognames:
659 if path:
660 try:
661 os.remove(path)
662 except Exception, error:
663 pass
664 my_logger = logging.getLogger(logname)
665 if logname in self.logger_saved_info:
666 my_logger.removeHandler(self.logger_saved_info[logname][0])
667 for old_hdlr in self.logger_saved_info[logname][1]:
668 my_logger.addHandler(old_hdlr)
669 else:
670 my_logger.setLevel(level)
671
672
673
674
675 nb_open =0
678 """
679 A context manager to temporarily redirect stdout or stderr
680
681 e.g.:
682
683
684 with stdchannel_redirected(sys.stderr, os.devnull):
685 if compiler.has_function('clock_gettime', libraries=['rt']):
686 libraries.append('rt')
687 """
688
689 try:
690 oldstdchannel = os.dup(stdchannel.fileno())
691 dest_file = open(dest_filename, 'w')
692 os.dup2(dest_file.fileno(), stdchannel.fileno())
693 yield
694 finally:
695 if oldstdchannel is not None:
696 os.dup2(oldstdchannel, stdchannel.fileno())
697 os.close(oldstdchannel)
698 if dest_file is not None:
699 dest_file.close()
700
702 '''
703 return the number of open file descriptors for current process
704
705 .. warning: will only work on UNIX-like os-es.
706 '''
707 import subprocess
708 import os
709
710 pid = os.getpid()
711 procs = subprocess.check_output(
712 [ "lsof", '-w', '-Ff', "-p", str( pid ) ] )
713 nprocs = filter(
714 lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(),
715 procs.split( '\n' ) )
716
717 return nprocs
718
720 """ Detects whether the specified C++ compiler is clang."""
721
722 try:
723 p = Popen([cpp_compiler, '--version'], stdout=subprocess.PIPE,
724 stderr=subprocess.PIPE)
725 output, error = p.communicate()
726 except Exception, error:
727
728 return False
729 return 'LLVM' in output
730
732 """ Detects if the specified c++ compiler will normally link against the C++
733 standard library -lc++ or -libstdc++."""
734
735 is_clang = detect_if_cpp_compiler_is_clang(cpp_compiler)
736 if is_clang:
737 try:
738 import platform
739 v, _,_ = platform.mac_ver()
740 if not v:
741
742
743 return '-lc++'
744 else:
745 v = float(v.rsplit('.')[1])
746 if v >= 9:
747 return '-lc++'
748 else:
749 return '-lstdc++'
750 except:
751 return '-lstdc++'
752 return '-lstdc++'
753
755 """find the current compiler for the current directory"""
756
757
758
759 if compiler_type == 'fortran':
760 comp = re.compile("^\s*FC\s*=\s*([\w\/\\.\-]+)\s*")
761 elif compiler_type == 'cpp':
762 comp = re.compile("^\s*CXX\s*=\s*([\w\/\\.\-]+)\s*")
763 else:
764 MadGraph5Error, 'Unknown compiler type: %s' % compiler_type
765
766 for line in open(path):
767 if comp.search(line):
768 compiler = comp.search(line).groups()[0]
769 return compiler
770 elif compiler_type == 'fortran' and line.startswith('DEFAULT_F_COMPILER'):
771 return line.split('=')[1].strip()
772 elif compiler_type == 'cpp' and line.startswith('DEFAULT_CPP_COMPILER'):
773 return line.split('=')[1].strip()
774
776 """ return a list of all file starting with makefile in the given directory"""
777
778 out=[]
779
780 if type(directory)==list:
781 for name in directory:
782 out+=find_makefile_in_dir(name)
783 return out
784
785
786 for name in os.listdir(directory):
787 if os.path.isdir(directory+'/'+name):
788 out+=find_makefile_in_dir(directory+'/'+name)
789 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('makefile'):
790 out.append(directory+'/'+name)
791 elif os.path.isfile(directory+'/'+name) and name.lower().startswith('make_opt'):
792 out.append(directory+'/'+name)
793 return out
794
796
797
798 os.path.walk('.', rm_file_extension, '.o')
799
800
801 libraries = ['libblocks.a', 'libgeneric_mw.a', 'libMWPS.a', 'libtools.a', 'libdhelas3.a',
802 'libdsample.a', 'libgeneric.a', 'libmodel.a', 'libpdf.a', 'libdhelas3.so', 'libTF.a',
803 'libdsample.so', 'libgeneric.so', 'libmodel.so', 'libpdf.so']
804 lib_pos='./lib'
805 [os.remove(os.path.join(lib_pos, lib)) for lib in libraries \
806 if os.path.exists(os.path.join(lib_pos, lib))]
807
821
825
829 replace_dict = dict(key_values)
830 replacement_function = lambda match: replace_dict[match.group(0)]
831 pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M)
832 return lambda string: pattern.sub(replacement_function, string)
833
836
839 def deco_check(f):
840 def deco_f(arg, *args, **opt):
841 try:
842 return f(arg, *args, **opt)
843 except OSError, error:
844 logger.debug('try to recover from %s' % error)
845 if isinstance(arg, list):
846 prog = arg[0]
847 else:
848 prog = arg[0]
849
850
851 if error.errno == 13:
852 if os.path.exists(prog):
853 os.system('chmod +x %s' % prog)
854 elif 'cwd' in opt and opt['cwd'] and \
855 os.path.isfile(pjoin(opt['cwd'],arg[0])):
856 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0]))
857 return f(arg, *args, **opt)
858
859 elif error.errno == 2:
860
861 raise Exception, '%s fails with no such file or directory' \
862 % arg
863 else:
864 raise
865 return deco_f
866 return deco_check
867
868
869 @check_system_error()
870 -def call(arg, *args, **opt):
871 """nice way to call an external program with nice error treatment"""
872 try:
873 return subprocess.call(arg, *args, **opt)
874 except OSError:
875 arg[0] = './%s' % arg[0]
876 return subprocess.call(arg, *args, **opt)
877
878 @check_system_error()
879 -def Popen(arg, *args, **opt):
880 """nice way to call an external program with nice error treatment"""
881 return subprocess.Popen(arg, *args, **opt)
882
885 """try to open a file with multiple try to ensure that filesystem is sync"""
886 return open(filepath, *args, ** opt)
887
888
889
890
891
892 -def tail(f, n, offset=None):
893 """Reads a n lines from f with an offset of offset lines. The return
894 value is a tuple in the form ``lines``.
895 """
896 avg_line_length = 74
897 to_read = n + (offset or 0)
898
899 while 1:
900 try:
901 f.seek(-(avg_line_length * to_read), 2)
902 except IOError:
903
904
905 f.seek(0)
906 pos = f.tell()
907 lines = f.read().splitlines()
908 if len(lines) >= to_read or pos == 0:
909 return lines[-to_read:offset and -offset or None]
910 avg_line_length *= 1.3
911 avg_line_length = int(avg_line_length)
912
917 """return the last line of a file"""
918
919 return tail(fsock, 1)[0]
920
922 """read a file returning the lines in reverse order for each call of readline()
923 This actually just reads blocks (4096 bytes by default) of data from the end of
924 the file and returns last line in an internal buffer."""
925
926
928 """ readline in a backward way """
929
930 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size):
931 self.blkcount = self.blkcount + 1
932 line = self.data[0]
933 try:
934 self.seek(-self.blksize * self.blkcount, 2)
935 self.data = (self.read(self.blksize) + line).split('\n')
936 except IOError:
937 self.seek(0)
938 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line
939 self.data = data.split('\n')
940
941 if len(self.data) == 0:
942 return ""
943
944 line = self.data.pop()
945 return line + '\n'
946
947 - def __init__(self, filepos, blksize=4096):
948 """initialize the internal structures"""
949
950
951 self.size = os.stat(filepos)[6]
952
953 self.blksize = blksize
954
955 self.blkcount = 1
956 file.__init__(self, filepos, 'rb')
957
958
959 if self.size > self.blksize:
960 self.seek(-self.blksize * self.blkcount, 2)
961 self.data = self.read(self.blksize).split('\n')
962
963
964 if not self.data[-1]:
965 self.data.pop()
966
968 line = self.readline()
969 if line:
970 return line
971 else:
972 raise StopIteration
973
989
1003
1009 """create a temporary directory and ensure this one to be cleaned.
1010 """
1011
1012 - def __init__(self, suffix='', prefix='tmp', dir=None):
1013 self.nb_try_remove = 0
1014 import tempfile
1015 self.path = tempfile.mkdtemp(suffix, prefix, dir)
1016
1017
1018 - def __exit__(self, ctype, value, traceback ):
1019
1020 if False and isinstance(value, Exception):
1021 sprint("Directory %s not cleaned. This directory can be removed manually" % self.path)
1022 return False
1023 try:
1024 shutil.rmtree(self.path)
1025 except OSError:
1026 self.nb_try_remove += 1
1027 if self.nb_try_remove < 3:
1028 time.sleep(10)
1029 self.__exit__(ctype, value, traceback)
1030 else:
1031 logger.warning("Directory %s not completely cleaned. This directory can be removed manually" % self.path)
1032
1035
1037 """create a temporary directory and ensure this one to be cleaned.
1038 """
1039
1040 - def __init__(self, cls, attribute, value):
1041
1042 self.old_value = getattr(cls, attribute)
1043 self.cls = cls
1044 self.attribute = attribute
1045 setattr(self.cls, self.attribute, value)
1046
1047 - def __exit__(self, ctype, value, traceback ):
1048
1049 setattr(self.cls, self.attribute, self.old_value)
1050
1052 return self.old_value
1053
1054
1055
1056
1057 -def gunzip(path, keep=False, stdout=None):
1058 """ a standard replacement for os.system('gunzip -f %s.gz ' % event_path)"""
1059
1060 if not path.endswith(".gz"):
1061 if os.path.exists("%s.gz" % path):
1062 path = "%s.gz" % path
1063 else:
1064 raise Exception, "%(path)s does not finish by .gz and the file %(path)s.gz does not exists" %\
1065 {"path": path}
1066
1067
1068
1069 if os.path.getsize(path) > 1e8:
1070 if stdout:
1071 os.system('gunzip -c %s > %s' % (path, stdout))
1072 else:
1073 os.system('gunzip %s' % path)
1074 return 0
1075
1076 if not stdout:
1077 stdout = path[:-3]
1078 try:
1079 gfile = ziplib.open(path, "r")
1080 except IOError:
1081 raise
1082 else:
1083 try:
1084 open(stdout,'w').write(gfile.read())
1085 except IOError:
1086
1087 if stdout == path:
1088 return
1089 else:
1090 files.cp(path, stdout)
1091
1092 if not keep:
1093 os.remove(path)
1094 return 0
1095
1096 -def gzip(path, stdout=None, error=True, forceexternal=False):
1097 """ a standard replacement for os.system('gzip %s ' % path)"""
1098
1099
1100 if os.path.getsize(path) > 1e9 or forceexternal:
1101 call(['gzip', '-f', path])
1102 if stdout:
1103 if not stdout.endswith(".gz"):
1104 stdout = "%s.gz" % stdout
1105 shutil.move('%s.gz' % path, stdout)
1106 return
1107
1108 if not stdout:
1109 stdout = "%s.gz" % path
1110 elif not stdout.endswith(".gz"):
1111 stdout = "%s.gz" % stdout
1112
1113 try:
1114 ziplib.open(stdout,"w").write(open(path).read())
1115 except OverflowError:
1116 gzip(path, stdout, error=error, forceexternal=True)
1117 except Exception:
1118 if error:
1119 raise
1120 else:
1121 os.remove(path)
1122
1127 """ a convinient class to open a file """
1128
1129 web_browser = None
1130 eps_viewer = None
1131 text_editor = None
1132 configured = False
1133
1135 """open a file"""
1136
1137
1138 if not self.configured:
1139 self.configure()
1140
1141 try:
1142 extension = filename.rsplit('.',1)[1]
1143 except IndexError:
1144 extension = ''
1145
1146
1147
1148 if extension in ['html','htm','php']:
1149 self.open_program(self.web_browser, filename, background=True)
1150 elif extension in ['ps','eps']:
1151 self.open_program(self.eps_viewer, filename, background=True)
1152 else:
1153 self.open_program(self.text_editor,filename, mac_check=False)
1154
1155
1156 @classmethod
1179
1180 @classmethod
1218
1219
1220 @staticmethod
1222 """find a valid shell program in the list"""
1223
1224 for p in possibility:
1225 if which(p):
1226 logger.info('Using default %s \"%s\". ' % (program, p) + \
1227 'Set another one in ./input/mg5_configuration.txt')
1228 return p
1229
1230 logger.info('No valid %s found. ' % program + \
1231 'Please set in ./input/mg5_configuration.txt')
1232 return None
1233
1234
1235 - def open_program(self, program, file_path, mac_check=True, background=False):
1236 """ open a file with a given program """
1237
1238 if mac_check==True and sys.platform == 'darwin':
1239 return self.open_mac_program(program, file_path)
1240
1241
1242 if program:
1243 arguments = program.split()
1244 arguments.append(file_path)
1245
1246 if not background:
1247 subprocess.call(arguments)
1248 else:
1249 import thread
1250 thread.start_new_thread(subprocess.call,(arguments,))
1251 else:
1252 logger.warning('Not able to open file %s since no program configured.' % file_path + \
1253 'Please set one in ./input/mg5_configuration.txt')
1254
1256 """ open a text with the text editor """
1257
1258 if not program:
1259
1260 os.system('open %s' % file_path)
1261 elif which(program):
1262
1263 arguments = program.split()
1264 arguments.append(file_path)
1265 subprocess.call(arguments)
1266 else:
1267
1268 os.system('open -a %s %s' % (program, file_path))
1269
1289
1291 """ Try and guess what shell type does the user use."""
1292 try:
1293 if os.environ['SHELL'].endswith('bash'):
1294 return 'bash'
1295 elif os.environ['SHELL'].endswith('tcsh'):
1296 return 'tcsh'
1297 else:
1298
1299 return None
1300 except KeyError:
1301 return None
1302
1304 """ check if a path is executable"""
1305 try:
1306 return os.access(path, os.X_OK)
1307 except Exception:
1308 return False
1309
1311 """Option Peaser which raise an error instead as calling exit"""
1312
1313 - def exit(self, status=0, msg=None):
1318
1320 """Returns the current line number in our program."""
1321
1322 if not __debug__:
1323 return
1324
1325 import inspect
1326 if opt.has_key('log'):
1327 log = opt['log']
1328 else:
1329 log = logging.getLogger('madgraph')
1330 if opt.has_key('level'):
1331 level = opt['level']
1332 else:
1333 level = logging.getLogger('madgraph').level
1334
1335
1336
1337
1338 lineno = inspect.currentframe().f_back.f_lineno
1339 fargs = inspect.getframeinfo(inspect.currentframe().f_back)
1340 filename, lineno = fargs[:2]
1341
1342
1343 try:
1344 source = inspect.getsourcelines(inspect.currentframe().f_back)
1345 line = source[0][lineno-source[1]]
1346 line = re.findall(r"misc\.sprint\(\s*(.*)\)\s*($|#)", line)[0][0]
1347 if line.startswith("'") and line.endswith("'") and line.count(",") ==0:
1348 line= ''
1349 elif line.startswith("\"") and line.endswith("\"") and line.count(",") ==0:
1350 line= ''
1351 elif line.startswith(("\"","'")) and len(args)==1 and "%" in line:
1352 line= ''
1353 except Exception:
1354 line=''
1355
1356 if line:
1357 intro = ' %s = \033[0m' % line
1358 else:
1359 intro = ''
1360
1361
1362 log.log(level, ' '.join([intro]+[str(a) for a in args]) + \
1363 ' \033[1;30m[%s at line %s]\033[0m' % (os.path.basename(filename), lineno))
1364 return
1365
1366
1367
1368
1369 -def equal(a,b,sig_fig=6, zero_limit=True):
1370 """function to check if two float are approximatively equal"""
1371 import math
1372
1373 if not a or not b:
1374 if zero_limit:
1375 power = sig_fig + 1
1376 else:
1377 return a == b
1378 else:
1379 power = sig_fig - int(math.log10(abs(a))) + 1
1380
1381 return ( a==b or abs(int(a*10**power) - int(b*10**power)) < 10)
1382
1383
1384
1385
1386
1387
1388
1389 -class chdir:
1391 self.newPath = newPath
1392
1394 self.savedPath = os.getcwd()
1395 os.chdir(self.newPath)
1396
1397 - def __exit__(self, etype, value, traceback):
1398 os.chdir(self.savedPath)
1399
1400
1401
1402
1403
1404 -def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
1405 '''This function will spwan a thread and run the given function using the args, kwargs and
1406 return the given default value if the timeout_duration is exceeded
1407 '''
1408 import threading
1409 class InterruptableThread(threading.Thread):
1410 def __init__(self):
1411 threading.Thread.__init__(self)
1412 self.result = default
1413 def run(self):
1414 try:
1415 self.result = func(*args, **kwargs)
1416 except Exception,error:
1417 print error
1418 self.result = default
1419 it = InterruptableThread()
1420 it.start()
1421 it.join(timeout_duration)
1422 return it.result
1423
1424
1425
1426
1427
1428 -class digest:
1429
1431 try:
1432 return self.test_hashlib()
1433 except Exception:
1434 pass
1435 try:
1436 return self.test_md5()
1437 except Exception:
1438 pass
1439 try:
1440 return self.test_zlib()
1441 except Exception:
1442 pass
1443
1445 import hashlib
1446 def digest(text):
1447 """using mg5 for the hash"""
1448 t = hashlib.md5()
1449 t.update(text)
1450 return t.hexdigest()
1451 return digest
1452
1454 import md5
1455 def digest(text):
1456 """using mg5 for the hash"""
1457 t = md5.md5()
1458 t.update(text)
1459 return t.hexdigest()
1460 return digest
1461
1463 import zlib
1464 def digest(text):
1465 return zlib.adler32(text)
1466
1467 digest = digest().test_all()
1474 self.cmd_args = args
1475 self.cmd_opts = opts
1476 self.execution_state = False
1477
1479 self.max_vms_memory = 0
1480 self.max_rss_memory = 0
1481
1482 self.t1 = None
1483 self.t0 = time.time()
1484 self.p = subprocess.Popen(*self.cmd_args,**self.cmd_opts)
1485 self.execution_state = True
1486
1488 if not self.check_execution_state():
1489 return False
1490
1491 self.t1 = time.time()
1492
1493
1494
1495 flash = subprocess.Popen("ps -p %i -o rss"%self.p.pid,
1496 shell=True,stdout=subprocess.PIPE,stderr=open(os.devnull,"w"))
1497 stdout_list = flash.communicate()[0].split('\n')
1498 rss_memory = int(stdout_list[1])
1499
1500 vms_memory = 0
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529 self.max_vms_memory = max(self.max_vms_memory,vms_memory)
1530 self.max_rss_memory = max(self.max_rss_memory,rss_memory)
1531
1532 return self.check_execution_state()
1533
1535
1536
1537 return self.p.poll() == None
1538
1540 if not self.execution_state:
1541 return False
1542 if self.is_running():
1543 return True
1544 self.executation_state = False
1545 self.t1 = time.time()
1546 return False
1547
1548 - def close(self,kill=False):
1549
1550 if self.p.poll() == None:
1551 if kill:
1552 self.p.kill()
1553 else:
1554 self.p.terminate()
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567 try:
1568 import Foundation
1569 import objc
1570 NSUserNotification = objc.lookUpClass('NSUserNotification')
1571 NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
1574 try:
1575 notification = NSUserNotification.alloc().init()
1576 notification.setTitle_('MadGraph5_aMC@NLO')
1577 notification.setSubtitle_(subtitle)
1578 notification.setInformativeText_(info_text)
1579 notification.setUserInfo_(userInfo)
1580 NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
1581 except:
1582 pass
1583 except:
1586