Repository: CORE-GATECH-GROUP/serpent-tools
Pull request #195 (2018-06-15 20:41:31)

[DEV] Extend splitValsUncs to n-dimensional arrays
`utils.splitValsUncs` now works for higher order arrays by splitting along the last axis. This translates to splitting at columns of a 2D matrix. Functionality is retained for
passing in vectors or strings. 
```
>>> v = [[1, 2], [3, 4]]
>>> splitValsUncs(v)
array([[1], [3]]), array([[2], [4]])
```

Test added to test this feature by splitting a 2D matrix along columns.

Possible Sticking Points
------------------------

Changed how the function handles non-array objects. If anything other than a string is passed to the function, it is converted to array not with `utils.str2Vec` but by `numpy.array`. This is described in the docstring.

Why
---

This is something that I'm using in the comparison methods for data with uncertainties on the results reader. Rather than march through all rows in the results dictionary, I use this to split the potentially 2D array along the columns, then I have the values as a potentially 2D matrix and their uncertainties as well. The tests are written to work with arbitrarily sized though, mostly 2D in mind so there isn't a need to march down one axis and test at each burnup step. More to come on that later



Patch:
diff --git a/serpentTools/utils.py b/serpentTools/utils.py
index 3a4e004..382befd 100644
--- a/serpentTools/utils.py
+++ b/serpentTools/utils.py
@@ -55,15 +55,20 @@ def splitValsUncs(iterable, copy=False):
     Return even and odd indexed values from iterable
 
     Designed to extract expected values and uncertainties from
-    SERPENT vectors of the form 
+    SERPENT vectors/matrices of the form 
     ``[x1, u1, x2, u2, ...]``
 
+    Slices along the last axis present on ``iterable``, e.g.
+    columns in 2D matrix.
+
     Parameters
     ----------
-    iterable: ndarray or iterable
+    iterable: :class:`numpy.ndarray`or iterable
         Initial arguments to be processed. If not 
-        :py:class:`numpy.ndarray`, then will be converted
-        by calling :py:func:`serpentTools.utils.str2vec`
+        :class:`numpy.ndarray`, then strings will be converted
+        by calling :func:`str2vec`. Lists and tuples
+        will be sent directly to arrays with 
+        :func:`numpy.array`.
     copy: bool
         If true, return a unique instance of the values
         and uncertainties. Otherwise, returns a view
@@ -71,9 +76,9 @@ def splitValsUncs(iterable, copy=False):
 
     Returns
     -------
-    numpy.ndarray
+    :class:`numpy.ndarray`
         Even indexed values from ``iterable``
-    numpy.ndarray
+    :class:`numpy.ndarray`
         Odd indexed values from ``iterable``
 
     Examples
@@ -88,12 +93,17 @@ def splitValsUncs(iterable, copy=False):
         >>> splitValsUnc(line)
         array([1, 3]), array([2, 4])
 
+        >>> v = [[1, 2], [3, 4]]
+        >>> splitValsUncs(v)
+        array([[1], [3]]), array([[2], [4]])
+
     """
 
     if not isinstance(iterable, ndarray):
-        iterable = str2vec(iterable)
-    vals = iterable[0::2]
-    uncs = iterable[1::2]
+        iterable = (str2vec(iterable) if isinstance(iterable, str) 
+                    else array(iterable))
+    vals = iterable[..., 0::2]
+    uncs = iterable[..., 1::2]
     if copy:
         return vals.copy(), uncs.copy()
     return vals, uncs


Test patch:
diff --git a/serpentTools/tests/test_utils.py b/serpentTools/tests/test_utils.py
index 6c9fc9d..4a8f1eb 100644
--- a/serpentTools/tests/test_utils.py
+++ b/serpentTools/tests/test_utils.py
@@ -83,6 +83,16 @@ class SplitValsTester(unittest.TestCase):
             assert_array_equal(view, copy,err_msg=msg)
             self.assertFalse(view is copy, msg=msg)
 
+    def test_splitAtCols(self):
+        """Verify that the splitValsUncs works for 2D arrays."""
+        mat = self.input.reshape(2, 2)
+        expectedV = array([[0], [2]])
+        expectedU = array([[1], [3]])
+        actualV, actualU = splitValsUncs(mat)
+        assert_array_equal(expectedV, actualV, err_msg="Values")
+        assert_array_equal(expectedU, actualU, err_msg="Uncertainties")
+
+
 if __name__ == '__main__':
     unittest.main()