Source code for pyne.utils

from __future__ import division
import os

from warnings import warn

from distutils.dir_util import remove_tree
import filecmp
from io import open

from pyne._utils import fromstring_split, fromstring_token, endftod,\
                        use_fast_endftod, fromendf_tok, toggle_warnings,\
                        use_warnings, fromendl_tok

[docs]class QAWarning(UserWarning): pass
def QA_warn(module_name): if ('PYNE_QA_WARN' in os.environ): warn(module_name + " is not yet fully QA compliant.", QAWarning) time_conv_dict = {'as': 1e-18, 'attosec': 1e-18, 'attosecond': 1e-18, 'attoseconds': 1e-18, 'fs': 1e-15, 'femtosec': 1e-15, 'femtosecond': 1e-15, 'femtoseconds': 1e-15, 'ps': 1e-12, 'picosec': 1e-12, 'picosecond': 1e-12, 'picoseconds': 1e-12, 'ns': 1e-9, 'nanosec': 1e-9, 'nanosecond': 1e-9, 'nanoseconds': 1e-9, 'us': 1e-6, 'microsec': 1e-6, 'microsecond': 1e-6, 'microseconds': 1e-6, 'ms': 1e-3, 'millisec': 1e-3, 'millisecond': 1e-3, 'milliseconds': 1e-3, 's': 1.0, 'sec': 1.0, 'second': 1.0, 'seconds': 1.0, 'm': 60.0, 'min': 60.0, 'minute': 60.0, 'minutes': 60.0, 'h': 3600.0, 'hour': 3600.0, 'hours': 3600.0, 'd': 86400.0, 'day': 86400.0, 'days': 86400.0, 'w': 86400.0*7.0, 'week': 86400.0*7.0, 'weeks': 86400.0*7.0, 'y': 86400.0*365.25, 'year': 86400.0*365.25, 'years': 86400.0*365.25, 'c': 86400.0*365.25*100, 'century': 86400.0*365.25*100, 'centuries': 86400.0*365.25*100, }
[docs]def to_sec(input_time, units): """Converts a time with units to seconds. Parameters ---------- input_time : number Time value in [units]. units : str Units flag, eg 'min', 'ms', 'days' Returns ------- sec_time : float Time value in [sec]. """ units = str_to_unicode(units) conv = time_conv_dict.get(units.lower(), None) if conv: sec_time = input_time * conv return sec_time else: raise ValueError('Invalid units: {0}'.format(units))
barn_conv_dict = { 'mb': 1E-3, 'ub': 1E-6, 'microbarn': 1E-6, 'b': 1.0, 'barn': 1.0, 'barns': 1.0, 'kb': 1E+3, 'kilobarn': 1E+3, 'cm2': 1E+24, 'cm^2': 1E+24, }
[docs]def to_barns(xs, units): """Converts a cross section with units to barns. Parameters ---------- xs : Cross section value in [units]. units : str Units flag, eg 'b', 'microbarn'. Returns ------- barn_xs : Cross section value in [barns]. """ return xs * barn_conv_dict[units.lower()]
[docs]def from_barns(xs, units): """Converts a cross section from barns to units. Parameters ---------- xs : Cross section value in [barns]. units : str Units flag, eg 'b', 'microbarn'. Returns ------- unit_xs : Cross section value in [units]. """ return xs / barn_conv_dict[units.lower()]
######################### ### message functions ### ######################### USE_COLOR = (os.name is 'posix')
[docs]def message(s): """Formats a message for printing. If on a posix system the message will be in color. """ head = "\033[1;32m" if USE_COLOR else "*** MESSAGE ***: " tail = "\033[0m" if USE_COLOR else "" msg = head + s + tail return msg
[docs]def failure(s): """Formats a fail message for printing. If on a posix system the message will be in color. """ head = "\033[1;31m" if USE_COLOR else "*** FAILURE ***: " tail = "\033[0m" if USE_COLOR else "" msg = head + s + tail return msg
[docs]def warning(s): """Formats a warning message for printing. If on a posix system the message will be in color. """ head = "\033[1;33m" if USE_COLOR else "*** WARNING ***: " tail = "\033[0m" if USE_COLOR else "" msg = head + s + tail return msg
################################## ### Path manipulation routines ### ##################################
[docs]def remove(path): """Removes a path, or recursively a directory, or does nothing if path is neither a file nor a directory. """ if os.path.isfile(path): os.remove(path) elif os.path.isdir(path): remove_tree(path, verbose=False) else: pass
[docs]def str_to_unicode(s): """ This function convert a str from binary or unicode to str (unicode). If it is a list of string, convert every element of the list. Parameters: ----------- s : str or list of str Returns: -------- s : text str or list of unicode str """ if isinstance(s, str) or isinstance(s, bytes): # it is a str, convert to text str try: s = s.decode('utf-8') except: pass return s else: for i, item in enumerate(s): try: s[i] = item.decode('utf-8') except: pass return s
def is_close(a, b, rel_tol=1e-9, abs_tol=0.0): return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
[docs]def is_float(s): """ This function checks whether a string can be converted as a float number. """ try: float(s) return True except ValueError: return False
[docs]def str_almost_same(s1, s2, rel_tol=1e-9): """ This function is used to compare two string to check whether they are almost the same. Return True if two strings are exactly the same. Return True if two strings are almost the same with only slight difference of float decimals. Return False if two strings are different. """ # if string can be converted to float number if is_float(s1) and is_float(s2): return is_close(float(s1), float(s2), rel_tol) else: # not a number return s1 == s2
[docs]def line_almost_same(l1, l2, rel_tol=1e-9): """ This function is used to compare two lines (read from files). If they are the same, or almost the same (with only slight difference on float numbers), return True. Ohterwise, return False. Parameters: ----------- l1 : str Line 1 l2 : str Line 2 rel_tol : float Relative tolerance for float comparison Returns: -------- True, if two lines are the same. False, if they are different. """ if l1 == l2: # exactly the same return True else: # There are differences tokens1 = l1.strip().split() tokens2 = l2.strip().split() if len(tokens1) != len(tokens2): return False else: # compare string elements of the line for i in range(len(tokens1)): if str_almost_same(tokens1[i], tokens2[i], rel_tol): pass else: return False return True
[docs]def file_almost_same(f1, f2, rel_tol=1e-9): """ For some reasones, it's useful to compare two files that are almost the same. Two files, f1 and f2, the text contents are exactly the same, but there is a small difference in numbers. Such as the difference between 'some text 9.5' and 'some text 9.500000000001'. For example, in PyNE test files, there are some expected file generated by python2, however, the the file generated by python3 may have difference in decimals. Parameters: ----------- f1 : str Filename of file 1 or lines f2 : str Filename of file 2 or lines rel_tol : float Relative tolerance for float numbers Returns: True : bool If two file are exactly the same, or almost the same with only decimal differences. False : bool If the strings of the two files are different and/or their numbers differences are greater than the tolerance """ if os.path.isfile(f1) and os.path.isfile(f2): if filecmp.cmp(f1, f2): # precheck return True else: # read lines of f1 and f2, convert to unicode if os.path.isfile(f1): with open(f1, 'r') as f: lines1 = f.readlines() else: lines1 = f1 lines1 = str_to_unicode(f1) lines1 = lines1.strip().split(u'\n') if os.path.isfile(f2): with open(f2, 'r') as f: lines2 = f.readlines() else: lines2 = f2 lines2 = str_to_unicode(f2) lines2 = lines2.strip().split(u'\n') # compare two files # check length of lines if len(lines1) != len(lines2): return False # check content line by line for i in range(len(lines1)): if line_almost_same(lines1[i], lines2[i], rel_tol): pass else: return False # no difference found return True
[docs]def block_in_blocks(block1, blocks2, rel_tol=1e-9): """ Test whether a block of content in another file (represented as blocks2). Parameters: ----------- block1 : str A block of file1. blocks2 : list of str Blocks of file2. rel_tol : float Tolerance for float comparision. Returns: -------- True : bool If block1 in blocks2. False : bool If block1 not in blocks2. """ for i in range(len(blocks2)): if file_almost_same(block1, blocks2[i]): return True return False
[docs]def file_block_almost_same(f1, f2, rel_tol=1e-9): """ Some files are seperated into different blocks without specific sequence. Such as the materials definition file: 'alara_matlib', the sequence of the materils doesn't matter. It is useful to compare whether their blocks are almost the same. Parameters: ----------- f1 : str Filename of file 1 or lines f2 : str Filename of file 2 or lines rel_tol : float Reletive tolerance for float numbers Returns: True : bool If two file are exactly the same, or almost the same with only dicimal differences, or almost same as blocks. False : bool They have different blocks. """ if os.path.isfile(f1) and os.path.isfile(f2): if file_almost_same(f1, f2): # precheck return True else: # convert to different blocks and compare each block # read lines of f1 and f2, convert to unicode if os.path.isfile(f1): with open(f1, 'r') as f: lines1 = f.readlines() lines1 = str_to_unicode(lines1) else: lines1 = str_to_unicode(f1) blocks1 = lines1.strip().split(u'\n\n') if os.path.isfile(f2): with open(f2, 'r') as f: lines2 = f.readlines() lines2 = str_to_unicode(lines2) else: lines2 = str_to_unicode(f2) blocks2 = lines2.strip().split(u'\n\n') # compare two files # check length of lines if len(blocks1) != len(blocks2): return False # check content of blocks for i in range(len(blocks1)): if block_in_blocks(blocks1[i], blocks2, rel_tol): pass else: return False # no difference found return True
[docs]def check_iterable(obj): """Check whether the object is Iterable.""" try: obj_iterator = iter(obj) except TypeError as te: print(obj.__str__(), "is not iterable") return False return True