Repository: CORE-GATECH-GROUP/serpent-tools
Pull request #274 (2019-02-08 22:31:56)

API Convert sensitivity files to MATLAB
Implemented the gathering method that allows sensitivity readers to be written to MATLAB using scipy.io.savemat. New tests were added, and some documentation updated.


Patch:
diff --git a/.travis.yml b/.travis.yml
index b0f456d..f370223 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,19 +3,11 @@ python:
   - "3.6"
   - "3.5"
   - "2.7"
-env:
-  - ST_INSTALL=setup
-  - ST_INSTALL=sdist
-  - ST_INSTALL=bdist_wheel
-  - ST_INSTALL=bdist_egg
 
-before_install:
-  - pip install -r requirements.txt -r requirements-test.txt
-  - rm -rf dist
-# install matrix
-# build some distributions (source and wheel) and install from those
+# install
 install:
-  - bash scripts/travis/install.sh
+  - pip install -r requirements.txt -r requirements-test.txt
+  - python setup.py install
 
 # use xvfb to give the plot functions something to use
 # PR 70
diff --git a/MANIFEST.in b/MANIFEST.in
index bc97e1a..334ac1c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,4 +3,3 @@ include serpentTools/_version.py
 include serpentTools/variables.yaml
 include serpentTools/data/*.m
 include serpentTools/data/*.coe
-include requirements.txt
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 062242e..8301113 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -31,8 +31,6 @@ Next
   to perturbations, universes, and burnup.
 * Plotting routines now use attach to the active plot or generate
   a new plot figure if ``ax`` argument not given - :issue:`267`
-* :class:`~serpentTools.parsers.branching.BranchingReader` can
-  read coefficient files with uncertainties - :issue:`270`
 
 .. warning::
 
diff --git a/docs/defaultSettings.rst b/docs/defaultSettings.rst
index c7102ec..f3664fd 100644
--- a/docs/defaultSettings.rst
+++ b/docs/defaultSettings.rst
@@ -1,3 +1,16 @@
+.. _branching-areUncsPresent:
+
+----------------------------
+``branching.areUncsPresent``
+----------------------------
+
+True if the values in the .coe file contain uncertainties
+::
+
+  Default: False
+  Type: bool
+  
+
 .. _branching-floatVariables:
 
 ----------------------------
diff --git a/docs/examples/Settings.rst b/docs/examples/Settings.rst
index 66e3aba..852ea39 100644
--- a/docs/examples/Settings.rst
+++ b/docs/examples/Settings.rst
@@ -35,7 +35,7 @@ with the ``.keys`` method.
  
 
     dict_keys(['depletion.processTotal', 'verbosity', 'xs.getInfXS',
-    'branching.intVariables', 'serpentVersion',
+    'branching.intVariables', 'branching.areUncsPresent', 'serpentVersion',
     'sampler.raiseErrors', 'xs.getB1XS', 'xs.variableGroups', 'xs.variableExtras',
     'depletion.materialVariables', 'depletion.metadataKeys', 'sampler.freeAll',
     'sampler.allExist', 'depletion.materials', 'sampler.skipPrecheck',
@@ -206,6 +206,7 @@ However, the loader can also expand a nested dictionary structure, as
 ::
 
     branching:
+      areUncsPresent: False
       floatVariables: [Fhi, Blo]
     depletion:
       materials: [fuel*]
@@ -225,6 +226,7 @@ However, the loader can also expand a nested dictionary structure, as
     xs.variableGroups: [gc-meta, kinetics,
     xs]
     branching:
+      areUncsPresent: False
       floatVariables: [Fhi, Blo]
     depletion:
       materials: [fuel*]
@@ -238,7 +240,7 @@ However, the loader can also expand a nested dictionary structure, as
     
     >>> myConf = 'myConfig.yaml'
     >>> rc.loadYaml(myConf)
-    >>> rc['xs.getInfXS']
+    >>> rc['branching.areUncsPresent']
 
 .. parsed-literal::
  
diff --git a/examples/Branching.ipynb b/examples/Branching.ipynb
index 5b1a687..9967883 100644
--- a/examples/Branching.ipynb
+++ b/examples/Branching.ipynb
@@ -570,6 +570,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "* [`branching.areUncsPresent`](http://serpent-tools.readthedocs.io/en/latest/settingsTop.html#branching-areuncspresent)\n",
     "* [`branching.floatVariables`](http://serpent-tools.readthedocs.io/en/latest/settingsTop.html#branching-floatvariables)\n",
     "* [`branching.intVariables`](http://serpent-tools.readthedocs.io/en/latest/settingsTop.html#branching-intvariables)\n",
     "* [`xs.getB1XS`](http://serpent-tools.readthedocs.io/en/latest/settingsTop.html#xs-getb1xs)\n",
diff --git a/examples/Settings.ipynb b/examples/Settings.ipynb
index 27951fb..385c525 100644
--- a/examples/Settings.ipynb
+++ b/examples/Settings.ipynb
@@ -50,7 +50,7 @@
     {
      "data": {
       "text/plain": [
-       "dict_keys(['depletion.processTotal', 'verbosity', 'xs.getInfXS', 'branching.intVariables', 'serpentVersion', 'sampler.raiseErrors', 'xs.getB1XS', 'xs.variableGroups', 'xs.variableExtras', 'depletion.materialVariables', 'depletion.metadataKeys', 'sampler.freeAll', 'sampler.allExist', 'depletion.materials', 'sampler.skipPrecheck', 'xs.reshapeScatter', 'branching.floatVariables', 'detector.names'])"
+       "dict_keys(['depletion.processTotal', 'verbosity', 'xs.getInfXS', 'branching.intVariables', 'branching.areUncsPresent', 'serpentVersion', 'sampler.raiseErrors', 'xs.getB1XS', 'xs.variableGroups', 'xs.variableExtras', 'depletion.materialVariables', 'depletion.metadataKeys', 'sampler.freeAll', 'sampler.allExist', 'depletion.materials', 'sampler.skipPrecheck', 'xs.reshapeScatter', 'branching.floatVariables', 'detector.names'])"
       ]
      },
      "execution_count": 13,
@@ -264,6 +264,7 @@
     "However, the loader can also expand a nested dictionary structure, as\n",
     "```\n",
     "branching:\n",
+    "  areUncsPresent: False\n",
     "  floatVariables: [Fhi, Blo]\n",
     "depletion:\n",
     "  materials: [fuel*]\n",
@@ -285,6 +286,7 @@
       "xs.getB1XS: True\r\n",
       "xs.variableGroups: [gc-meta, kinetics, xs]\r\n",
       "branching:\r\n",
+      "  areUncsPresent: False\r\n",
       "  floatVariables: [Fhi, Blo]\r\n",
       "depletion:\r\n",
       "  materials: [fuel*]\r\n",
@@ -325,7 +327,7 @@
    "source": [
     "myConf = 'myConfig.yaml'\n",
     "rc.loadYaml(myConf)\n",
-    "rc['xs.getInfXS']"
+    "rc['branching.areUncsPresent']"
    ]
   }
  ],
diff --git a/examples/myConfig.yaml b/examples/myConfig.yaml
index 523fa61..8953d66 100644
--- a/examples/myConfig.yaml
+++ b/examples/myConfig.yaml
@@ -2,6 +2,7 @@ xs.getInfXS: False
 xs.getB1XS: True
 xs.variableGroups: [gc-meta, kinetics, xs]
 branching:
+  areUncsPresent: False
   floatVariables: [Fhi, Blo]
 depletion:
   materials: [fuel*]
diff --git a/scripts/travis/install.sh b/scripts/travis/install.sh
deleted file mode 100644
index e0960a5..0000000
--- a/scripts/travis/install.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-# Install script that depends on $INSTALL variable
-# Options:
-# setup: install with setup.py
-# sdist: create a source distribution and install from that
-# bdist_wheel: create a wheel and install from that
-
-if [[ -z $ST_INSTALL ]]; then exit; fi
-
-set -ev
-set -o pipefail
-
-ST_VERSION=$(python setup.py version | grep Version | cut -d" " -f 2)
-echo $ST_VERSION
-
-case $ST_INSTALL in
-    'setup')
-        python setup.py install
-        ;;
-    'sdist')
-        python setup.py sdist
-        pip install dist/serpentTools-${ST_VERSION}.tar.gz
-        ;;
-    'bdist_wheel')
-        python setup.py bdist_wheel
-        easy_install dist/serpentTools-${ST_VERSION}*whl
-        ;;
-    'bdist_egg')
-        python setup.py bdist_egg
-        easy_install dist/serpentTools-${ST_VERSION}*egg
-        ;;
-    *)
-        echo No install option
-        exit 1
-esac
-                
diff --git a/serpentTools/data/demo_uncs.coe b/serpentTools/data/demo_uncs.coe
deleted file mode 100644
index 256c7d0..0000000
--- a/serpentTools/data/demo_uncs.coe
+++ /dev/null
@@ -1,14 +0,0 @@
-1 2 1 2 1
-1 nom
-3 VERSION 2.1.30 DATE 19/02/07 TIME 15:27:13
-0 1 1
-0 2
-INF_TOT 2  4.92499E-01 0.00074  1.01767E+00 0.00072
-INF_S0 4  4.66391E-01 0.00072  1.55562E-02 0.00148  1.28821E-03 0.01793  9.21487E-01 0.00091
-2 2 2 2 1
-1 hot
-3 VERSION 2.1.30 DATE 19/02/07 TIME 15:27:55
-0 1 1
-0 2
-INF_TOT 2  4.92806E-01 0.00063  1.01680E+00 0.00104
-INF_S0 4  4.66639E-01 0.00062  1.53978E-02 0.00214  1.38727E-03 0.03073  9.20270E-01 0.00112
diff --git a/serpentTools/parsers/branching.py b/serpentTools/parsers/branching.py
index 8ba6fb4..daaa8f3 100644
--- a/serpentTools/parsers/branching.py
+++ b/serpentTools/parsers/branching.py
@@ -33,12 +33,6 @@ class BranchingReader(XSReader):
         self._whereAmI = {key: None for key in
                           {'runIndx', 'coefIndx', 'buIndx', 'universe'}}
         self._totalBranches = None
-        self._hasUncs = None
-
-    @property
-    def hasUncs(self):
-        """boolean if uncertainties are present in the file"""
-        return self._hasUncs
 
     def _read(self):
         """Read the branching file and store the coefficients."""
@@ -122,10 +116,10 @@ class BranchingReader(XSReader):
                       .format(varName))
                 continue
             if self._checkAddVariable(varName):
-                if self._hasUncs:
+                if self.settings['areUncsPresent']:
                     vals, uncs = splitValsUncs(varValues)
-                    univ.addData(varName, array(vals), uncertainty=False)
-                    univ.addData(varName, array(uncs), uncertainty=True)
+                    univ.addData(varName, array(vals), uncertaity=False)
+                    univ.addData(varName, array(uncs), unertainty=True)
                 else:
                     univ.addData(varName, array(varValues), uncertainty=False)
 
@@ -135,19 +129,13 @@ class BranchingReader(XSReader):
             yield bID, b
 
     def _precheck(self):
-        """Total number of branches and check for uncertainties"""
+        """Currently, just grabs total number of coeff calcs."""
         with open(self.filePath) as fObj:
             try:
                 self._totalBranches = int(fObj.readline().split()[1])
             except Exception as ee:
                 error("COE output at {} likely malformatted or misnamed\n{}"
                       .format(self.filePath, str(ee)))
-            # skip first few lines with integer until first named value
-            for _x in range(4):
-                fObj.readline()
-            lsplt = fObj.readline().split()
-            nvals = int(lsplt[1])
-            self._hasUncs = not nvals == len(lsplt) - 2
 
     def _postcheck(self):
         """Make sure Serpent finished printing output."""
diff --git a/serpentTools/parsers/sensitivity.py b/serpentTools/parsers/sensitivity.py
index 84bc4aa..b077fad 100644
--- a/serpentTools/parsers/sensitivity.py
+++ b/serpentTools/parsers/sensitivity.py
@@ -19,26 +19,42 @@ class SensitivityReader(BaseReader):
     """
     Class for reading sensitivity files
 
-    The arrays that are stored in ``sensitivities`` and
-    ``energyIntegratedSens`` are stored under converted names.
+    The arrays that are stored in :attr:`sensitivities` and
+    :attr:`energyIntegratedSens` are stored under converted names.
     The original names from SERPENT are of the form
     ``ADJ_PERT_KEFF_SENS`` or ``ADJ_PERT_KEFF_SENS_E_INT``,
     respectively. Since this reader stores the resulting arrays
     in unique locations, the names are converted to a succint form.
     The two arrays listed above would be stored both as ``keff``
-    in ``sensitivities`` and ``energyIntegratedSens``.
+    in :attr:`sensitivities` and :attr:`energyIntegratedSens`.
     All names are converted to ``mixedCaseNames`` to fit the
     style of the project.
 
-    Ordered dictionaries ``materials``, ``zais``, and
-    ``perts`` contain keys of the names of their respective
+    Ordered dictionaries :attr:`materials`, :attr:`zais` and
+    :attr:`perts` contain keys of the names of their respective
     data, and the corresponding index, ``iSENS_ZAI_zzaaai``,
     in the sensitivity arrays. These arrays are zero-indexed,
     so the first item will have an index of zero. The data stored
-    in the ``sensitivities`` and ``energyIntegratedSens`` dictionaries
+    in the :attr:`sensitivities` and :attr:`energyIntegratedSens` dictionaries
     has the exact same structure as if the arrays were loaded into
     ``MATLAB``/``Octave``, but with zero-indexing.
 
+    The matrices in :attr:`sensitivities` are ordered as they
+    would be in MATLAB. The five dimensions correspond to:
+
+        1. :attr:`materials` that were contained perturbed isotopes
+        2. :attr:`zais` that were perturbed
+        3. :attr:`perts` - reactions that were perturbed, e.g.
+           ``'total xs'``
+        4: :attr:`energies` - which energy group contained the
+           perturbation. Will have one fewer dimensions than
+           the number of values in :attr:`energies`, corresponding
+           to the number of energy groups.
+        5: [value, relative uncertainty] pairs
+
+    The matrices in :attr:`energyIntegratedSens` will have the same
+    structure, but with the :attr:`energies` dimension removed.
+
     Parameters
     ----------
     filePath: str
@@ -81,6 +97,26 @@ class SensitivityReader(BaseReader):
         against energy, and their corresponding arrays
     """
 
+    _RECONVERT_ATTR_MAP = {
+        'nMat': ('sensNumMat', 'SENS_N_MAT'),
+        'nZai': ('sensNumZai', 'SENS_N_ZAI'),
+        'nPert': ('sensNumPert', 'SENS_N_PERT'),
+        'nEne': ('sensNumEne', 'SENS_N_ENE'),
+        'nMu': ('sensNumMu', 'SENS_N_MU'),
+        'latGen': ('sensLatGen', 'SENS_N_LATGEN'),
+        'energies': ('sensEne', 'SENS_E'),
+        'lethargyWidths': ('sensLethWidth', 'SENS_LETHARGY_WIDTHS'),
+    }
+    _RECONVERT_LIST_MAP = {
+        'materials': ('sensMats', 'SENS_MAT_LIST'),
+        'zais': ('sensZais', 'SENS_ZAI_LIST'),
+        'perts': ('sensPerts', 'SENS_PERT_LIST'),
+    }
+    _RECONVERT_SENS_FMT = [
+        ['sens{}', 'sens{}_eneInt'],
+        ['ADJ_PERT_{}_SENS', 'ADJ_PERT_{}_SENS_E_INT'],
+    ]
+
     def __init__(self, filePath):
         BaseReader.__init__(self, filePath, 'sens')
         self.nMat = None
@@ -341,6 +377,22 @@ class SensitivityReader(BaseReader):
                         legend=legend, xlabel=xlabel, ylabel=ylabel.strip())
         return ax
 
+    def _gather_matlab(self, reconvert):
+        """Gather data for matlab conversion"""
+        out = {}
+        reconvNameIx = 1 if reconvert else 0
+        # get basic indexing
+        for attr, reconvNameTpl in iteritems(self._RECONVERT_ATTR_MAP):
+            out[reconvNameTpl[reconvNameIx]] = getattr(self, attr)
+        # ordered dictionary -> vectors
+        for attr, reconvNameTpl in iteritems(self._RECONVERT_LIST_MAP):
+            out[reconvNameTpl[reconvNameIx]] = list(getattr(self, attr).keys())
+        sensFmt, eneSensFmt = self._RECONVERT_SENS_FMT[reconvNameIx]
+        for key, sensMat in iteritems(self.sensitivities):
+            out[sensFmt.format(key)] = sensMat
+            out[eneSensFmt.format(key)] = self.energyIntegratedSens[key]
+        return out
+
     def _getCleanedPertOpt(self, key, value):
         """Return a set of all or some of the requested perturbations."""
         assert hasattr(self, key), key
diff --git a/serpentTools/settings.py b/serpentTools/settings.py
index 7954ee5..4a2b414 100644
--- a/serpentTools/settings.py
+++ b/serpentTools/settings.py
@@ -28,6 +28,12 @@ SETTING_DOC_FMTR = """.. _{tag}:
 
 SETTING_OPTIONS_FMTR = "Options: [{}]"
 defaultSettings = {
+    'branching.areUncsPresent': {
+        'default': False,
+        'type': bool,
+        'description': "True if the values in the .coe file contain "
+                       "uncertainties"
+    },
     'branching.intVariables': {
         'default': [],
         'description': 'Name of state data variables to convert to integers '
diff --git a/setup.py b/setup.py
index 9e29d5c..e671d87 100644
--- a/setup.py
+++ b/setup.py
@@ -63,7 +63,6 @@ setupArgs = {
     'package_data': {
         'serpentTools.data': ['data/{}'.format(ext) for ext in DATA_EXTS],
     },
-    'include_package_data': True,
     'cmdclass': versioneer.get_cmdclass(),
     'data_files': [
         ('serpentTools', ['serpentTools/variables.yaml', ]),


Test patch:
diff --git a/serpentTools/tests/test_branching.py b/serpentTools/tests/test_branching.py
index 9780cd4..8f60fb0 100644
--- a/serpentTools/tests/test_branching.py
+++ b/serpentTools/tests/test_branching.py
@@ -50,13 +50,12 @@ class BranchTester(_BranchTesterHelper):
                     'CMM_TRANSPXS_Z', 'CMM_DIFFCOEF', 'CMM_DIFFCOEF_X',
                     'CMM_DIFFCOEF_Y', 'CMM_DIFFCOEF_Z'}
         self.assertSetEqual(expected, self.reader.settings['variables'])
-        self.assertFalse(self.reader.hasUncs)
 
     def test_raiseError(self):
         """Verify that the reader raises an error for unexpected EOF"""
         badFile = 'bad_branching.coe'
         with open(self.file) as fObj, open(badFile, 'w') as badObj:
-            for _line in range(10):
+            for _line in range(5):
                 badObj.write(fObj.readline())
         badReader = BranchingReader(badFile)
         with self.assertRaises(EOFError):
@@ -124,53 +123,5 @@ class BranchContainerTester(_BranchTesterHelper):
             containerWithDays.addUniverse(101, 10, 1)
 
 
-class BranchWithUncsTester(unittest.TestCase):
-    """Tester that just tests a small file with uncertainties"""
-
-    BRANCH_DATA = {
-        'nom': {
-            'infTot': [
-                [4.92499E-01, 1.01767E+00],  # value
-                [0.00074, 0.00072],  # uncertainty
-            ],
-            'infS0': [
-                [0.466391, 0.0155562, 0.00128821, 0.921487],
-                [0.00072, 0.00148, 0.01793, 0.00091],
-            ],
-        },
-        'hot': {
-            'infTot': [
-                [4.92806E-1, 1.0168E00],  # value
-                [0.00063, 0.00104],  # uncertainty
-            ],
-            'infS0': [
-                [4.66639E-1, 1.53978E-02, 1.38727E-03, 9.20270E-01],
-                [0.00062, 0.00214, 0.03073, 0.00112],
-            ],
-        },
-    }
-    BRANCH_UNIVKEY = (0, 0, 0)
-
-    def setUp(self):
-        fp = getFile('demo_uncs.coe')
-        self.reader = BranchingReader(fp)
-        self.reader.read()
-
-    def test_valsWithUncs(self):
-        """Test that the branches and the uncertainties are present"""
-        self.assertTrue(self.reader.hasUncs)
-        for expKey, expSubData in iteritems(self.BRANCH_DATA):
-            self.assertTrue(expKey in self.reader.branches, msg=expKey)
-            actBranch = self.reader.branches[expKey]
-            self.assertTrue(self.BRANCH_UNIVKEY in actBranch.universes,
-                            msg=self.BRANCH_UNIVKEY)
-            univ = actBranch.universes[self.BRANCH_UNIVKEY]
-            for gcKey, gcVals in iteritems(expSubData):
-                actData = univ.get(gcKey, True)
-                for act, exp, what in zip(actData, gcVals, ['val', 'unc']):
-                    assert_allclose(act, exp, err_msg='{} {} {}'.format(
-                        expKey, gcKey, what))
-
-
 if __name__ == '__main__':
     unittest.main()
diff --git a/serpentTools/tests/test_sensivity.py b/serpentTools/tests/test_sensivity.py
index 59a4ea7..7d39651 100644
--- a/serpentTools/tests/test_sensivity.py
+++ b/serpentTools/tests/test_sensivity.py
@@ -1,26 +1,32 @@
 """
 Test the sensitivity reader
 """
-from unittest import TestCase
+from os import remove
+from unittest import TestCase, skipUnless
 from collections import OrderedDict
 from itertools import product
 
 from six import iteritems
 from numpy import array, inf
-from numpy.testing import assert_allclose
+from numpy.testing import assert_allclose, assert_array_equal
 
 from serpentTools.data import getFile
 from serpentTools.parsers.sensitivity import SensitivityReader
+from serpentTools.io import toMatlab
+from serpentTools.utils import checkScipy
 from serpentTools.tests import compareDictOfArrays
 from serpentTools.tests.utils import (plotTest, getLegendTexts)
 
 TEST_FILE = getFile('bwr_sens0.m')
 
+HAS_SCIPY = checkScipy()
+
 
 class SensitivityTestHelper(TestCase):
-    def setUp(self):
-        self.reader = SensitivityReader(TEST_FILE)
-        self.reader.read()
+    @classmethod
+    def setUpClass(cls):
+        cls.reader = SensitivityReader(TEST_FILE)
+        cls.reader.read()
 
 
 class SensitivityTester(SensitivityTestHelper):
@@ -282,6 +288,87 @@ class SensitivityPlotTester(SensitivityTestHelper):
             self.reader.plot("THIS SHOULD FAIL")
 
 
+class Sens2MatlabHelper(SensitivityTestHelper):
+    """Base class for comparing sensitivity reader to matlab"""
+
+    def setUp(self):
+        convertIx = int(self.RECONVERT)
+        self.attrMap = {
+            key: value[convertIx] for key, value in iteritems(
+                SensitivityReader._RECONVERT_ATTR_MAP)}
+        self.listMap = {
+            key: value[convertIx] for key, value in iteritems(
+                SensitivityReader._RECONVERT_LIST_MAP)}
+        self.sensFmts = SensitivityReader._RECONVERT_SENS_FMT[convertIx]
+
+    def _testGathered(self, gathered):
+        """Test the contents of the gathered data"""
+        # attributes
+        for attr, expKey in iteritems(self.attrMap):
+            self.assertTrue(expKey in gathered, msg=expKey)
+            expVal = getattr(self.reader, attr)
+            actVal = gathered[expKey]
+            assert_array_equal(actVal, expVal, err_msg=expKey)
+
+        # lists -> compare against ordered dictionaries
+        for attr, expKey in iteritems(self.listMap):
+            self.assertTrue(expKey in gathered, msg=expKey)
+            expVal = list(getattr(self.reader, attr).keys())
+            actVal = gathered[expKey]
+            assert_array_equal(actVal, expVal, err_msg=expKey)
+
+        for sensKey, expSens in iteritems(self.reader.sensitivities):
+            expEneSens = self.reader.energyIntegratedSens[sensKey]
+            sensName, eneName = [fmt.format(sensKey) for fmt in self.sensFmts]
+            self.assertTrue(sensName in gathered,
+                            msg="{}//{}".format(sensKey, sensName))
+            self.assertTrue(eneName in gathered,
+                            msg="{}//{}".format(sensKey, eneName))
+            actSens = gathered[sensName]
+            actEneSens = gathered[eneName]
+            assert_array_equal(actSens, expSens,
+                               err_msg="{}//{}".format(sensKey, sensName))
+            assert_array_equal(actEneSens, expEneSens,
+                               err_msg="{}//{}".format(sensKey, eneName))
+
+    def test_gatherMatlab(self):
+        """Test the readers ability to gather for matlab"""
+        gathered = self.reader._gather_matlab(self.RECONVERT)
+        self._testGathered(gathered)
+
+    @skipUnless(HAS_SCIPY, "SCIPY needed for this test")
+    def test_toMatlab(self):
+        """Verify the contents of the reader can be written to matlab"""
+        from scipy.io import loadmat
+        fp = "sens2matlab_r{}.mat".format(int(self.RECONVERT))
+        toMatlab(self.reader, fp)
+        gathered = loadmat(fp)
+        # some vectors will be written as 2D row/column vectors
+        # need to reshape them to 1D arrays
+        keys = gathered.keys()
+        for key in keys:
+            if key[:2] == '__':  # special stuff from savemat
+                continue
+            value = gathered[key]
+            if value.size > 1 and 1 in value.shape:
+                gathered[key] = value.flatten()
+
+        remove(fp)
+
+
+class ReconvertedSens2MatlabTester(Sens2MatlabHelper):
+    """Class for testing the sens - matlab conversion with original names"""
+    RECONVERT = True
+
+
+class UnconvertedSens2MatlabTester(Sens2MatlabHelper):
+    """Class for testing the sens - matlab conversion with unconverted names"""
+    RECONVERT = False
+
+
+del Sens2MatlabHelper
+
+
 if __name__ == '__main__':
     from unittest import main
     main()
diff --git a/serpentTools/tests/test_settings.py b/serpentTools/tests/test_settings.py
index 22671b9..b4d60a2 100644
--- a/serpentTools/tests/test_settings.py
+++ b/serpentTools/tests/test_settings.py
@@ -112,6 +112,7 @@ class ConfigLoaderTester(TestCaseWithLogCapture):
     @classmethod
     def setUpClass(cls):
         cls.configSettings = {
+            'branching.areUncsPresent': True,
             'branching.floatVariables': ['Bhi', 'Tlo'],
             'verbosity': 'warning',
             'depletion.materials': ['fuel*'],
@@ -119,6 +120,8 @@ class ConfigLoaderTester(TestCaseWithLogCapture):
         }
         cls.nestedSettings = {
             'branching': {
+                'areUncsPresent':
+                    cls.configSettings['branching.areUncsPresent'],
                 'floatVariables':
                     cls.configSettings['branching.floatVariables']
             },