Index: .gitignore
===================================================================
--- .gitignore	(revision 153b75a64d88ad8b0597c08dada6ae0ca20c08d1)
+++ .gitignore	(revision 3fca52c4f75eb23b57cb047514c6a35696eea2b6)
@@ -39,4 +39,5 @@
 
 # test outputs
+/.eggs
 /test/pr_inversion/test/test_output.txt
 /test/sasdataloader/test/plugins.zip
Index: LICENSE.TXT
===================================================================
--- LICENSE.TXT	(revision b01252e4d2bf882c4e3550f0f724855d350201fc)
+++ LICENSE.TXT	(revision 94cd1d6035c22af0d02cbf7abc8cffbc6ac3b956)
@@ -1,3 +1,3 @@
-Copyright (c) 2009-2018, SasView Developers
+Copyright (c) 2009-2019, SasView Developers
 All rights reserved.
 
Index: conftest.py
===================================================================
--- conftest.py	(revision 3fca52c4f75eb23b57cb047514c6a35696eea2b6)
+++ conftest.py	(revision 3fca52c4f75eb23b57cb047514c6a35696eea2b6)
@@ -0,0 +1,7 @@
+"""
+Pytest configuration file.
+"""
+
+# Prepare the runtime environment for the tests
+import run
+run.prepare()
Index: docs/sphinx-docs/source/conf.py
===================================================================
--- docs/sphinx-docs/source/conf.py	(revision b229a3bf14cf52237670dc67090e092cbe9939db)
+++ docs/sphinx-docs/source/conf.py	(revision db8805f53d4aded2e417ff1a82f30d2150960876)
@@ -25,4 +25,10 @@
 print("-- path --")
 print("\n".join(sys.path))
+
+#need to import src.sas.sasview init to access version number and dates
+#use abspath as above to locate then import
+sasview_path = os.path.abspath('../../../src/sas')
+sys.path.append(sasview_path)
+import sas.sasview
 
 # -- General configuration -----------------------------------------------------
@@ -71,6 +77,7 @@
 
 # General information about the project.
+copyright_date = sas.sasview.__release_date__
 project = u'SasView'
-copyright = u'2018, The SasView Project'
+copyright = u'%s, The SasView Project' % copyright_date
 
 # The version info for the project you're documenting, acts as replacement for
@@ -79,7 +86,7 @@
 #
 # The short X.Y version.
-version = '4.2'
-# The full version, including alpha/beta/rc tags.
-release = '4.2.0'
+version = ".".join(sas.sasview.__version__.split(".", 2)[0:2]) 
+# The full version, including ax/bx tags Note strict version is enforced.
+release = sas.sasview.__version__
 
 # The language for content autogenerated by Sphinx. Refer to documentation
Index: docs/sphinx-docs/source/user/RELEASE.rst
===================================================================
--- docs/sphinx-docs/source/user/RELEASE.rst	(revision 67ed5438043ca99c016f8a5ca333aea21e13ddc4)
+++ docs/sphinx-docs/source/user/RELEASE.rst	(revision 8514f8955871de6ea7af23297d51f3e052aa3fdf)
@@ -9,4 +9,34 @@
 Features
 ========
+
+New in Version 4.2.1
+--------------------
+The major changes for this point release were to fix several problems with using
+the built in editor to create new models and to bring the NXcanSAS reader into
+compliance with the final published specification.  The orignal reader was
+based on a draft version of the specification.  As an early adopter,
+interpretation and implementation of the spec was iterated with all producers
+of NXcanSAS reduced data known to the SasView team in order to ensure
+compatibility and verify the implementation.  A few other enhancements and bug
+fixed were also introduced such as cleaning up the resolution section of the
+fitting page GUI, increasing the max size range allowed in the corfunc
+analysis, and adding the incomplete gamma function to the python library. 
+
+Resolved Issues
+^^^^^^^^^^^^^^^
+* Fixes #  976:	CanSas HDF reader will not read all valid CanSas HDF (NXcanSAS) files
+* Fixes # 1074:	Add incomplete gamma function to sasmodels
+* Fixes # 1111:	Convert all input Q units to 1/A
+* Fixes # 1129:	NXcanSAS writer not writing all meta data
+* Fixes # 1142:	Plugin framework is broken
+* Fixes # 1183:	Test from creating new model reset all parameters to default in all open FitPages
+* Fixes # 1188:   Colons removed from magnetic parameter names to address Python variable issue - done in 4.2. but documented in 4.2.1
+* Fixes # 1205:	4.2 set weighting choice seems to be ignored.
+* Fixes # 1206:	Incorrect (and confusing) presentation of dQ from data in instrumental smearing section
+* Fixes # 1212:	Bug in Iqxqy plotting non rectangular / square matrices?
+* Fixes # 1221:	ABS reader does not read in USANS data properly	GitHub
+* Fixes # 1222:	smearing options incorrect on show2D and show1D in fitpage14: Loading a saved project is really really slow
+* Fixes # 1223:	Expand permitted range of transformed data in Corfunc implementation
+
 
 New in Version 4.2.0
@@ -126,5 +156,5 @@
 * Fixes # 784: Add 3D integral to Correlation Function analysis
 * Fixes # 786: core_shell_parallelepiped 1-D model is incorrect
-* Fixes # 818: report button followed by save makes an empty pdf file???
+* Fixes # 818: âreport buttonâ followed by âsaveâ makes an empty pdf file???
 * Fixes # 830: Check compliance of loader against NXcanSAS-1.0 release
 * Fixes # 838: Fix model download from marketplace
Index: installers/license.txt
===================================================================
--- installers/license.txt	(revision c6a4d1432c516fabc19624b0845742d0074dee0e)
+++ installers/license.txt	(revision 55fa530cb8effccf6a3c046de8e306925b050cb4)
@@ -20,5 +20,5 @@
 SasView is free to download and use, including for commercial purposes.
 
-© 2009-2018 UMD, UTK, NIST, ORNL, ISIS, ESS, ANSTO, ILL, TUD, DLS, BAM  
+© 2009-2019 UMD, UTK, NIST, ORNL, ISIS, ESS, ANSTO, ILL, TUD, DLS, BAM  
 
 
Index: run.py
===================================================================
--- run.py	(revision bc8b8a1eb1a0f65ae6814fb0a8aabf3e2dce40b6)
+++ run.py	(revision 952ea1fd0d931d2eae09831204ea057abfe5450f)
@@ -67,5 +67,5 @@
 
 
-def prepare():
+def prepare(rebuild=True):
     # Don't create *.pyc files
     sys.dont_write_bytecode = True
@@ -95,15 +95,15 @@
     try:
         import periodictable
-    except:
+    except ImportError:
         addpath(joinpath(root, '..', 'periodictable'))
 
     try:
         import bumps
-    except:
+    except ImportError:
         addpath(joinpath(root, '..', 'bumps'))
 
     try:
         import tinycc
-    except:
+    except ImportError:
         addpath(joinpath(root, '../tinycc/build/lib'))
 
@@ -111,9 +111,22 @@
     #addpath(os.path.join(root, '..','wxPython-src-3.0.0.0','wxPython'))
 
-    # Build project if the build directory does not already exist.
-    # PAK: with "update" we can always build since it is fast
-    if True or not os.path.exists(build_path):
+    # Put the sas source tree on the path
+    addpath(joinpath(root, 'src'))
+
+    # Put sasmodels on the path
+    addpath(joinpath(root, '../sasmodels/'))
+
+    # Check if the C extensions are already built
+    try:
+        from sas.sascalc.pr import _pr_inversion
+        from sas.sascalc.calculator import _sld2i
+        from sas.sascalc.file_converter import _bsl_loader
+    except ImportError:
+        rebuild = True
+
+    # Build C extensions if necessary.  Do an inplace build to simplify path.
+    if rebuild:
         import subprocess
-        build_cmd = [sys.executable, "setup.py", "build", "update"]
+        build_cmd = [sys.executable, "setup.py", "build_ext", "--inplace", "update"]
         if os.name == 'nt':
             build_cmd.append('--compiler=tinycc')
@@ -122,31 +135,4 @@
         with cd(root):
             subprocess.call(build_cmd, shell=shell)
-
-    # Put the source trees on the path
-    addpath(joinpath(root, 'src'))
-
-    # sasmodels on the path
-    addpath(joinpath(root, '../sasmodels/'))
-
-    # The sas.models package Compiled Model files should be pulled in from the build directory even though
-    # the source is stored in src/sas/models.
-
-    # Compiled modules need to be pulled from the build directory.
-    # Some packages are not where they are needed, so load them explicitly.
-    import sas.sascalc.pr
-    sas.sascalc.pr.core = import_package('sas.sascalc.pr.core',
-                                         joinpath(build_path, 'sas', 'sascalc', 'pr', 'core'))
-
-    # Compiled modules need to be pulled from the build directory.
-    # Some packages are not where they are needed, so load them explicitly.
-    import sas.sascalc.file_converter
-    sas.sascalc.file_converter.core = import_package('sas.sascalc.file_converter.core',
-                                                     joinpath(build_path, 'sas', 'sascalc', 'file_converter', 'core'))
-
-    import sas.sascalc.calculator
-    sas.sascalc.calculator.core = import_package('sas.sascalc.calculator.core',
-                                                 joinpath(build_path, 'sas', 'sascalc', 'calculator', 'core'))
-
-    sys.path.append(build_path)
 
     set_git_tag()
Index: setup.py
===================================================================
--- setup.py	(revision c16172d313e67da70e771029395ec7bd2bdba4e6)
+++ setup.py	(revision 46119c2f4dbe06ef0ff27514ccf0b4cbc4493762)
@@ -12,9 +12,10 @@
 import shutil
 import sys
-from distutils.command.build_ext import build_ext
-from distutils.core import Command
 
 import numpy as np
+
 from setuptools import Extension, setup
+from setuptools import Command
+from setuptools.command.build_ext import build_ext
 
 try:
@@ -22,4 +23,7 @@
 except ImportError:
     pass
+
+# Convert "test" argument to "pytest" so 'python setup.py test' works
+sys.argv = [("pytest" if s == "test" else s) for s in sys.argv]
 
 # Manage version number ######################################
@@ -51,23 +55,4 @@
 CURRENT_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 SASVIEW_BUILD = os.path.join(CURRENT_SCRIPT_DIR, "build")
-
-# TODO: build step should not be messing with existing installation!!
-sas_dir = os.path.join(os.path.expanduser("~"), '.sasview')
-if os.path.isdir(sas_dir):
-    f_path = os.path.join(sas_dir, "sasview.log")
-    if os.path.isfile(f_path):
-        os.remove(f_path)
-    f_path = os.path.join(sas_dir, "categories.json")
-    if os.path.isfile(f_path):
-        os.remove(f_path)
-    f_path = os.path.join(sas_dir, 'config', "custom_config.py")
-    if os.path.isfile(f_path):
-        os.remove(f_path)
-    #f_path = os.path.join(sas_dir, 'plugin_models')
-    # if os.path.isdir(f_path):
-    #     for f in os.listdir(f_path):
-    #         if f in plugin_model_list:
-    #             file_path =  os.path.join(f_path, f)
-    #             os.remove(file_path)
 
 
@@ -246,9 +231,8 @@
 # sas.sascalc.calculator
 gen_dir = os.path.join("src", "sas", "sascalc", "calculator", "c_extensions")
-package_dir["sas.sascalc.calculator.core"] = gen_dir
 package_dir["sas.sascalc.calculator"] = os.path.join(
     "src", "sas", "sascalc", "calculator")
-packages.extend(["sas.sascalc.calculator", "sas.sascalc.calculator.core"])
-ext_modules.append(Extension("sas.sascalc.calculator.core.sld2i",
+packages.append("sas.sascalc.calculator")
+ext_modules.append(Extension("sas.sascalc.calculator._sld2i",
                              sources=[
                                  os.path.join(gen_dir, "sld2i_module.c"),
@@ -258,13 +242,11 @@
                              ],
                              include_dirs=[gen_dir],
-                             )
-                   )
+                             ))
 
 # sas.sascalc.pr
 srcdir = os.path.join("src", "sas", "sascalc", "pr", "c_extensions")
-package_dir["sas.sascalc.pr.core"] = srcdir
 package_dir["sas.sascalc.pr"] = os.path.join("src", "sas", "sascalc", "pr")
-packages.extend(["sas.sascalc.pr", "sas.sascalc.pr.core"])
-ext_modules.append(Extension("sas.sascalc.pr.core.pr_inversion",
+packages.append("sas.sascalc.pr")
+ext_modules.append(Extension("sas.sascalc.pr._pr_inversion",
                              sources=[os.path.join(srcdir, "Cinvertor.c"),
                                       os.path.join(srcdir, "invertor.c"),
@@ -276,10 +258,8 @@
 # sas.sascalc.file_converter
 mydir = os.path.join("src", "sas", "sascalc", "file_converter", "c_ext")
-package_dir["sas.sascalc.file_converter.core"] = mydir
 package_dir["sas.sascalc.file_converter"] = os.path.join(
     "src", "sas", "sascalc", "file_converter")
-packages.extend(["sas.sascalc.file_converter",
-                 "sas.sascalc.file_converter.core"])
-ext_modules.append(Extension("sas.sascalc.file_converter.core.bsl_loader",
+packages.append("sas.sascalc.file_converter")
+ext_modules.append(Extension("sas.sascalc.file_converter._bsl_loader",
                              sources=[os.path.join(mydir, "bsl_loader.c")],
                              include_dirs=[np.get_include()],
@@ -443,4 +423,6 @@
     cmdclass={'build_ext': build_ext_subclass,
               'docs': BuildSphinxCommand,
-              'disable_openmp': DisableOpenMPCommand}
+              'disable_openmp': DisableOpenMPCommand},
+    setup_requires=['pytest-runner'] if 'pytest' in sys.argv else [],
+    tests_require=['pytest'],
 )
Index: src/sas/_config.py
===================================================================
--- src/sas/_config.py	(revision b963b2066d6a76fe5073000c5a596a6fd0130ac4)
+++ src/sas/_config.py	(revision 93b34cc20c889f8987e6e4767a8fefae8cea7f78)
@@ -86,4 +86,5 @@
 def setup_custom_config(app_dir, user_dir):
     path = make_custom_config_path(user_dir)
+    #logger.info("custom config path %s", path)
     if not os.path.isfile(path):
         try:
@@ -94,15 +95,16 @@
             logger.error("Could not copy default custom config.")
 
+    custom_config = load_custom_config(path)
+
     #Adding SAS_OPENCL if it doesn't exist in the config file
     # - to support backcompability
-    if not "SAS_OPENCL" in open(path).read():
+    if not hasattr(custom_config, "SAS_OPENCL"):
+        custom_config.SAS_OPENCL = None
         try:
-            open(config_file, "a+").write("SAS_OPENCL = \"None\"\n")
+            open(path, "a+").write("SAS_OPENCL = \"None\"\n")
         except Exception:
             logger.error("Could not update custom config with SAS_OPENCL.")
 
-    custom_config = load_custom_config(path)
     return custom_config
-
 
 def load_custom_config(path):
Index: c/sas/sascalc/calculator/c_extensions/__init__.py
===================================================================
--- src/sas/sascalc/calculator/c_extensions/__init__.py	(revision a57ae0704487b63fbba07d89eff101d45ec4a470)
+++ 	(revision )
@@ -1,3 +1,0 @@
-"""
-    C extensions to provide the sas_gen computations.
-"""
Index: src/sas/sascalc/calculator/c_extensions/sld2i_module.c
===================================================================
--- src/sas/sascalc/calculator/c_extensions/sld2i_module.c	(revision a1daf86c0d7d0aba84e29d778ffd6148e933d93a)
+++ src/sas/sascalc/calculator/c_extensions/sld2i_module.c	(revision 7ba64705ddaa18ab8bce14ae2ac2e767b23eb313)
@@ -2,6 +2,9 @@
   SLD2I module to perform point and I calculations
  */
+#include <stdio.h>
+
+//#define Py_LIMITED_API 0x03020000
 #include <Python.h>
-#include <stdio.h>
+
 #include "sld2i.h"
 
@@ -13,20 +16,24 @@
 #endif
 
-
-// Utilities
-#define INVECTOR(obj,buf,len)										\
-    do { \
-        int err = PyObject_AsReadBuffer(obj, (const void **)(&buf), &len); \
-        if (err < 0) return NULL; \
-        len /= sizeof(*buf); \
-    } while (0)
-
-#define OUTVECTOR(obj,buf,len) \
-    do { \
-        int err = PyObject_AsWriteBuffer(obj, (void **)(&buf), &len); \
-        if (err < 0) return NULL; \
-        len /= sizeof(*buf); \
-    } while (0)
-
+// Vector binding glue
+#if (PY_VERSION_HEX > 0x03000000) && !defined(Py_LIMITED_API)
+  // Assuming that a view into a writable vector points to a 
+  // non-changing pointer for the duration of the C call, capture 
+  // the view pointer and immediately free the view.
+  #define VECTOR(VEC_obj, VEC_buf, VEC_len) do { \
+    Py_buffer VEC_view; \
+    int VEC_err = PyObject_GetBuffer(VEC_obj, &VEC_view, PyBUF_WRITABLE|PyBUF_FORMAT); \
+    if (VEC_err < 0 || sizeof(*VEC_buf) != VEC_view.itemsize) return NULL; \
+    VEC_buf = (typeof(VEC_buf))VEC_view.buf; \
+    VEC_len = VEC_view.len/sizeof(*VEC_buf); \
+    PyBuffer_Release(&VEC_view); \
+  } while (0)
+#else
+  #define VECTOR(VEC_obj, VEC_buf, VEC_len) do { \
+    int VEC_err = PyObject_AsWriteBuffer(VEC_obj, (void **)(&VEC_buf), &VEC_len); \
+    if (VEC_err < 0) return NULL; \
+    VEC_len /= sizeof(*VEC_buf); \
+  } while (0)
+#endif
 
 /**
@@ -73,12 +80,12 @@
 	//printf("new GenI\n");
 	if (!PyArg_ParseTuple(args, "iOOOOOOOOddd", &is_avg, &x_val_obj, &y_val_obj, &z_val_obj, &sldn_val_obj, &mx_val_obj, &my_val_obj, &mz_val_obj, &vol_pix_obj, &inspin, &outspin, &stheta)) return NULL;
-	INVECTOR(x_val_obj, x_val, n_x);
-	INVECTOR(y_val_obj, y_val, n_y);
-	INVECTOR(z_val_obj, z_val, n_z);
-	INVECTOR(sldn_val_obj, sldn_val, n_sld);
-	INVECTOR(mx_val_obj, mx_val, n_mx);
-	INVECTOR(my_val_obj, my_val, n_my);
-	INVECTOR(mz_val_obj, mz_val, n_mz);
-	INVECTOR(vol_pix_obj, vol_pix, n_vol_pix);
+	VECTOR(x_val_obj, x_val, n_x);
+	VECTOR(y_val_obj, y_val, n_y);
+	VECTOR(z_val_obj, z_val, n_z);
+	VECTOR(sldn_val_obj, sldn_val, n_sld);
+	VECTOR(mx_val_obj, mx_val, n_mx);
+	VECTOR(my_val_obj, my_val, n_my);
+	VECTOR(mz_val_obj, mz_val, n_mz);
+	VECTOR(vol_pix_obj, vol_pix, n_vol_pix);
 	sld2i = PyMem_Malloc(sizeof(GenI));
 	//printf("sldi:%p\n", sld2i);
@@ -108,7 +115,7 @@
 	if (!PyArg_ParseTuple(args, "OOOO",  &gen_obj, &qx_obj, &qy_obj, &I_out_obj)) return NULL;
 	sld2i = (GenI *)PyCapsule_GetPointer(gen_obj, "GenI");
-	INVECTOR(qx_obj, qx, n_qx);
-	INVECTOR(qy_obj, qy, n_qy);
-	OUTVECTOR(I_out_obj, I_out, n_out);
+	VECTOR(qx_obj, qx, n_qx);
+	VECTOR(qy_obj, qy, n_qy);
+	VECTOR(I_out_obj, I_out, n_out);
 	//printf("qx, qy, I_out: %d %d %d, %d %d %d\n", qx, qy, I_out, n_qx, n_qy, n_out);
 
@@ -136,6 +143,6 @@
 	if (!PyArg_ParseTuple(args, "OOO",  &gen_obj, &q_obj, &I_out_obj)) return NULL;
 	sld2i = (GenI *)PyCapsule_GetPointer(gen_obj, "GenI");
-	INVECTOR(q_obj, q, n_q);
-	OUTVECTOR(I_out_obj, I_out, n_out);
+	VECTOR(q_obj, q, n_q);
+	VECTOR(I_out_obj, I_out, n_out);
 
 	// Sanity check
@@ -160,7 +167,7 @@
 
 #define MODULE_DOC "Sld2i C Library"
-#define MODULE_NAME "sld2i"
-#define MODULE_INIT2 initsld2i
-#define MODULE_INIT3 PyInit_sld2i
+#define MODULE_NAME "_sld2i"
+#define MODULE_INIT2 init_sld2i
+#define MODULE_INIT3 PyInit__sld2i
 #define MODULE_METHODS module_methods
 
Index: src/sas/sascalc/calculator/sas_gen.py
===================================================================
--- src/sas/sascalc/calculator/sas_gen.py	(revision 144e032af2559d8208e907563f404ab479862dbf)
+++ src/sas/sascalc/calculator/sas_gen.py	(revision 952ea1fd0d931d2eae09831204ea057abfe5450f)
@@ -14,5 +14,5 @@
 import numpy as np
 
-from .core import sld2i as mod
+from . import _sld2i
 from .BaseComponent import BaseComponent
 
@@ -145,15 +145,15 @@
             self.params['Up_frac_out'],
             self.params['Up_theta'])
-        model = mod.new_GenI(*args)
+        model = _sld2i.new_GenI(*args)
         if len(qy):
             qx, qy = _vec(qx), _vec(qy)
             I_out = np.empty_like(qx)
             #print("npoints", qx.shape, "npixels", pos_x.shape)
-            mod.genicomXY(model, qx, qy, I_out)
+            _sld2i.genicomXY(model, qx, qy, I_out)
             #print("I_out after", I_out)
         else:
             qx = _vec(qx)
             I_out = np.empty_like(qx)
-            mod.genicom(model, qx, I_out)
+            _sld2i.genicom(model, qx, I_out)
         vol_correction = self.data_total_volume / self.params['total_volume']
         result = (self.params['scale'] * vol_correction * I_out
@@ -304,6 +304,6 @@
                 z_dir2 *= z_dir2
                 mask = (x_dir2 + y_dir2 + z_dir2) <= 1.0
-            except Exception:
-                logger.error(sys.exc_value)
+            except Exception as exc:
+                logger.error(exc)
         self.output = MagSLD(self.pos_x[mask], self.pos_y[mask],
                              self.pos_z[mask], self.sld_n[mask],
@@ -600,6 +600,6 @@
                         y_lines.append(y_line)
                         z_lines.append(z_line)
-                except Exception:
-                    logger.error(sys.exc_value)
+                except Exception as exc:
+                    logger.error(exc)
 
             output = MagSLD(pos_x, pos_y, pos_z, sld_n, sld_mx, sld_my, sld_mz)
@@ -691,9 +691,9 @@
                             _vol_pix = float(toks[7])
                             vol_pix = np.append(vol_pix, _vol_pix)
-                        except Exception:
+                        except Exception as exc:
                             vol_pix = None
-                    except Exception:
+                    except Exception as exc:
                         # Skip non-data lines
-                        logger.error(sys.exc_value)
+                        logger.error(exc)
             output = MagSLD(pos_x, pos_y, pos_z, sld_n,
                             sld_mx, sld_my, sld_mz)
Index: src/sas/sascalc/corfunc/transform_thread.py
===================================================================
--- src/sas/sascalc/corfunc/transform_thread.py	(revision a859f9916f07adbcfeb4bebd403b46e6f32d18a7)
+++ src/sas/sascalc/corfunc/transform_thread.py	(revision ef74a8b4c5fbc72695853e60c09c0379d8d1c2c6)
@@ -45,5 +45,5 @@
             # gamma3(R) = 1/R int_{0}^{R} gamma1(x) dx
             # trapz uses the trapezium rule to calculate the integral
-            mask = xs <= 200.0 # Only calculate gamma3 up to x=200 (as this is all that's plotted)
+            mask = xs <= 1000.0 # Only calculate gamma3 up to x=1000 (as this is all that's plotted)
             # gamma3 = [trapz(gamma1[:n], xs[:n])/xs[n-1] for n in range(2, len(xs[mask]) + 1)]j
             # gamma3.insert(0, 1.0) # Gamma_3(0) is defined as 1
@@ -79,5 +79,5 @@
 
         transform1 = Data1D(xs, gamma1)
-        transform3 = Data1D(xs[xs <= 200], gamma3)
+        transform3 = Data1D(xs[xs <= 1000], gamma3)
         idf = Data1D(xs, idf)
 
Index: src/sas/sascalc/data_util/nxsunit.py
===================================================================
--- src/sas/sascalc/data_util/nxsunit.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
+++ src/sas/sascalc/data_util/nxsunit.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
@@ -135,6 +135,7 @@
     sld = { '10^-6 Angstrom^-2': 1e-6, 'Angstrom^-2': 1 }
     Q = { 'invA': 1, 'invAng': 1, 'invAngstroms': 1, '1/A': 1,
+          '1/Angstrom': 1, '1/angstrom': 1, 'A^{-1}': 1, 'cm^{-1}': 1e-8,
           '10^-3 Angstrom^-1': 1e-3, '1/cm': 1e-8, '1/m': 1e-10,
-          'nm^-1': 0.1, '1/nm': 0.1, 'n_m^-1': 0.1 }
+          'nm^{-1}': 1, 'nm^-1': 0.1, '1/nm': 0.1, 'n_m^-1': 0.1 }
 
     _caret_optional(sld)
@@ -156,5 +157,5 @@
     # units for that particular dimension.
     # Note: don't have support for dimensionless units.
-    unknown = {None:1, '???':1, '': 1, 'a.u.': 1}
+    unknown = {None:1, '???':1, '': 1, 'a.u.': 1, 'Counts': 1, 'counts': 1}
 
     def __init__(self, name):
Index: src/sas/sascalc/dataloader/data_info.py
===================================================================
--- src/sas/sascalc/dataloader/data_info.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
+++ src/sas/sascalc/dataloader/data_info.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
@@ -957,5 +957,6 @@
         _str += "Data:\n"
         _str += "   Type:         %s\n" % self.__class__.__name__
-        _str += "   X- & Y-axis:  %s\t[%s]\n" % (self._yaxis, self._yunit)
+        _str += "   X-axis:       %s\t[%s]\n" % (self._xaxis, self._xunit)
+        _str += "   Y-axis:       %s\t[%s]\n" % (self._yaxis, self._yunit)
         _str += "   Z-axis:       %s\t[%s]\n" % (self._zaxis, self._zunit)
         _str += "   Length:       %g \n" % (len(self.data))
@@ -986,4 +987,13 @@
                            qx_data=qx_data, qy_data=qy_data,
                            q_data=q_data, mask=mask)
+
+        clone._xaxis = self._xaxis
+        clone._yaxis = self._yaxis
+        clone._zaxis = self._zaxis
+        clone._xunit = self._xunit
+        clone._yunit = self._yunit
+        clone._zunit = self._zunit
+        clone.x_bins = self.x_bins
+        clone.y_bins = self.y_bins
 
         clone.title = self.title
@@ -1156,5 +1166,6 @@
 def combine_data_info_with_plottable(data, datainfo):
     """
-    A function that combines the DataInfo data in self.current_datainto with a plottable_1D or 2D data object.
+    A function that combines the DataInfo data in self.current_datainto with a
+    plottable_1D or 2D data object.
 
     :param data: A plottable_1D or plottable_2D data object
@@ -1174,16 +1185,16 @@
         final_dataset.yaxis(data._yaxis, data._yunit)
     elif isinstance(data, plottable_2D):
-        final_dataset = Data2D(data.data, data.err_data, data.qx_data, data.qy_data, data.q_data,
-                               data.mask, data.dqx_data, data.dqy_data)
+        final_dataset = Data2D(data.data, data.err_data, data.qx_data,
+                               data.qy_data, data.q_data, data.mask,
+                               data.dqx_data, data.dqy_data)
         final_dataset.xaxis(data._xaxis, data._xunit)
         final_dataset.yaxis(data._yaxis, data._yunit)
         final_dataset.zaxis(data._zaxis, data._zunit)
-        if len(data.data.shape) == 2:
-            n_rows, n_cols = data.data.shape
-            final_dataset.y_bins = data.qy_data[0::int(n_cols)]
-            final_dataset.x_bins = data.qx_data[:int(n_cols)]
+        final_dataset.y_bins = data.y_bins
+        final_dataset.x_bins = data.x_bins
     else:
-        return_string = "Should Never Happen: _combine_data_info_with_plottable input is not a plottable1d or " + \
-                        "plottable2d data object"
+        return_string = ("Should Never Happen: _combine_data_info_with_plottabl"
+                         "e input is not a plottable1d or plottable2d data "
+                         "object")
         return return_string
 
Index: src/sas/sascalc/dataloader/file_reader_base_class.py
===================================================================
--- src/sas/sascalc/dataloader/file_reader_base_class.py	(revision 4a8d55c05d1355e27bf5afa880633879b6178acc)
+++ src/sas/sascalc/dataloader/file_reader_base_class.py	(revision fee520ecb8daf1211d988303a9ed0f650c777fb5)
@@ -16,4 +16,5 @@
 from .data_info import Data1D, Data2D, DataInfo, plottable_1D, plottable_2D,\
     combine_data_info_with_plottable
+from sas.sascalc.data_util.nxsunit import Converter
 
 logger = logging.getLogger(__name__)
@@ -37,4 +38,5 @@
                        "SasView cannot guarantee the accuracy of the data.")
 
+
 class FileReader(object):
     # String to describe the type of data this reader can load
@@ -45,5 +47,5 @@
     ext = ['.txt']
     # Deprecated extensions
-    deprecated_extensions = ['.asc', '.nxs']
+    deprecated_extensions = ['.asc']
     # Bypass extension check and try to load anyway
     allow_all = False
@@ -98,6 +100,6 @@
                     if len(self.output) > 0:
                         # Sort the data that's been loaded
-                        self.sort_one_d_data()
-                        self.sort_two_d_data()
+                        self.convert_data_units()
+                        self.sort_data()
         else:
             msg = "Unable to find file at: {}\n".format(filepath)
@@ -140,5 +142,4 @@
         Returns the entire file as a string.
         """
-        #return self.f_open.read()
         return decode(self.f_open.read())
 
@@ -166,5 +167,5 @@
         self.output.append(data_obj)
 
-    def sort_one_d_data(self):
+    def sort_data(self):
         """
         Sort 1D data along the X axis for consistency
@@ -174,5 +175,7 @@
                 # Normalize the units for
                 data.x_unit = self.format_unit(data.x_unit)
+                data._xunit = data.x_unit
                 data.y_unit = self.format_unit(data.y_unit)
+                data._yunit = data.y_unit
                 # Sort data by increasing x and remove 1st point
                 ind = np.lexsort((data.y, data.x))
@@ -203,4 +206,40 @@
                     data.ymin = np.min(data.y)
                     data.ymax = np.max(data.y)
+            elif isinstance(data, Data2D):
+                # Normalize the units for
+                data.Q_unit = self.format_unit(data.Q_unit)
+                data.I_unit = self.format_unit(data.I_unit)
+                data._xunit = data.Q_unit
+                data._yunit = data.Q_unit
+                data._zunit = data.I_unit
+                data.data = data.data.astype(np.float64)
+                data.qx_data = data.qx_data.astype(np.float64)
+                data.xmin = np.min(data.qx_data)
+                data.xmax = np.max(data.qx_data)
+                data.qy_data = data.qy_data.astype(np.float64)
+                data.ymin = np.min(data.qy_data)
+                data.ymax = np.max(data.qy_data)
+                data.q_data = np.sqrt(data.qx_data * data.qx_data
+                                         + data.qy_data * data.qy_data)
+                if data.err_data is not None:
+                    data.err_data = data.err_data.astype(np.float64)
+                if data.dqx_data is not None:
+                    data.dqx_data = data.dqx_data.astype(np.float64)
+                if data.dqy_data is not None:
+                    data.dqy_data = data.dqy_data.astype(np.float64)
+                if data.mask is not None:
+                    data.mask = data.mask.astype(dtype=bool)
+
+                if len(data.data.shape) == 2:
+                    n_rows, n_cols = data.data.shape
+                    data.y_bins = data.qy_data[0::int(n_cols)]
+                    data.x_bins = data.qx_data[:int(n_cols)]
+                    data.data = data.data.flatten()
+                data = self._remove_nans_in_data(data)
+                if len(data.data) > 0:
+                    data.xmin = np.min(data.qx_data)
+                    data.xmax = np.max(data.qx_data)
+                    data.ymin = np.min(data.qy_data)
+                    data.ymax = np.max(data.qy_data)
 
     @staticmethod
@@ -242,39 +281,86 @@
         return data
 
-    def sort_two_d_data(self):
-        for dataset in self.output:
-            if isinstance(dataset, Data2D):
-                # Normalize the units for
-                dataset.x_unit = self.format_unit(dataset.Q_unit)
-                dataset.y_unit = self.format_unit(dataset.I_unit)
-                dataset.data = dataset.data.astype(np.float64)
-                dataset.qx_data = dataset.qx_data.astype(np.float64)
-                dataset.xmin = np.min(dataset.qx_data)
-                dataset.xmax = np.max(dataset.qx_data)
-                dataset.qy_data = dataset.qy_data.astype(np.float64)
-                dataset.ymin = np.min(dataset.qy_data)
-                dataset.ymax = np.max(dataset.qy_data)
-                dataset.q_data = np.sqrt(dataset.qx_data * dataset.qx_data
-                                         + dataset.qy_data * dataset.qy_data)
-                if dataset.err_data is not None:
-                    dataset.err_data = dataset.err_data.astype(np.float64)
-                if dataset.dqx_data is not None:
-                    dataset.dqx_data = dataset.dqx_data.astype(np.float64)
-                if dataset.dqy_data is not None:
-                    dataset.dqy_data = dataset.dqy_data.astype(np.float64)
-                if dataset.mask is not None:
-                    dataset.mask = dataset.mask.astype(dtype=bool)
-
-                if len(dataset.data.shape) == 2:
-                    n_rows, n_cols = dataset.data.shape
-                    dataset.y_bins = dataset.qy_data[0::int(n_cols)]
-                    dataset.x_bins = dataset.qx_data[:int(n_cols)]
-                dataset.data = dataset.data.flatten()
-                dataset = self._remove_nans_in_data(dataset)
-                if len(dataset.data) > 0:
-                    dataset.xmin = np.min(dataset.qx_data)
-                    dataset.xmax = np.max(dataset.qx_data)
-                    dataset.ymin = np.min(dataset.qy_data)
-                    dataset.ymax = np.max(dataset.qx_data)
+    @staticmethod
+    def set_default_1d_units(data):
+        """
+        Set the x and y axes to the default 1D units
+        :param data: 1D data set
+        :return:
+        """
+        data.xaxis(r"\rm{Q}", '1/A')
+        data.yaxis(r"\rm{Intensity}", "1/cm")
+        return data
+
+    @staticmethod
+    def set_default_2d_units(data):
+        """
+        Set the x and y axes to the default 2D units
+        :param data: 2D data set
+        :return:
+        """
+        data.xaxis("\\rm{Q_{x}}", '1/A')
+        data.yaxis("\\rm{Q_{y}}", '1/A')
+        data.zaxis("\\rm{Intensity}", "1/cm")
+        return data
+
+    def convert_data_units(self, default_q_unit="1/A"):
+        """
+        Converts al; data to the sasview default of units of A^{-1} for Q and
+        cm^{-1} for I.
+        :param default_q_unit: The default Q unit used by Sasview
+        """
+        convert_q = True
+        new_output = []
+        for data in self.output:
+            if data.isSesans:
+                new_output.append(data)
+                continue
+            try:
+                file_x_unit = data._xunit
+                data_conv_x = Converter(file_x_unit)
+            except KeyError:
+                logger.info("Unrecognized Q units in data file. No data "
+                            "conversion attempted")
+                convert_q = False
+            try:
+
+                if isinstance(data, Data1D):
+                        if convert_q:
+                            data.x = data_conv_x(data.x, units=default_q_unit)
+                            data._xunit = default_q_unit
+                            data.x_unit = default_q_unit
+                            if data.dx is not None:
+                                data.dx = data_conv_x(data.dx,
+                                                      units=default_q_unit)
+                            if data.dxl is not None:
+                                data.dxl = data_conv_x(data.dxl,
+                                                       units=default_q_unit)
+                            if data.dxw is not None:
+                                data.dxw = data_conv_x(data.dxw,
+                                                       units=default_q_unit)
+                elif isinstance(data, Data2D):
+                    if convert_q:
+                        data.qx_data = data_conv_x(data.qx_data,
+                                                   units=default_q_unit)
+                        if data.dqx_data is not None:
+                            data.dqx_data = data_conv_x(data.dqx_data,
+                                                        units=default_q_unit)
+                        try:
+                            file_y_unit = data._yunit
+                            data_conv_y = Converter(file_y_unit)
+                            data.qy_data = data_conv_y(data.qy_data,
+                                                       units=default_q_unit)
+                            if data.dqy_data is not None:
+                                data.dqy_data = data_conv_y(data.dqy_data,
+                                                            units=default_q_unit)
+                        except KeyError:
+                            logger.info("Unrecognized Qy units in data file. No"
+                                        " data conversion attempted")
+            except KeyError:
+                message = "Unable to convert Q units from {0} to 1/A."
+                message.format(default_q_unit)
+                data.errors.append(message)
+            new_output.append(data)
+        self.output = new_output
 
     def format_unit(self, unit=None):
@@ -367,9 +453,12 @@
                     self.current_dataset.qy_data))
             if has_error_dy:
-                self.current_dataset.err_data = self.current_dataset.err_data[x != 0]
+                self.current_dataset.err_data = self.current_dataset.err_data[
+                    x != 0]
             if has_error_dqx:
-                self.current_dataset.dqx_data = self.current_dataset.dqx_data[x != 0]
+                self.current_dataset.dqx_data = self.current_dataset.dqx_data[
+                    x != 0]
             if has_error_dqy:
-                self.current_dataset.dqy_data = self.current_dataset.dqy_data[x != 0]
+                self.current_dataset.dqy_data = self.current_dataset.dqy_data[
+                    x != 0]
             if has_mask:
                 self.current_dataset.mask = self.current_dataset.mask[x != 0]
Index: src/sas/sascalc/dataloader/loader.py
===================================================================
--- src/sas/sascalc/dataloader/loader.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
+++ src/sas/sascalc/dataloader/loader.py	(revision b1ec23da8185a2a0dbda947ce190774e0b87aa90)
@@ -367,8 +367,9 @@
             try:
                 return fn(path, data)
-            except Exception:
-                pass  # give other loaders a chance to succeed
-        # If we get here it is because all loaders failed
-        raise  # reraises last exception
+            except Exception as exc:
+                msg = "Saving file {} using the {} writer failed.\n".format(
+                    path, type(fn).__name__)
+                msg += str(exc)
+                logger.exception(msg)  # give other loaders a chance to succeed
 
 
Index: src/sas/sascalc/dataloader/readers/abs_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/abs_reader.py	(revision bd5c3b11a604dfd75fa3d6424e1ea40bcafd3727)
+++ src/sas/sascalc/dataloader/readers/abs_reader.py	(revision d96744de9a57d30dd495ba032913ed4268252bf5)
@@ -48,4 +48,5 @@
         detector = Detector()
         data_line = 0
+        x_index = 4
         self.reset_data_list(len(lines))
         self.current_datainfo.detector.append(detector)
@@ -63,4 +64,6 @@
         for line in lines:
             # Information line 1
+            if line.find(".bt5") > 0:
+                x_index = 0
             if is_info:
                 is_info = False
@@ -171,5 +174,5 @@
 
                 try:
-                    _x = float(toks[4])
+                    _x = float(toks[x_index])
                     _y = float(toks[1])
                     _dy = float(toks[2])
@@ -225,12 +228,9 @@
             raise ValueError("ascii_reader: could not load file")
 
+        self.current_dataset = self.set_default_1d_units(self.current_dataset)
         if data_conv_q is not None:
             self.current_dataset.xaxis("\\rm{Q}", base_q_unit)
-        else:
-            self.current_dataset.xaxis("\\rm{Q}", 'A^{-1}')
         if data_conv_i is not None:
             self.current_dataset.yaxis("\\rm{Intensity}", base_i_unit)
-        else:
-            self.current_dataset.yaxis("\\rm{Intensity}", "cm^{-1}")
 
         # Store loading process information
Index: src/sas/sascalc/dataloader/readers/ascii_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/ascii_reader.py	(revision 7b07fbe306fb8a4fe61838f12a869394e2e47c0a)
+++ src/sas/sascalc/dataloader/readers/ascii_reader.py	(revision 3bab401d91e365ff93f8efbf5368655767ff2e5f)
@@ -157,6 +157,5 @@
 
         self.remove_empty_q_values()
-        self.current_dataset.xaxis("\\rm{Q}", 'A^{-1}')
-        self.current_dataset.yaxis("\\rm{Intensity}", "cm^{-1}")
+        self.current_dataset = self.set_default_1d_units(self.current_dataset)
 
         # Store loading process information
Index: src/sas/sascalc/dataloader/readers/associations.py
===================================================================
--- src/sas/sascalc/dataloader/readers/associations.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
+++ src/sas/sascalc/dataloader/readers/associations.py	(revision c7c814358a478ddea9a6f8b57a46374c443b4776)
@@ -23,4 +23,5 @@
     ".ses": "sesans_reader",
     ".h5": "cansas_reader_HDF5",
+    ".nxs": "cansas_reader_HDF5",
     ".txt": "ascii_reader",
     ".dat": "red2d_reader",
Index: src/sas/sascalc/dataloader/readers/cansas_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/cansas_reader.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
+++ src/sas/sascalc/dataloader/readers/cansas_reader.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
@@ -812,20 +812,20 @@
             node.append(point)
             self.write_node(point, "Q", datainfo.x[i],
-                            {'unit': datainfo.x_unit})
+                            {'unit': datainfo._xunit})
             if len(datainfo.y) >= i:
                 self.write_node(point, "I", datainfo.y[i],
-                                {'unit': datainfo.y_unit})
+                                {'unit': datainfo._yunit})
             if datainfo.dy is not None and len(datainfo.dy) > i:
                 self.write_node(point, "Idev", datainfo.dy[i],
-                                {'unit': datainfo.y_unit})
+                                {'unit': datainfo._yunit})
             if datainfo.dx is not None and len(datainfo.dx) > i:
                 self.write_node(point, "Qdev", datainfo.dx[i],
-                                {'unit': datainfo.x_unit})
+                                {'unit': datainfo._xunit})
             if datainfo.dxw is not None and len(datainfo.dxw) > i:
                 self.write_node(point, "dQw", datainfo.dxw[i],
-                                {'unit': datainfo.x_unit})
+                                {'unit': datainfo._xunit})
             if datainfo.dxl is not None and len(datainfo.dxl) > i:
                 self.write_node(point, "dQl", datainfo.dxl[i],
-                                {'unit': datainfo.x_unit})
+                                {'unit': datainfo._xunit})
         if datainfo.isSesans:
             sesans_attrib = {'x_axis': datainfo._xaxis,
Index: src/sas/sascalc/dataloader/readers/danse_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/danse_reader.py	(revision 2469df7fc9ffa047115c5bffe589ed307b12c363)
+++ src/sas/sascalc/dataloader/readers/danse_reader.py	(revision fc51d06ca61c96f09100f834da5f2bd421f461f7)
@@ -180,9 +180,5 @@
         detector.beam_center.y = center_y * pixel
 
-
-        self.current_dataset.xaxis("\\rm{Q_{x}}", 'A^{-1}')
-        self.current_dataset.yaxis("\\rm{Q_{y}}", 'A^{-1}')
-        self.current_dataset.zaxis("\\rm{Intensity}", "cm^{-1}")
-
+        self.current_dataset = self.set_default_2d_units(self.current_dataset)
         self.current_dataset.x_bins = x_vals
         self.current_dataset.y_bins = y_vals
Index: src/sas/sascalc/dataloader/readers/red2d_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/red2d_reader.py	(revision c8321cfca1fe64cbabb0c8b781cf5aecc57c211b)
+++ src/sas/sascalc/dataloader/readers/red2d_reader.py	(revision 058f6c331803fd9d3a8627da92364a3b0c0c29b5)
@@ -317,7 +317,5 @@
 
         # Units of axes
-        self.current_dataset.xaxis(r"\rm{Q_{x}}", 'A^{-1}')
-        self.current_dataset.yaxis(r"\rm{Q_{y}}", 'A^{-1}')
-        self.current_dataset.zaxis(r"\rm{Intensity}", "cm^{-1}")
+        self.current_dataset = self.set_default_2d_units(self.current_dataset)
 
         # Store loading process information
Index: src/sas/sascalc/file_converter/bsl_loader.py
===================================================================
--- src/sas/sascalc/file_converter/bsl_loader.py	(revision f00691d4eb5ea44608db5bc5dba2511a65165909)
+++ src/sas/sascalc/file_converter/bsl_loader.py	(revision 952ea1fd0d931d2eae09831204ea057abfe5450f)
@@ -1,3 +1,3 @@
-from sas.sascalc.file_converter.core.bsl_loader import CLoader
+from sas.sascalc.file_converter._bsl_loader import CLoader
 from sas.sascalc.dataloader.data_info import Data2D
 from copy import deepcopy
@@ -67,5 +67,5 @@
                     'swap_bytes': int(metadata[3])
                 }
-            except:
+            except Exception:
                 is_valid = False
                 err_msg = "Invalid metadata in header file for {}"
Index: c/sas/sascalc/file_converter/c_ext/__init__.py
===================================================================
--- src/sas/sascalc/file_converter/c_ext/__init__.py	(revision a26f67f1457e7e39b79d4c3800c03bcaa208dff7)
+++ 	(revision )
@@ -1,3 +1,0 @@
-"""
-    Data loader for the Diamond BSL beamline.
-"""
Index: src/sas/sascalc/file_converter/c_ext/bsl_loader.c
===================================================================
--- src/sas/sascalc/file_converter/c_ext/bsl_loader.c	(revision d5aeaa3a97e3a88347ad8b3aad7acfd95e97de89)
+++ src/sas/sascalc/file_converter/c_ext/bsl_loader.c	(revision 952ea1fd0d931d2eae09831204ea057abfe5450f)
@@ -1,8 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+//#define Py_LIMITED_API 0x03020000
 #include <Python.h>
+#include <structmember.h>
 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
 #include <numpy/arrayobject.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "structmember.h"
+
 #include "bsl_loader.h"
 
@@ -292,7 +295,7 @@
 
 #define MODULE_DOC "C module for loading bsl."
-#define MODULE_NAME "bsl_loader"
-#define MODULE_INIT2 initbsl_loader
-#define MODULE_INIT3 PyInit_bsl_loader
+#define MODULE_NAME "_bsl_loader"
+#define MODULE_INIT2 init_bsl_loader
+#define MODULE_INIT3 PyInit__bsl_loader
 #define MODULE_METHODS module_methods
 
Index: src/sas/sascalc/file_converter/nxcansas_writer.py
===================================================================
--- src/sas/sascalc/file_converter/nxcansas_writer.py	(revision 574adc767a9e86744546f8edd6a23dc4f81914ad)
+++ src/sas/sascalc/file_converter/nxcansas_writer.py	(revision 109afbd5a53a6f4e77bd27e189ff20434158516c)
@@ -8,8 +8,8 @@
 import os
 
-from sas.sascalc.dataloader.readers.cansas_reader_HDF5 import Reader as Cansas2Reader
+from sas.sascalc.dataloader.readers.cansas_reader_HDF5 import Reader
 from sas.sascalc.dataloader.data_info import Data1D, Data2D
 
-class NXcanSASWriter(Cansas2Reader):
+class NXcanSASWriter(Reader):
     """
     A class for writing in NXcanSAS data files. Any number of data sets may be
@@ -87,7 +87,8 @@
                     entry[names[2]].attrs['units'] = units
 
-        valid_data = all([issubclass(d.__class__, (Data1D, Data2D)) for d in dataset])
+        valid_data = all([isinstance(d, (Data1D, Data2D)) for d in dataset])
         if not valid_data:
-            raise ValueError("All entries of dataset must be Data1D or Data2D objects")
+            raise ValueError("All entries of dataset must be Data1D or Data2D"
+                             "objects")
 
         # Get run name and number from first Data object
@@ -109,8 +110,6 @@
         sasentry.attrs['version'] = '1.0'
 
-        i = 1
-
-        for data_obj in dataset:
-            data_entry = sasentry.create_group("sasdata{0:0=2d}".format(i))
+        for i, data_obj in enumerate(dataset):
+            data_entry = sasentry.create_group("sasdata{0:0=2d}".format(i+1))
             data_entry.attrs['canSAS_class'] = 'SASdata'
             if isinstance(data_obj, Data1D):
@@ -118,5 +117,4 @@
             elif isinstance(data_obj, Data2D):
                 self._write_2d_data(data_obj, data_entry)
-            i += 1
 
         data_info = dataset[0]
@@ -148,5 +146,5 @@
                 sample_entry.create_dataset('details', data=details)
 
-        # Instrumment metadata
+        # Instrument metadata
         instrument_entry = sasentry.create_group('sasinstrument')
         instrument_entry.attrs['canSAS_class'] = 'SASinstrument'
@@ -176,32 +174,31 @@
             units=data_info.source.beam_size_unit, write_fn=_write_h5_float)
 
-
         # Collimation metadata
         if len(data_info.collimation) > 0:
-            i = 1
-            for coll_info in data_info.collimation:
+            for i, coll_info in enumerate(data_info.collimation):
                 collimation_entry = instrument_entry.create_group(
-                    'sascollimation{0:0=2d}'.format(i))
+                    'sascollimation{0:0=2d}'.format(i + 1))
                 collimation_entry.attrs['canSAS_class'] = 'SAScollimation'
                 if coll_info.length is not None:
                     _write_h5_float(collimation_entry, coll_info.length, 'SDD')
-                    collimation_entry['SDD'].attrs['units'] = coll_info.length_unit
+                    collimation_entry['SDD'].attrs['units'] =\
+                        coll_info.length_unit
                 if coll_info.name is not None:
                     collimation_entry['name'] = _h5_string(coll_info.name)
         else:
-            # Create a blank one - at least 1 set of collimation metadata
-            # required by format
-            collimation_entry = instrument_entry.create_group('sascollimation01')
+            # Create a blank one - at least 1 collimation required by format
+            instrument_entry.create_group('sascollimation01')
 
         # Detector metadata
         if len(data_info.detector) > 0:
             i = 1
-            for det_info in data_info.detector:
+            for i, det_info in enumerate(data_info.detector):
                 detector_entry = instrument_entry.create_group(
-                    'sasdetector{0:0=2d}'.format(i))
+                    'sasdetector{0:0=2d}'.format(i + 1))
                 detector_entry.attrs['canSAS_class'] = 'SASdetector'
                 if det_info.distance is not None:
                     _write_h5_float(detector_entry, det_info.distance, 'SDD')
-                    detector_entry['SDD'].attrs['units'] = det_info.distance_unit
+                    detector_entry['SDD'].attrs['units'] =\
+                        det_info.distance_unit
                 if det_info.name is not None:
                     detector_entry['name'] = _h5_string(det_info.name)
@@ -209,6 +206,8 @@
                     detector_entry['name'] = _h5_string('')
                 if det_info.slit_length is not None:
-                    _write_h5_float(detector_entry, det_info.slit_length, 'slit_length')
-                    detector_entry['slit_length'].attrs['units'] = det_info.slit_length_unit
+                    _write_h5_float(detector_entry, det_info.slit_length,
+                                    'slit_length')
+                    detector_entry['slit_length'].attrs['units'] =\
+                        det_info.slit_length_unit
                 _write_h5_vector(detector_entry, det_info.offset)
                 # NXcanSAS doesn't save information about pitch, only roll
@@ -224,6 +223,4 @@
                     names=['x_pixel_size', 'y_pixel_size'],
                     write_fn=_write_h5_float, units=det_info.pixel_size_unit)
-
-                i += 1
         else:
             # Create a blank one - at least 1 detector required by format
@@ -231,4 +228,48 @@
             detector_entry.attrs['canSAS_class'] = 'SASdetector'
             detector_entry.attrs['name'] = ''
+
+        # Process meta data
+        for i, process in enumerate(data_info.process):
+            process_entry = sasentry.create_group('sasprocess{0:0=2d}'.format(
+                i + 1))
+            process_entry.attrs['canSAS_class'] = 'SASprocess'
+            if process.name:
+                name = _h5_string(process.name)
+                process_entry.create_dataset('name', data=name)
+            if process.date:
+                date = _h5_string(process.date)
+                process_entry.create_dataset('date', data=date)
+            if process.description:
+                desc = _h5_string(process.description)
+                process_entry.create_dataset('description', data=desc)
+            for j, term in enumerate(process.term):
+                # Don't save empty terms
+                if term:
+                    h5_term = _h5_string(term)
+                    process_entry.create_dataset('term{0:0=2d}'.format(
+                        j + 1), data=h5_term)
+            for j, note in enumerate(process.notes):
+                # Don't save empty notes
+                if note:
+                    h5_note = _h5_string(note)
+                    process_entry.create_dataset('note{0:0=2d}'.format(
+                        j + 1), data=h5_note)
+
+        # Transmission Spectrum
+        for i, trans in enumerate(data_info.trans_spectrum):
+            trans_entry = sasentry.create_group(
+                'sastransmission_spectrum{0:0=2d}'.format(i + 1))
+            trans_entry.attrs['canSAS_class'] = 'SAStransmission_spectrum'
+            trans_entry.attrs['signal'] = 'T'
+            trans_entry.attrs['T_axes'] = 'T'
+            trans_entry.attrs['name'] = trans.name
+            if trans.timestamp is not '':
+                trans_entry.attrs['timestamp'] = trans.timestamp
+            transmission = trans_entry.create_dataset('T',
+                                                      data=trans.transmission)
+            transmission.attrs['unertainties'] = 'Tdev'
+            trans_entry.create_dataset('Tdev',
+                                       data=trans.transmission_deviation)
+            trans_entry.create_dataset('lambda', data=trans.wavelength)
 
         note_entry = sasentry.create_group('sasnote'.format(i))
@@ -254,14 +295,23 @@
         data_entry.attrs['signal'] = 'I'
         data_entry.attrs['I_axes'] = 'Q'
-        data_entry.attrs['I_uncertainties'] = 'Idev'
-        data_entry.attrs['Q_indicies'] = 0
-
-        dI = data_obj.dy
-        if dI is None:
-            dI = np.zeros((data_obj.y.shape))
-
-        data_entry.create_dataset('Q', data=data_obj.x)
-        data_entry.create_dataset('I', data=data_obj.y)
-        data_entry.create_dataset('Idev', data=dI)
+        data_entry.attrs['Q_indices'] = [0]
+        q_entry = data_entry.create_dataset('Q', data=data_obj.x)
+        q_entry.attrs['units'] = data_obj.x_unit
+        i_entry = data_entry.create_dataset('I', data=data_obj.y)
+        i_entry.attrs['units'] = data_obj.y_unit
+        if data_obj.dy is not None:
+            i_entry.attrs['uncertainties'] = 'Idev'
+            i_dev_entry = data_entry.create_dataset('Idev', data=data_obj.dy)
+            i_dev_entry.attrs['units'] = data_obj.y_unit
+        if data_obj.dx is not None:
+            q_entry.attrs['resolutions'] = 'dQ'
+            dq_entry = data_entry.create_dataset('dQ', data=data_obj.dx)
+            dq_entry.attrs['units'] = data_obj.x_unit
+        elif data_obj.dxl is not None:
+            q_entry.attrs['resolutions'] = ['dQl','dQw']
+            dql_entry = data_entry.create_dataset('dQl', data=data_obj.dxl)
+            dql_entry.attrs['units'] = data_obj.x_unit
+            dqw_entry = data_entry.create_dataset('dQw', data=data_obj.dxw)
+            dqw_entry.attrs['units'] = data_obj.x_unit
 
     def _write_2d_data(self, data, data_entry):
@@ -273,11 +323,10 @@
         """
         data_entry.attrs['signal'] = 'I'
-        data_entry.attrs['I_axes'] = 'Q,Q'
-        data_entry.attrs['I_uncertainties'] = 'Idev'
-        data_entry.attrs['Q_indicies'] = [0,1]
+        data_entry.attrs['I_axes'] = 'Qx,Qy'
+        data_entry.attrs['Q_indices'] = [0,1]
 
         (n_rows, n_cols) = (len(data.y_bins), len(data.x_bins))
 
-        if n_rows == 0 and n_cols == 0:
+        if (n_rows == 0 and n_cols == 0) or (n_cols*n_rows != data.data.size):
             # Calculate rows and columns, assuming detector is square
             # Same logic as used in PlotPanel.py _get_bins
@@ -288,17 +337,32 @@
                 raise ValueError("Unable to calculate dimensions of 2D data")
 
-        I = np.reshape(data.data, (n_rows, n_cols))
-        dI = np.zeros((n_rows, n_cols))
-        if not all(data.err_data == [None]):
-            dI = np.reshape(data.err_data, (n_rows, n_cols))
-        qx =  np.reshape(data.qx_data, (n_rows, n_cols))
+        intensity = np.reshape(data.data, (n_rows, n_cols))
+        qx = np.reshape(data.qx_data, (n_rows, n_cols))
         qy = np.reshape(data.qy_data, (n_rows, n_cols))
 
-        I_entry = data_entry.create_dataset('I', data=I)
-        I_entry.attrs['units'] = data.I_unit
-        Qx_entry = data_entry.create_dataset('Qx', data=qx)
-        Qx_entry.attrs['units'] = data.Q_unit
-        Qy_entry = data_entry.create_dataset('Qy', data=qy)
-        Qy_entry.attrs['units'] = data.Q_unit
-        Idev_entry = data_entry.create_dataset('Idev', data=dI)
-        Idev_entry.attrs['units'] = data.I_unit
+        i_entry = data_entry.create_dataset('I', data=intensity)
+        i_entry.attrs['units'] = data.I_unit
+        qx_entry = data_entry.create_dataset('Qx', data=qx)
+        qx_entry.attrs['units'] = data.Q_unit
+        qy_entry = data_entry.create_dataset('Qy', data=qy)
+        qy_entry.attrs['units'] = data.Q_unit
+        if (data.err_data is not None
+                and not all(v is None for v in data.err_data)):
+            d_i = np.reshape(data.err_data, (n_rows, n_cols))
+            i_entry.attrs['uncertainties'] = 'Idev'
+            i_dev_entry = data_entry.create_dataset('Idev', data=d_i)
+            i_dev_entry.attrs['units'] = data.I_unit
+        if (data.dqx_data is not None
+                and not all(v is None for v in data.dqx_data)):
+            qx_entry.attrs['resolutions'] = 'dQx'
+            dqx_entry = data_entry.create_dataset('dQx', data=data.dqx_data)
+            dqx_entry.attrs['units'] = data.Q_unit
+        if (data.dqy_data is not None
+                and not all(v is None for v in data.dqy_data)):
+            qy_entry.attrs['resolutions'] = 'dQy'
+            dqy_entry = data_entry.create_dataset('dQy', data=data.dqy_data)
+            dqy_entry.attrs['units'] = data.Q_unit
+        if data.mask is not None and not all(v is None for v in data.mask):
+            data_entry.attrs['mask'] = "mask"
+            mask = np.invert(np.asarray(data.mask, dtype=bool))
+            data_entry.create_dataset('mask', data=mask)
Index: src/sas/sascalc/pr/c_extensions/Cinvertor.c
===================================================================
--- src/sas/sascalc/pr/c_extensions/Cinvertor.c	(revision a52f32f0dbf9ba217a21de95ba57c8862a042cad)
+++ src/sas/sascalc/pr/c_extensions/Cinvertor.c	(revision 7ba64705ddaa18ab8bce14ae2ac2e767b23eb313)
@@ -5,6 +5,4 @@
  *
  */
-#include <Python.h>
-#include "structmember.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -12,24 +10,33 @@
 #include <time.h>
 
+//#define Py_LIMITED_API 0x03050000
+#include <Python.h>
+#include <structmember.h>
+
+// Vector binding glue
+#if (PY_VERSION_HEX > 0x03000000) && !defined(Py_LIMITED_API)
+  // Assuming that a view into a writable vector points to a
+  // non-changing pointer for the duration of the C call, capture
+  // the view pointer and immediately free the view.
+  #define VECTOR(VEC_obj, VEC_buf, VEC_len) do { \
+    Py_buffer VEC_view; \
+    int VEC_err = PyObject_GetBuffer(VEC_obj, &VEC_view, PyBUF_WRITABLE|PyBUF_FORMAT); \
+    if (VEC_err < 0 || sizeof(*VEC_buf) != VEC_view.itemsize) return NULL; \
+    VEC_buf = (typeof(VEC_buf))VEC_view.buf; \
+    VEC_len = VEC_view.len/sizeof(*VEC_buf); \
+    PyBuffer_Release(&VEC_view); \
+  } while (0)
+#else
+  #define VECTOR(VEC_obj, VEC_buf, VEC_len) do { \
+    int VEC_err = PyObject_AsWriteBuffer(VEC_obj, (void **)(&VEC_buf), &VEC_len); \
+    if (VEC_err < 0) return NULL; \
+    VEC_len /= sizeof(*VEC_buf); \
+  } while (0)
+#endif
+
 #include "invertor.h"
-
 
 /// Error object for raised exceptions
 PyObject * CinvertorError;
-
-#define INVECTOR(obj,buf,len)										\
-    do { \
-        int err = PyObject_AsReadBuffer(obj, (const void **)(&buf), &len); \
-        if (err < 0) return NULL; \
-        len /= sizeof(*buf); \
-    } while (0)
-
-#define OUTVECTOR(obj,buf,len) \
-    do { \
-        int err = PyObject_AsWriteBuffer(obj, (void **)(&buf), &len); \
-        if (err < 0) return NULL; \
-        len /= sizeof(*buf); \
-    } while (0)
-
 
 // Class definition
@@ -99,5 +106,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,data,ndata);
+	VECTOR(data_obj,data,ndata);
 
 	free(self->params.x);
@@ -131,5 +138,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj, data, ndata);
+	VECTOR(data_obj, data, ndata);
 
 	// Check that the input array is large enough
@@ -164,5 +171,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,data,ndata);
+	VECTOR(data_obj,data,ndata);
 
 	free(self->params.y);
@@ -196,5 +203,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj, data, ndata);
+	VECTOR(data_obj, data, ndata);
 
 	// Check that the input array is large enough
@@ -229,5 +236,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,data,ndata);
+	VECTOR(data_obj,data,ndata);
 
 	free(self->params.err);
@@ -261,5 +268,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj, data, ndata);
+	VECTOR(data_obj, data, ndata);
 
 	// Check that the input array is large enough
@@ -517,5 +524,5 @@
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
 
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
     // PyList of residuals
@@ -568,5 +575,5 @@
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
 
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	// Should create this list only once and refill it
@@ -609,5 +616,5 @@
 
 	if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	iq_value = iq(pars, self->params.d_max, (int)npars, q);
@@ -634,5 +641,5 @@
 
 	if (!PyArg_ParseTuple(args, "Od", &data_obj, &q)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	iq_value = iq_smeared(pars, self->params.d_max, (int)npars,
@@ -659,5 +666,5 @@
 
 	if (!PyArg_ParseTuple(args, "Od", &data_obj, &r)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	pr_value = pr(pars, self->params.d_max, (int)npars, r);
@@ -686,5 +693,5 @@
 
 	if (!PyArg_ParseTuple(args, "OOd", &data_obj, &err_obj, &r)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	if (err_obj == Py_None) {
@@ -692,5 +699,5 @@
 		pr_err_value = 0.0;
 	} else {
-		OUTVECTOR(err_obj,pars_err,npars2);
+		VECTOR(err_obj,pars_err,npars2);
 		pr_err(pars, pars_err, self->params.d_max, (int)npars, r, &pr_value, &pr_err_value);
 	}
@@ -726,5 +733,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	oscill = reg_term(pars, self->params.d_max, (int)npars, 100);
@@ -747,5 +754,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	count = npeaks(pars, self->params.d_max, (int)npars, 100);
@@ -768,5 +775,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	fraction = positive_integral(pars, self->params.d_max, (int)npars, 100);
@@ -792,6 +799,6 @@
 
 	if (!PyArg_ParseTuple(args, "OO", &data_obj, &err_obj)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
-	OUTVECTOR(err_obj,pars_err,npars2);
+	VECTOR(data_obj,pars,npars);
+	VECTOR(err_obj,pars_err,npars2);
 
 	fraction = positive_errors(pars, pars_err, self->params.d_max, (int)npars, 51);
@@ -813,5 +820,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	value = rg(pars, self->params.d_max, (int)npars, 101);
@@ -833,5 +840,5 @@
 
 	if (!PyArg_ParseTuple(args, "O", &data_obj)) return NULL;
-	OUTVECTOR(data_obj,pars,npars);
+	VECTOR(data_obj,pars,npars);
 
 	value = 4.0*acos(-1.0)*int_pr(pars, self->params.d_max, (int)npars, 101);
@@ -874,6 +881,6 @@
 
 	if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &b_obj)) return NULL;
-	OUTVECTOR(a_obj,a,n_a);
-	OUTVECTOR(b_obj,b,n_b);
+	VECTOR(a_obj,a,n_a);
+	VECTOR(b_obj,b,n_b);
 
 	assert(n_b>=nfunc);
@@ -947,6 +954,6 @@
 
 	if (!PyArg_ParseTuple(args, "iiOO", &nfunc, &nr, &a_obj, &cov_obj)) return NULL;
-	OUTVECTOR(a_obj,a,n_a);
-	OUTVECTOR(cov_obj,inv_cov,n_cov);
+	VECTOR(a_obj,a,n_a);
+	VECTOR(cov_obj,inv_cov,n_cov);
 
 	assert(n_cov>=nfunc*nfunc);
@@ -981,5 +988,5 @@
 
 	if (!PyArg_ParseTuple(args, "iiO", &nfunc, &nr, &a_obj)) return NULL;
-	OUTVECTOR(a_obj,a,n_a);
+	VECTOR(a_obj,a,n_a);
 
 	assert(n_a>=nfunc*(nr+self->params.npoints));
@@ -1121,7 +1128,7 @@
 
 #define MODULE_DOC "C extension module for inversion to P(r)."
-#define MODULE_NAME "pr_inversion"
-#define MODULE_INIT2 initpr_inversion
-#define MODULE_INIT3 PyInit_pr_inversion
+#define MODULE_NAME "_pr_inversion"
+#define MODULE_INIT2 init_pr_inversion
+#define MODULE_INIT3 PyInit__pr_inversion
 #define MODULE_METHODS module_methods
 
Index: c/sas/sascalc/pr/c_extensions/__init__.py
===================================================================
--- src/sas/sascalc/pr/c_extensions/__init__.py	(revision 959eb0181ad06828a748f04512f953aad5b31659)
+++ 	(revision )
@@ -1,3 +1,0 @@
-"""
-    C extensions to provide the P(r) inversion computations.
-"""
Index: src/sas/sascalc/pr/fit/BumpsFitting.py
===================================================================
--- src/sas/sascalc/pr/fit/BumpsFitting.py	(revision 9a5097cd1c76689d1f997b85ba43d12a95d8f243)
+++ src/sas/sascalc/pr/fit/BumpsFitting.py	(revision 3e6829d03839dc7a60382a887dc7f27da1c50c8f)
@@ -2,4 +2,6 @@
 BumpsFitting module runs the bumps optimizer.
 """
+from __future__ import division
+
 import os
 from datetime import timedelta, datetime
@@ -34,5 +36,5 @@
 class Progress(object):
     def __init__(self, history, max_step, pars, dof):
-        remaining_time = int(history.time[0]*(float(max_step)/history.step[0]-1))
+        remaining_time = int(history.time[0]*(max_step/history.step[0]-1))
         # Depending on the time remaining, either display the expected
         # time of completion, or the amount of time remaining.  Use precision
Index: src/sas/sascalc/pr/fit/Loader.py
===================================================================
--- src/sas/sascalc/pr/fit/Loader.py	(revision 574adc767a9e86744546f8edd6a23dc4f81914ad)
+++ src/sas/sascalc/pr/fit/Loader.py	(revision 57e48ca3fba05a5ace7a3f2a5b6ff8f1a9f4206c)
@@ -1,7 +1,8 @@
+"""
+class Loader  to load any kind of file
+"""
+
 from __future__ import print_function
 
-# class Loader  to load any king of file
-#import wx
-#import string
 import numpy as np
 
Index: src/sas/sascalc/pr/invertor.py
===================================================================
--- src/sas/sascalc/pr/invertor.py	(revision dbfd307df25dbe7befe02b50ded9d06ccf6499e3)
+++ src/sas/sascalc/pr/invertor.py	(revision dbfd307df25dbe7befe02b50ded9d06ccf6499e3)
@@ -6,4 +6,5 @@
 FIXME: The way the Invertor interacts with its C component should be cleaned up
 """
+from __future__ import division
 
 import numpy as np
@@ -17,5 +18,5 @@
 from numpy.linalg import lstsq
 from scipy import optimize
-from sas.sascalc.pr.core.pr_inversion import Cinvertor
+from sas.sascalc.pr._pr_inversion import Cinvertor
 
 logger = logging.getLogger(__name__)
@@ -71,5 +72,5 @@
         A[j][i] = (Fourier transformed base function for point j)
 
-    We them choose a number of r-points, n_r, to evaluate the second
+    We then choose a number of r-points, n_r, to evaluate the second
     derivative of P(r) at. This is used as our regularization term.
     For a vector r of length n_r, the following n_r rows are set to ::
@@ -144,5 +145,5 @@
         x, y, err, d_max, q_min, q_max and alpha
         """
-        if   name == 'x':
+        if name == 'x':
             if 0.0 in value:
                 msg = "Invertor: one of your q-values is zero. "
@@ -268,5 +269,5 @@
             A[i][j] = (Fourier transformed base function for point j)
 
-        We them choose a number of r-points, n_r, to evaluate the second
+        We then choose a number of r-points, n_r, to evaluate the second
         derivative of P(r) at. This is used as our regularization term.
         For a vector r of length n_r, the following n_r rows are set to ::
@@ -416,5 +417,5 @@
             A[i][j] = (Fourier transformed base function for point j)
 
-        We them choose a number of r-points, n_r, to evaluate the second
+        We then choose a number of r-points, n_r, to evaluate the second
         derivative of P(r) at. This is used as our regularization term.
         For a vector r of length n_r, the following n_r rows are set to ::
@@ -498,9 +499,9 @@
         try:
             cov = np.linalg.pinv(inv_cov)
-            err = math.fabs(chi2 / float(npts - nfunc)) * cov
-        except:
+            err = math.fabs(chi2 / (npts - nfunc)) * cov
+        except Exception as exc:
             # We were not able to estimate the errors
             # Return an empty error matrix
-            logger.error(sys.exc_value)
+            logger.error(exc)
 
         # Keep a copy of the last output
@@ -539,13 +540,13 @@
 
         """
-        from num_term import NTermEstimator
+        from .num_term import NTermEstimator
         estimator = NTermEstimator(self.clone())
         try:
             return estimator.num_terms(isquit_func)
-        except:
+        except Exception as exc:
             # If we fail, estimate alpha and return the default
             # number of terms
             best_alpha, _, _ = self.estimate_alpha(self.nfunc)
-            logger.warning("Invertor.estimate_numterms: %s" % sys.exc_value)
+            logger.warning("Invertor.estimate_numterms: %s" % exc)
             return self.nfunc, best_alpha, "Could not estimate number of terms"
 
@@ -633,6 +634,6 @@
                 return best_alpha, message, elapsed
 
-        except:
-            message = "Invertor.estimate_alpha: %s" % sys.exc_value
+        except Exception as exc:
+            message = "Invertor.estimate_alpha: %s" % exc
             return 0, message, elapsed
 
@@ -750,6 +751,6 @@
                         self.cov[i][i] = float(toks2[1])
 
-            except:
-                msg = "Invertor.from_file: corrupted file\n%s" % sys.exc_value
+            except Exception as exc:
+                msg = "Invertor.from_file: corrupted file\n%s" % exc
                 raise RuntimeError(msg)
         else:
Index: src/sas/sascalc/pr/num_term.py
===================================================================
--- src/sas/sascalc/pr/num_term.py	(revision e090ba909aeb28ce2f0504a77e5a800070907873)
+++ src/sas/sascalc/pr/num_term.py	(revision 3e6829d03839dc7a60382a887dc7f27da1c50c8f)
@@ -1,3 +1,3 @@
-from __future__ import print_function
+from __future__ import print_function, division
 
 import math
@@ -51,5 +51,5 @@
         osc = self.sort_osc()
         dv = len(osc)
-        med = float(dv) / 2.0
+        med = 0.5*dv
         odd = self.is_odd(dv)
         medi = 0
@@ -140,5 +140,5 @@
             nts = self.compare_err()
             div = len(nts)
-            tem = float(div) / 2.0
+            tem = 0.5*div
             if self.is_odd(div):
                 nt = nts[int(tem)]
Index: src/sas/sasgui/guiframe/gui_manager.py
===================================================================
--- src/sas/sasgui/guiframe/gui_manager.py	(revision 8ac05a59a0078f40fc8af4febae16624b9d5c818)
+++ src/sas/sasgui/guiframe/gui_manager.py	(revision 9220e89c31ca5156d9c3a40634b4257084d139a2)
@@ -46,4 +46,5 @@
 from sas.sasgui.guiframe.CategoryManager import CategoryManager
 from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.file_converter.nxcansas_writer import NXcanSASWriter
 from sas.sasgui.guiframe.proxy import Connection
 
@@ -62,47 +63,35 @@
 SPLASH_SCREEN_HEIGHT = config.SPLASH_SCREEN_HEIGHT
 SS_MAX_DISPLAY_TIME = config.SS_MAX_DISPLAY_TIME
-if not WELCOME_PANEL_ON:
-    WELCOME_PANEL_SHOW = False
+
+def custom_value(name, default=None):
+    """
+    Fetch a config value from custom_config.  Fallback to config, and then
+    to default if it doesn't exist in config.
+    """
+    default = getattr(config, name, default)
+    return getattr(custom_config, name, default)
+
+# Custom config values in the order they appear.
+DATAPANEL_WIDTH = custom_value('DATAPANEL_WIDTH', -1)
+CLEANUP_PLOT = custom_value('CLEANUP_PLOT', False)
+FIXED_PANEL = custom_value('FIXED_PANEL', True)
+PLOPANEL_WIDTH = custom_value('PLOPANEL_WIDTH', -1)
+DATALOADER_SHOW = custom_value('DATALOADER_SHOW', True)
+GUIFRAME_HEIGHT = custom_value('GUIFRAME_HEIGHT', -1)
+GUIFRAME_WIDTH = custom_value('GUIFRAME_WIDTH', -1)
+CONTROL_WIDTH = custom_value('CONTROL_WIDTH', -1)
+CONTROL_HEIGHT = custom_value('CONTROL_HEIGHT', -1)
+open_folder = custom_value('DEFAULT_OPEN_FOLDER', None)
+if open_folder is not None and os.path.isdir(open_folder):
+    DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
 else:
-    WELCOME_PANEL_SHOW = True
-try:
-    DATALOADER_SHOW = custom_config.DATALOADER_SHOW
-    TOOLBAR_SHOW = custom_config.TOOLBAR_SHOW
-    FIXED_PANEL = custom_config.FIXED_PANEL
-    if WELCOME_PANEL_ON:
-        WELCOME_PANEL_SHOW = custom_config.WELCOME_PANEL_SHOW
-    PLOPANEL_WIDTH = custom_config.PLOPANEL_WIDTH
-    DATAPANEL_WIDTH = custom_config.DATAPANEL_WIDTH
-    GUIFRAME_WIDTH = custom_config.GUIFRAME_WIDTH
-    GUIFRAME_HEIGHT = custom_config.GUIFRAME_HEIGHT
-    CONTROL_WIDTH = custom_config.CONTROL_WIDTH
-    CONTROL_HEIGHT = custom_config.CONTROL_HEIGHT
-    DEFAULT_PERSPECTIVE = custom_config.DEFAULT_PERSPECTIVE
-    CLEANUP_PLOT = custom_config.CLEANUP_PLOT
-    # custom open_path
-    open_folder = custom_config.DEFAULT_OPEN_FOLDER
-    if open_folder is not None and os.path.isdir(open_folder):
-        DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
-    else:
-        DEFAULT_OPEN_FOLDER = get_app_dir()
-    SAS_OPENCL = custom_config.SAS_OPENCL
-except:
-    DATALOADER_SHOW = True
-    TOOLBAR_SHOW = True
-    FIXED_PANEL = True
-    WELCOME_PANEL_SHOW = False
-    PLOPANEL_WIDTH = config.PLOPANEL_WIDTH
-    DATAPANEL_WIDTH = config.DATAPANEL_WIDTH
-    GUIFRAME_WIDTH = config.GUIFRAME_WIDTH
-    GUIFRAME_HEIGHT = config.GUIFRAME_HEIGHT
-    CONTROL_WIDTH = -1
-    CONTROL_HEIGHT = -1
-    DEFAULT_PERSPECTIVE = None
-    CLEANUP_PLOT = False
     DEFAULT_OPEN_FOLDER = get_app_dir()
-    DEFAULT_OPEN_FOLDER = PATH_APP
-    SAS_OPENCL = None
+WELCOME_PANEL_SHOW = (custom_value('WELCOME_PANEL_SHOW', False)
+                      if WELCOME_PANEL_ON else False)
+TOOLBAR_SHOW = custom_value('TOOLBAR_SHOW', True)
+DEFAULT_PERSPECTIVE = custom_value('DEFAULT_PERSPECTIVE', 'Fitting')
+SAS_OPENCL = custom_value('SAS_OPENCL', 'None')
+
 DEFAULT_STYLE = config.DEFAULT_STYLE
-
 PLUGIN_STATE_EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS
 OPEN_SAVE_MENU = config.OPEN_SAVE_PROJECT_MENU
@@ -2170,5 +2159,5 @@
         # original 2.x tutorial.
         # Code below, implemented from 4.2.0, redirects
-        # action to the Tutorials page of the help 
+        # action to the Tutorials page of the help
         # documentation to give access to all available
         # tutorials
@@ -2419,6 +2408,7 @@
         default_name = fname
         wildcard = "Text files (*.txt)|*.txt|"\
-                    "CanSAS 1D files(*.xml)|*.xml"
-        path = None
+                    "CanSAS 1D files (*.xml)|*.xml|"\
+                     "NXcanSAS files (*.h5)|*.h5|"
+        options = [".txt", ".xml",".h5"]
         dlg = wx.FileDialog(self, "Choose a file",
                             self._default_save_location,
@@ -2430,25 +2420,23 @@
             # This is MAC Fix
             ext_num = dlg.GetFilterIndex()
-            if ext_num == 0:
-                ext_format = '.txt'
-            else:
-                ext_format = '.xml'
+
+            ext_format = options[ext_num]
             path = os.path.splitext(path)[0] + ext_format
             mypath = os.path.basename(path)
-
-            # Instantiate a loader
-            loader = Loader()
-            ext_format = ".txt"
-            if os.path.splitext(mypath)[1].lower() == ext_format:
+            fName = os.path.splitext(path)[0] + ext_format
+
+            if os.path.splitext(mypath)[1].lower() == options[0]:
                 # Make sure the ext included in the file name
                 # especially on MAC
-                fName = os.path.splitext(path)[0] + ext_format
                 self._onsaveTXT(data, fName)
-            ext_format = ".xml"
-            if os.path.splitext(mypath)[1].lower() == ext_format:
+            elif os.path.splitext(mypath)[1].lower() == options[1]:
                 # Make sure the ext included in the file name
                 # especially on MAC
-                fName = os.path.splitext(path)[0] + ext_format
+                # Instantiate a loader
+                loader = Loader()
                 loader.save(fName, data, ext_format)
+            elif os.path.splitext(mypath)[1].lower() == options[2]:
+                nxcansaswriter = NXcanSASWriter()
+                nxcansaswriter.write([data], fName)
             try:
                 self._default_save_location = os.path.dirname(path)
@@ -2477,9 +2465,9 @@
             if has_errors:
                 if data.dx is not None and data.dx != []:
-                    out.write("<X>   <Y>   <dY>   <dX>\n")
+                    out.write("<X>\t<Y>\t<dY>\t<dX>\n")
                 else:
-                    out.write("<X>   <Y>   <dY>\n")
+                    out.write("<X>\t<Y>\t<dY>\n")
             else:
-                out.write("<X>   <Y>\n")
+                out.write("<X>\t<Y>\n")
 
             for i in range(len(data.x)):
@@ -2525,5 +2513,7 @@
             text += 'dY_min = %s:  dY_max = %s\n' % (min(data.dy), max(data.dy))
         text += '\nData Points:\n'
-        x_st = "X"
+        text += "<index> \t<X> \t<Y> \t<dY> "
+        text += "\t<dXl> \t<dXw>\n" if(data.dxl is not None and
+                                       data.dxw is not None) else "\t<dX>\n"
         for index in range(len(data.x)):
             if data.dy is not None and len(data.dy) > index:
@@ -2536,14 +2526,8 @@
                 dx_val = 0.0
             if data.dxl is not None and len(data.dxl) > index:
-                if index == 0:
-                    x_st = "Xl"
                 dx_val = data.dxl[index]
-            elif data.dxw is not None and len(data.dxw) > index:
-                if index == 0:
-                    x_st = "Xw"
-                dx_val = data.dxw[index]
-
-            if index == 0:
-                text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n" % x_st
+                if data.dxw is not None and len(data.dxw) > index:
+                    dx_val = "%s \t%s" % (data.dxl[index], data.dxw[index])
+
             text += "%s \t%s \t%s \t%s \t%s\n" % (index,
                                                   data.x[index],
@@ -2562,5 +2546,6 @@
         """
         default_name = fname
-        wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
+        wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT|"\
+                   "NXcanSAS files (*.h5)|*.h5|"
         dlg = wx.FileDialog(self, "Choose a file",
                             self._default_save_location,
@@ -2574,4 +2559,6 @@
             if ext_num == 0:
                 ext_format = '.dat'
+            elif ext_num == 1:
+                ext_format = '.h5'
             else:
                 ext_format = ''
@@ -2581,11 +2568,16 @@
             # Instantiate a loader
             loader = Loader()
-
-            ext_format = ".dat"
-            if os.path.splitext(mypath)[1].lower() == ext_format:
+            ext = os.path.splitext(mypath)[1].lower()
+            if ext == '.dat':
                 # Make sure the ext included in the file name
                 # especially on MAC
                 fileName = os.path.splitext(path)[0] + ext_format
                 loader.save(fileName, data, ext_format)
+            elif ext == '.h5':
+                # Make sure the ext included in the file name
+                # especially on MAC
+                fileName = os.path.splitext(path)[0] + ext_format
+                nxcansaswriter = NXcanSASWriter()
+                nxcansaswriter.write([data], fileName)
             try:
                 self._default_save_location = os.path.dirname(path)
Index: src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py	(revision 9c7e2b8361553f8e2f246d344c791c385f3b2254)
+++ src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py	(revision 9c7e2b8361553f8e2f246d344c791c385f3b2254)
@@ -205,5 +205,5 @@
             except NoKnownLoaderException as e:
                 exception_occurred = True
-                error_message = "Loading data failed!" + e.message
+                error_message = "Loading data failed!\n" + e.message
                 file_errors[basename] = [error_message]
             except Exception as e:
@@ -224,4 +224,5 @@
                 for message in error_array:
                     error_message += message + "\n"
+                error_message = error_message[:-1]
             self.load_complete(output=output,
                                message=error_message,
@@ -231,6 +232,4 @@
             self.load_complete(output=output, message="Loading data complete!",
                                info="info")
-        else:
-            self.load_complete(output=None, message=error_message, info="error")
 
     def load_update(self, message="", info="warning"):
Index: src/sas/sasgui/perspectives/calculator/model_editor.py
===================================================================
--- src/sas/sasgui/perspectives/calculator/model_editor.py	(revision 9bf40e7da42d4112c3098b54d9c3b12081500c84)
+++ src/sas/sasgui/perspectives/calculator/model_editor.py	(revision 1752f38b456a43e18ad070757b9e3f32528721ca)
@@ -965,9 +965,9 @@
         out_f.write('    """Absolute scattering"""\n')
         if "scipy." in func_str:
-            out_f.write('    import scipy')
+            out_f.write('    import scipy\n')
         if "numpy." in func_str:
-            out_f.write('    import numpy')
+            out_f.write('    import numpy\n')
         if "np." in func_str:
-            out_f.write('    import numpy as np')
+            out_f.write('    import numpy as np\n')
         for func_line in func_str.split('\n'):
             out_f.write('%s%s\n' % ('    ', func_line))
Index: src/sas/sasgui/perspectives/corfunc/corfunc_panel.py
===================================================================
--- src/sas/sasgui/perspectives/corfunc/corfunc_panel.py	(revision 5652efcc300905660181472befe611868f2ddeb8)
+++ src/sas/sasgui/perspectives/corfunc/corfunc_panel.py	(revision ef74a8b4c5fbc72695853e60c09c0379d8d1c2c6)
@@ -277,12 +277,12 @@
         self._transformed_data = transforms
         (transform1, transform3, idf) = transforms
-        plot_x = transform1.x[transform1.x <= 200]
-        plot_y = transform1.y[transform1.x <= 200]
+        plot_x = transform1.x[transform1.x <= 1000]
+        plot_y = transform1.y[transform1.x <= 1000]
         self._manager.show_data(Data1D(plot_x, plot_y), TRANSFORM_LABEL1)
-        # No need to shorten gamma3 as it's only calculated up to x=200
+        # No need to shorten gamma3 as it's only calculated up to x=1000
         self._manager.show_data(transform3, TRANSFORM_LABEL3)
 
-        plot_x = idf.x[idf.x <= 200]
-        plot_y = idf.y[idf.x <= 200]
+        plot_x = idf.x[idf.x <= 1000]
+        plot_y = idf.y[idf.x <= 1000]
         self._manager.show_data(Data1D(plot_x, plot_y), IDF_LABEL)
 
Index: src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst
===================================================================
--- src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst	(revision 490f79075e15c069f2a131d3ccd6a1e510e7dcfe)
+++ src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst	(revision 4d0666809b8cd216e5fe489e7e0b84ee88c2e188)
@@ -30,4 +30,9 @@
 of the profile provides measures of the layer thickness, and the area under 
 the profile is related to the amount of material that is adsorbed.
+
+.. note::
+    These transforms assume that the data has been measured on a pinhole-
+    collimated instrument or, if not, that the data has been Lorentz-
+    corrected beforehand.
 
 Both analyses are performed in 3 stages:
Index: src/sas/sasgui/perspectives/fitting/fitpage.py
===================================================================
--- src/sas/sasgui/perspectives/fitting/fitpage.py	(revision ba1c14560ba5f607c084c317e9b98cd8acfbfaa7)
+++ src/sas/sasgui/perspectives/fitting/fitpage.py	(revision ca4f40d38aa2c0abd8d7a1571cf953a85a676091)
@@ -13,8 +13,10 @@
 import time
 import traceback
+import logging
 
 from sasmodels.weights import MODELS as POLYDISPERSITY_MODELS
 
 from sas.sascalc.fit.qsmearing import smear_selection
+from sas.sascalc.dataloader.data_info import Data1D, Data2D
 
 from sas.sasgui.guiframe.events import StatusEvent, NewPlotEvent, \
@@ -28,4 +30,6 @@
     PageInfoEvent
 from .basepage import ModelTextCtrl
+
+logger = logging.getLogger(__name__)
 
 (Chi2UpdateEvent, EVT_CHI2_UPDATE) = wx.lib.newevent.NewEvent()
@@ -184,6 +188,5 @@
         :return: True or False
         """
-        if self.data.__class__.__name__ == "Data2D" or \
-                        self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             return True
         return False
@@ -199,6 +202,5 @@
 
         # Check if data is 2D
-        if self.data.__class__.__name__ == "Data2D" or \
-                        self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             is_2d_data = True
 
@@ -213,7 +215,9 @@
         smear_message_new_psmear = \
               "Please enter a fixed percentage to be applied to all Q values..."
-        smear_message_2d_x_title = "<dQp>[1/A]:"
-        smear_message_2d_y_title = "<dQs>[1/A]:"
-        smear_message_pinhole_percent_title = "dQ[%]:"
+        smear_message_2d_x_title = "<dQ/Q>_r[%]:"
+        smear_message_2d_y_title = "<dQ/Q>_phi[%]:"
+        smear_message_pinhole_percent_min_title = "[dQ/Q]min(%):"
+        smear_message_pinhole_percent_max_title = "[dQ/Q]max(%):"
+        smear_message_pinhole_percent_title = "dQ/Q(%):"
         smear_message_slit_height_title = "Slit height[1/A]:"
         smear_message_slit_width_title = "Slit width[1/A]:"
@@ -418,9 +422,15 @@
                             smear_message_2d_x_title, style=wx.ALIGN_LEFT)
         self.smear_description_2d_x.SetToolTipString(
-                                        "  dQp(parallel) in q_r direction.")
+                                        "  dQ_r q_r in polar coordinates.")
         self.smear_description_2d_y = wx.StaticText(self, wx.ID_ANY,
                             smear_message_2d_y_title, style=wx.ALIGN_LEFT)
         self.smear_description_2d_y.SetToolTipString(
-                                    " dQs(perpendicular) in q_phi direction.")
+                                    " dQ_phi q_phi in polar coordinates.")
+        self.smear_description_pin_percent_min = wx.StaticText(self, wx.ID_ANY,
+                                            smear_message_pinhole_percent_min_title,
+                                            style=wx.ALIGN_LEFT)
+        self.smear_description_pin_percent_max = wx.StaticText(self, wx.ID_ANY,
+                                            smear_message_pinhole_percent_max_title,
+                                            style=wx.ALIGN_LEFT)
         self.smear_description_pin_percent = wx.StaticText(self, wx.ID_ANY,
                                             smear_message_pinhole_percent_title,
@@ -449,7 +459,12 @@
         self.sizer_new_smear.Add((15, -1))
         self.sizer_new_smear.Add(self.smear_description_2d_x, 0, wx.CENTER, 10)
+        self.sizer_new_smear.Add(self.smear_description_pin_percent_min,
+                                 0, wx.CENTER, 10)
+        self.sizer_new_smear.Add(self.smear_description_pin_percent,
+                                 0, wx.CENTER, 10)
         self.sizer_new_smear.Add(self.smear_description_slit_height,
                                  0, wx.CENTER, 10)
 
+        self.sizer_new_smear.Add(self.smear_pinhole_percent, 0, wx.CENTER, 10)
         self.sizer_new_smear.Add(self.smear_slit_height, 0, wx.CENTER, 10)
         self.sizer_new_smear.Add(self.smear_data_left, 0, wx.CENTER, 10)
@@ -457,10 +472,9 @@
         self.sizer_new_smear.Add(self.smear_description_2d_y,
                                  0, wx.CENTER, 10)
-        self.sizer_new_smear.Add(self.smear_description_pin_percent,
+        self.sizer_new_smear.Add(self.smear_description_pin_percent_max,
                                  0, wx.CENTER, 10)
         self.sizer_new_smear.Add(self.smear_description_slit_width,
                                  0, wx.CENTER, 10)
 
-        self.sizer_new_smear.Add(self.smear_pinhole_percent, 0, wx.CENTER, 10)
         self.sizer_new_smear.Add(self.smear_slit_width, 0, wx.CENTER, 10)
         self.sizer_new_smear.Add(self.smear_data_right, 0, wx.CENTER, 10)
@@ -503,5 +517,5 @@
 
         # check if it is 2D data
-        if self.data.__class__.__name__ == "Data2D" or self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             is_2d_data = True
 
@@ -806,6 +820,5 @@
                         self.sizer4_4.Add(cb, (iy, ix), (1, 1),
                                 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
-                        if self.data.__class__.__name__ == "Data2D" or \
-                                    self.enable2D:
+                        if isinstance(self.data, Data2D) or self.enable2D:
                             cb.Show(True)
                         elif cb.IsShown():
@@ -819,6 +832,5 @@
                         ctl1.SetToolTipString(poly_tip)
                         ctl1.SetValue(str(format_number(value, True)))
-                        if self.data.__class__.__name__ == "Data2D" or \
-                                    self.enable2D:
+                        if isinstance(self.data, Data2D) or self.enable2D:
                             if first_orient:
                                 values.SetLabel('PD[ratio], Sig[deg]')
@@ -854,6 +866,5 @@
 
                         ctl2.Hide()
-                        if self.data.__class__.__name__ == "Data2D" or \
-                                self.enable2D:
+                        if isinstance(self.data, Data2D) or self.enable2D:
                             if self.is_mac:
                                 text2.Show(True)
@@ -880,6 +891,5 @@
                         ctl4.Hide()
 
-                        if self.data.__class__.__name__ == "Data2D" or \
-                                self.enable2D:
+                        if isinstance(self.data, Data2D) or self.enable2D:
                             ctl3.Show(True)
                             ctl4.Show(True)
@@ -893,6 +903,5 @@
 
                         Tctl.SetValue(str(format_number(value)))
-                        if self.data.__class__.__name__ == "Data2D" or \
-                                self.enable2D:
+                        if isinstance(self.data, Data2D) or self.enable2D:
                             Tctl.Show(True)
                         else:
@@ -913,6 +922,5 @@
 
                         Tct2.SetValue(str(format_number(value)))
-                        if self.data.__class__.__name__ == "Data2D" or \
-                                self.enable2D:
+                        if isinstance(self.data, Data2D) or self.enable2D:
                             Tct2.Show(True)
                         else:
@@ -941,6 +949,5 @@
                                             text2, ctl2, ctl3, ctl4, disp_box])
 
-                if self.data.__class__.__name__ == "Data2D" or \
-                                self.enable2D:
+                if isinstance(self.data, Data2D) or self.enable2D:
                     disp_box.Show(True)
                 else:
@@ -1327,6 +1334,5 @@
                         flag1 = self.update_pinhole_smear()
                         flag = flag or flag1
-                elif self.data.__class__.__name__ != "Data2D" and \
-                        not self.enable2D:
+                elif not isinstance(self.data, Data2D) and not self.enable2D:
                     enable_smearer = not self.disable_smearer.GetValue()
                     self._manager.set_smearer(smearer=temp_smearer,
@@ -1401,5 +1407,5 @@
         if event is not None:
             event.Skip()
-        if self.data.__class__.__name__ == "Data2D":
+        if isinstance(self.data, Data2D):
             return
         is_click = event.LeftDown()
@@ -1419,5 +1425,5 @@
         if event is not None:
             event.Skip()
-        if self.data.__class__.__name__ == "Data2D":
+        if isinstance(self.data, Data2D):
             return
         act_ctrl = event.GetEventObject()
@@ -1435,5 +1441,5 @@
         """
         event.Skip()
-        if self.data.__class__.__name__ == "Data2D":
+        if isinstance(self.data, Data2D):
             return
         ctrl = event.GetEventObject()
@@ -1496,6 +1502,5 @@
             # Check if # of points for theory model are valid(>0).
             # check for 2d
-            if self.data.__class__.__name__ == "Data2D" or \
-                    self.enable2D:
+            if isinstance(self.data, Data2D) or self.enable2D:
                 # set mask
                 radius = np.sqrt(self.data.qx_data * self.data.qx_data +
@@ -1549,6 +1554,5 @@
                 if item[0].IsShown():
                     # Skip the angle parameters if 1D data
-                    if self.data.__class__.__name__ != "Data2D" and \
-                            not self.enable2D:
+                    if not isinstance(self.data, Data2D) and not self.enable2D:
                         if item in self.orientation_params:
                             continue
@@ -1568,6 +1572,5 @@
                 if item[0].IsShown():
                     # Skip the angle parameters if 1D data
-                    if self.data.__class__.__name__ != "Data2D" and \
-                            not self.enable2D:
+                    if not isinstance(self.data, Data2D) and not self.enable2D:
                         if item in self.orientation_params:
                             continue
@@ -1601,41 +1604,68 @@
 
         :return: self.smear_type, self.dq_l and self.dq_r,
-            respectively the type of the smear, dq_min and
-            dq_max for pinhole smear data
-            while dxl and dxw for slit smear
-        """
-        # default
+            respectively the type of the smear, The average <dq/q> radial(p)
+            and <dq/q> theta (s)s for 2D pinhole resolution in % (slit is not
+            currently supported in 2D), (dq/q)_min and (dq/q)_max for 1D pinhole
+            smeared data, again in %, and dxl and/or dxw for slit smeared data
+            given in 1/A and assumed constant.
+        """
+        # set up defaults
         self.smear_type = None
         self.dq_l = None
         self.dq_r = None
         data = self.data
+        #sanity check - this should only be called if data exits
         if self.data is None:
             return
-        elif self.data.__class__.__name__ == "Data2D" or \
-            self.enable2D:
-            if data.dqx_data is None or data.dqy_data is None:
-                return
-            elif self.current_smearer is not None \
-                and data.dqx_data.any() != 0 \
-                and data.dqx_data.any() != 0:
+        #First check if data is 2D
+        #If so check that data set has smearing info and that none are zero.
+        #Otherwise no smearing can be applied using smear from data (a Gaussian
+        #width of zero will cause a divide by zero error)
+        if isinstance(self.data, Data2D):
+            if data.dqx_data is not None and data.dqy_data is not None \
+              and data.dqx_data.all()and data.dqy_data.all():
                 self.smear_type = "Pinhole2d"
-                self.dq_l = format_number(np.average(data.dqx_data))
-                self.dq_r = format_number(np.average(data.dqy_data))
-                return
+                #report as average dQ/Q % as for 1D pinhole
+                self.dq_l = format_number(np.average(data.dqx_data
+                                                     / abs(data.qx_data)) * 100)
+                self.dq_r = format_number(np.average(data.dqy_data
+                                                     / abs(data.qy_data)) * 100)
+            #if not then log that data did not contain resolutin info                                         / abs(data.qy_data)) * 100)
             else:
-                return
-        # check if it is pinhole smear and get min max if it is.
-        if data.dx is not None and np.any(data.dx):
-            self.smear_type = "Pinhole"
-            self.dq_l = data.dx[0]
-            self.dq_r = data.dx[-1]
-
-        # check if it is slit smear and get min max if it is.
-        elif data.dxl is not None or data.dxw is not None:
-            self.smear_type = "Slit"
-            if data.dxl is not None and np.all(data.dxl, 0):
-                self.dq_l = data.dxl[0]
-            if data.dxw is not None and np.all(data.dxw, 0):
-                self.dq_r = data.dxw[0]
+                self.msg = "2D Data did not contain recognizable " \
+                           "resolution info."
+                logger.info(self.msg)
+        #If not check that data is 1D
+        #If so check for pinhole vs slit by veryfing whehter dx or dxl or dxw
+        #have data (currently sasview only supports either dx or dxl/dxw but
+        #not both simultaneously) and, as for 2D, are non zero .
+        #Otherwise no smearing can be applied using smear from data (a Gaussian
+        #width of zero will cause a divide by zero error)
+        elif isinstance(self.data, Data1D):
+            #is it valid 1D pinhole resolution data?
+            if data.dx is not None and np.all(data.dx):
+                self.smear_type = "Pinhole"
+                #report in % for display makes more sense than absolute value
+                #for pinhole smearing .. but keep old names of dq_l
+                self.dq_l = format_number(data.dx[0] / data.x[0] * 100,1)
+                self.dq_r = format_number(data.dx[-1] / data.x[-1] * 100,1)
+            #If not, is it valid 1D slit resolution data?
+            elif (data.dxl is not None or data.dxw is not None) \
+                and (np.all(data.dxl, 0) or np.all(data.dxw, 0)):
+                self.smear_type = "Slit"
+                #for slit units of 1/A make most sense
+                if data.dxl is not None and np.all(data.dxl, 0):
+                    self.dq_l = format_number(data.dxl[0],1)
+                if data.dxw is not None and np.all(data.dxw, 0):
+                    self.dq_r = format_number(data.dxw[0],1)
+            #otherwise log that the data did not conatain resolution info
+            else:
+                self.msg = "1D Data did not contain recognizable " \
+                           "resolution info."
+                logger.info(self.msg)
+        #If drops to here it is neither data1D or data2D so log that
+        else:
+            self.msg = "Data was not recognized as either 1D or 2D data."
+            logger.info(self.msg)
         # return self.smear_type,self.dq_l,self.dq_r
 
@@ -1644,40 +1674,49 @@
         Show only the sizers depending on smear selection
         """
-        # smear disabled
+        # smear disabled = No Smearing used
         if self.disable_smearer.GetValue():
             self.smear_description_none.Show(True)
-        # 2Dsmear
+        # 2Dsmearing - for use with 2D data only
         elif self._is_2D():
             self.smear_description_accuracy_type.Show(True)
             self.smear_accuracy.Show(True)
-            self.smear_description_accuracy_type.Show(True)
             self.smear_description_2d.Show(True)
-            self.smear_description_2d_x.Show(True)
-            self.smear_description_2d_y.Show(True)
+            #2D custom pinhole smearing
             if self.pinhole_smearer.GetValue():
+                self.smear_description_pin_percent.Show(True)
                 self.smear_pinhole_percent.Show(True)
-        # smear from data
+            #get 2D smearing from data
+            elif self.enable_smearer.GetValue():
+                self.smear_description_2d_x.Show(True)
+                self.smear_description_2d_y.Show(True)
+                self.smear_data_left.Show(True)
+                self.smear_data_right.Show(True)
+            #Currently 2D custom slit smearing is not currently supported
+            else:
+                logger.error("2D custom smearing cannot use slit smearing")
+
+        # 1D smearing from data
         elif self.enable_smearer.GetValue():
-
             self.smear_description_dqdata.Show(True)
             if self.smear_type is not None:
                 self.smear_description_smear_type.Show(True)
+                #1D data has slit smearing
                 if self.smear_type == 'Slit':
                     self.smear_description_slit_height.Show(True)
                     self.smear_description_slit_width.Show(True)
+                #1D data has pinhole smearing
                 elif self.smear_type == 'Pinhole':
-                    self.smear_description_pin_percent.Show(True)
+                    self.smear_description_pin_percent_min.Show(True)
+                    self.smear_description_pin_percent_max.Show(True)
                 self.smear_description_smear_type.Show(True)
                 self.smear_description_type.Show(True)
                 self.smear_data_left.Show(True)
                 self.smear_data_right.Show(True)
-        # custom pinhole smear
+        # 1D custom pinhole smearing
         elif self.pinhole_smearer.GetValue():
-            if self.smear_type == 'Pinhole':
-                self.smear_message_new_p.Show(True)
-                self.smear_description_pin_percent.Show(True)
-
+            self.smear_message_new_p.Show(True)
+            self.smear_description_pin_percent.Show(True)
             self.smear_pinhole_percent.Show(True)
-        # custom slit smear
+        # 1D custom slit smear
         elif self.slit_smearer.GetValue():
             self.smear_message_new_s.Show(True)
@@ -1686,4 +1725,6 @@
             self.smear_description_slit_width.Show(True)
             self.smear_slit_width.Show(True)
+        else:
+            logger.error("smearing type is not defined")
 
     def _hide_all_smear_info(self):
@@ -1703,4 +1744,6 @@
         self.smear_data_left.Hide()
         self.smear_data_right.Hide()
+        self.smear_description_pin_percent_min.Hide()
+        self.smear_description_pin_percent_max.Hide()
         self.smear_description_pin_percent.Hide()
         self.smear_pinhole_percent.Hide()
@@ -1920,6 +1963,5 @@
             di_flag = False
             dq_flag = False
-            if self.data.__class__.__name__ == "Data2D" or \
-                        self.enable2D:
+            if isinstance(self.data, Data2D) or self.enable2D:
                 self.slit_smearer.Disable()
                 self.pinhole_smearer.Enable(True)
@@ -2006,5 +2048,5 @@
         # update model plot with new data information
         if flag:
-            if self.data.__class__.__name__ == "Data2D":
+            if isinstance(self.data, Data2D):
                 self.enable2D = True
                 self.model_view.SetLabel("2D Mode")
@@ -2073,6 +2115,5 @@
         npts2fit = 0
         qmin, qmax = self.get_range()
-        if self.data.__class__.__name__ == "Data2D" or \
-                        self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             radius = np.sqrt(self.data.qx_data * self.data.qx_data +
                                 self.data.qy_data * self.data.qy_data)
@@ -2464,5 +2505,5 @@
             of the values entered for slit smear
         """
-        if self.data.__class__.__name__ == "Data2D" or self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             return
         # make sure once more if it is smearer
@@ -2660,6 +2701,5 @@
         for item in self.parameters:
             # Skip t ifhe angle parameters if 1D data
-            if self.data.__class__.__name__ != "Data2D" and\
-                        not self.enable2D:
+            if not isinstance(self.data, Data2D) and not self.enable2D:
                 if item in self.orientation_params:
                     continue
@@ -2677,6 +2717,5 @@
         for item in self.fittable_param:
             # Skip t ifhe angle parameters if 1D data
-            if self.data.__class__.__name__ != "Data2D" and\
-                        not self.enable2D:
+            if not isinstance(self.data, Data2D) and not self.enable2D:
                 if item in self.orientation_params:
                     continue
@@ -2690,6 +2729,5 @@
 
         # Calculate num. of angle parameters
-        if self.data.__class__.__name__ == "Data2D" or \
-                       self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             len_orient_para = 0
         else:
@@ -2984,5 +3022,5 @@
                 if not self._has_magnetic:
                     mag_on_button.Show(False)
-                elif not self.data.__class__.__name__ == "Data2D":
+                elif not isinstance(self.data, Data2D):
                     mag_on_button.Show(False)
                 else:
@@ -3000,6 +3038,5 @@
                         mag_angle_help_button.Show(False)
 
-                if not self.data.__class__.__name__ == "Data2D" and \
-                        not self.enable2D:
+                if not isinstance(self.data, Data2D) and not self.enable2D:
                     orient_angle.Hide()
                 else:
@@ -3025,6 +3062,5 @@
                     cb.SetToolTipString("Check mark to fit")
                     wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
-                    if self.data.__class__.__name__ == "Data2D" or \
-                            self.enable2D:
+                    if isinstance(self.data, Data2D) or self.enable2D:
                         cb.Show(True)
                     else:
@@ -3041,6 +3077,5 @@
                                 "Hit 'Enter' after typing to update the plot.")
                     ctl1.SetValue(format_number(value, True))
-                    if self.data.__class__.__name__ == "Data2D" or \
-                            self.enable2D:
+                    if isinstance(self.data, Data2D) or self.enable2D:
                         ctl1.Show(True)
                     else:
@@ -3082,6 +3117,5 @@
                     ctl4.Hide()
 
-                    if self.data.__class__.__name__ == "Data2D" or \
-                            self.enable2D:
+                    if isinstance(self.data, Data2D) or self.enable2D:
                         if self.is_mac:
                             text2.Show(True)
@@ -3099,6 +3133,5 @@
                         units = wx.StaticText(self, -1, "",
                                               style=wx.ALIGN_LEFT)
-                    if self.data.__class__.__name__ == "Data2D" or \
-                            self.enable2D:
+                    if isinstance(self.data, Data2D) or self.enable2D:
                         units.Show(True)
                     else:
@@ -3179,12 +3212,17 @@
         """
         # more disables for 2D
-        if self.data.__class__.__name__ == "Data2D" or \
-                    self.enable2D:
+        if isinstance(self.data, Data2D) or self.enable2D:
             self.slit_smearer.Disable()
-            self.pinhole_smearer.Enable(True)
             self.default_mask = copy.deepcopy(self.data.mask)
-        else:
-            self.slit_smearer.Enable(True)
-            self.pinhole_smearer.Enable(True)
+            if self.model is not None:
+                self.pinhole_smearer.Enable(True)
+
+        elif isinstance(self.data, Data1D):
+            if self.model is not None:
+                self.slit_smearer.Enable(True)
+                self.pinhole_smearer.Enable(True)
+        else:
+            msg="data is not recognized as either 1D or 2D"
+            logger.info(msg)
 
 
Index: src/sas/sasgui/perspectives/fitting/fitting.py
===================================================================
--- src/sas/sasgui/perspectives/fitting/fitting.py	(revision aba455916c90b078a4a7d77651680d2dbf1b959f)
+++ src/sas/sasgui/perspectives/fitting/fitting.py	(revision a5cffe570a689752aa7b74ce8a71d2b1704e624f)
@@ -776,8 +776,6 @@
         :param weight: current dy data
         """
-        # If we are not dealing with a specific fit problem, then
-        # there is no point setting the weights.
-        if fid is None:
-            return
+        # Note: this is used to set the data weights for the fit based on
+        # the weight selection in the GUI.
         if uid in self.page_finder.keys():
             self.page_finder[uid].set_weight(flag=flag, is2d=is2d)
Index: src/sas/sasgui/perspectives/fitting/gpu_options.py
===================================================================
--- src/sas/sasgui/perspectives/fitting/gpu_options.py	(revision 388aefbfe7862efae1f1595105c7a8b53bb3e8e3)
+++ src/sas/sasgui/perspectives/fitting/gpu_options.py	(revision 895703d186f0963beb7b46058e022d7f4b7ae9d4)
@@ -8,9 +8,21 @@
 '''
 
+import json
+import platform
 import logging
 import os
 import sys
+
 import wx
+
+try:
+    import pyopencl as cl
+except ImportError:
+    cl = None
+
 import sasmodels
+import sasmodels.model_test
+import sasmodels.sasview_model
+
 from sas.sasgui.guiframe.documentation_window import DocumentationWindow
 
@@ -169,16 +181,17 @@
         clinfo = []
         platforms = []
-        try:
-            import pyopencl as cl
-            platforms = cl.get_platforms()
-        except ImportError:
+
+        if cl is None:
             logger.warn("Unable to import the pyopencl package.  It may not "
                         "have been installed.  If you wish to use OpenCL, try "
                         "running pip install --user pyopencl")
-        except cl.LogicError as err:
-            logger.warn("Unable to fetch the OpenCL platforms.  This likely "
-                        "means that the opencl drivers for your system are "
-                        "not installed.")
-            logger.warn(err)
+        else:
+            try:
+                platforms = cl.get_platforms()
+            except cl.LogicError as err:
+                logger.warn("Unable to fetch the OpenCL platforms.  This likely "
+                            "means that the opencl drivers for your system are "
+                            "not installed.")
+                logger.warn(err)
 
         p_index = 0
@@ -226,10 +239,5 @@
             if "SAS_OPENCL" in os.environ:
                 del os.environ["SAS_OPENCL"]
-
-        #Sasmodels kernelcl doesn't exist when initiated with None
-        if 'sasmodels.kernelcl' in sys.modules:
-            sasmodels.kernelcl.ENV = None
-
-        reload(sasmodels.core)
+        sasmodels.sasview_model.reset_environment()
         event.Skip()
 
@@ -247,8 +255,4 @@
         Run sasmodels check from here and report results from
         """
-        import json
-        import platform
-        #import sasmodels
-
         #The same block of code as for OK but it is needed if we want to have
         #active response to Test button
@@ -261,19 +265,8 @@
             if "SAS_OPENCL" in os.environ:
                 del os.environ["SAS_OPENCL"]
-
-        #Sasmodels kernelcl doesn't exist when initiated with None
-        if 'sasmodels.kernelcl' in sys.modules:
-            sasmodels.kernelcl.ENV = None
-
-
-        #Need to reload sasmodels.core module to account SAS_OPENCL = "None"
-        reload(sasmodels.core)
-
-
-        from sasmodels.model_test import model_tests
+        sasmodels.sasview_model.reset_environment()
 
         try:
-            from sasmodels.kernelcl import environment
-            env = environment()
+            env = sasmodels.kernelcl.environment()
             clinfo = [(ctx.devices[0].platform.vendor,
                        ctx.devices[0].platform.version,
@@ -282,10 +275,10 @@
                        ctx.devices[0].version)
                       for ctx in env.context]
-        except ImportError:
+        except Exception:
             clinfo = None
 
         failures = []
         tests_completed = 0
-        for test in model_tests():
+        for test in sasmodels.model_test.model_tests():
             try:
                 test()
Index: src/sas/sasgui/plottools/PlotPanel.py
===================================================================
--- src/sas/sasgui/plottools/PlotPanel.py	(revision 2469df7fc9ffa047115c5bffe589ed307b12c363)
+++ src/sas/sasgui/plottools/PlotPanel.py	(revision 75313af5ff7a47b13075dd439585c592071aebaf)
@@ -1434,4 +1434,5 @@
 
         """
+        # TODO: include mask info in plotter
         self.data = data
         self.qx_data = qx_data
@@ -1451,35 +1452,24 @@
         else:
             output = copy.deepcopy(self.data)
-        # check scale
+        # rescale data if necessary
         if self.scale == 'log_{10}':
-            try:
-                if  self.zmin_2D <= 0  and len(output[output > 0]) > 0:
-                    zmin_temp = self.zmin_2D
-                    output[output > 0] = np.log10(output[output > 0])
-                    #In log scale Negative values are not correct in general
-                    #output[output<=0] = math.log(np.min(output[output>0]))
-                elif self.zmin_2D <= 0:
-                    zmin_temp = self.zmin_2D
-                    output[output > 0] = np.zeros(len(output))
-                    output[output <= 0] = -32
-                else:
-                    zmin_temp = self.zmin_2D
-                    output[output > 0] = np.log10(output[output > 0])
-                    #In log scale Negative values are not correct in general
-                    #output[output<=0] = math.log(np.min(output[output>0]))
-            except:
-                #Too many problems in 2D plot with scale
-                pass
-
-        else:
-            zmin_temp = self.zmin_2D
+            with np.errstate(all='ignore'):
+                output = np.log10(output)
+            index = np.isfinite(output)
+            if not index.all():
+                cutoff = (np.min(output[index]) - np.log10(2)
+                          if index.any() else 0.)
+                output[~index] = cutoff
+        # TODO: fix handling of zmin_2D/zmax_2D in _onToggleScale
+        # For now, use default vmin/vmax from data
+        #vmin, vmax = self.zmin_2D, self.zmax_2D
+        vmin, vmax = None, None
         self.cmap = cmap
         if self.dimension != 3:
             #Re-adjust colorbar
             self.subplot.figure.subplots_adjust(left=0.2, right=.8, bottom=.2)
-
             im = self.subplot.imshow(output, interpolation='nearest',
                                      origin='lower',
-                                     vmin=zmin_temp, vmax=self.zmax_2D,
+                                     vmin=vmin, vmax=vmax,
                                      cmap=self.cmap,
                                      extent=(self.xmin_2D, self.xmax_2D,
Index: src/sas/sasview/__init__.py
===================================================================
--- src/sas/sasview/__init__.py	(revision b229a3bf14cf52237670dc67090e092cbe9939db)
+++ src/sas/sasview/__init__.py	(revision 5e16b300002805e77419d0b6692a4dbc4c5b04f6)
@@ -1,2 +1,6 @@
-__version__ = "4.2.0"
+from distutils.version import StrictVersion
+__version__ = "4.2.1"
+StrictVersion(__version__)
+__DOI__ = "Zenodo, 10.5281/zenodo.2561236"
+__release_date__ = "2019"
 __build__ = "GIT_COMMIT"
Index: src/sas/sasview/local_config.py
===================================================================
--- src/sas/sasview/local_config.py	(revision 1b4cb415644d6a02d2bc0e559654a42560242058)
+++ src/sas/sasview/local_config.py	(revision 839f70f759caa589905d9a52601c1b91d3151dba)
@@ -16,4 +16,6 @@
 __appname__ = "SasView"
 __version__ = sas.sasview.__version__
+__DOI__ = sas.sasview.__DOI__
+__release_date__ = sas.sasview.__release_date__
 __build__ = sas.sasview.__build__
 __download_page__ = 'https://github.com/SasView/sasview/releases'
@@ -36,6 +38,6 @@
 _do_tutorial = True
 _acknowledgement_preamble =\
-'''To ensure the long term support and development of this software please''' +\
-''' remember to:'''
+'''To ensure the long term support and development of this software please
+remember to:'''
 _acknowledgement_preamble_bullet1 =\
 '''Acknowledge its use in your publications as :'''
@@ -47,10 +49,18 @@
 '''Send us your reference for our records: developers@sasview.org'''
 _acknowledgement_publications = \
-'''This work benefited from the use of the SasView application, originally developed under NSF Award DMR-0520547. SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project Grant No 654000.'''
+("This work benefited from the use of the SasView application, originally"
+"developed under NSF Award DMR-0520547. SasView also contains code developed"
+"with funding from the EU Horizon 2020 programme under the SINE2020 project"
+"Grant No 654000.")
 _acknowledgement_citation = \
-'''M. Doucet et al. SasView Version 4.2, Zenodo, 10.5281/zenodo.1412041'''
+'''M. Doucet et al. SasView Version %s, %s''' % (__version__, __DOI__)
 _acknowledgement =  \
-'''This work was originally developed as part of the DANSE project funded by the US NSF under Award DMR-0520547,\n but is currently maintained by a collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, DLS, BAM and the scattering community.\n\n SasView also contains code developed with funding from the EU Horizon 2020 programme under the SINE2020 project (Grant No 654000).\nA list of individual contributors can be found at: http://www.sasview.org/contact.html
-'''
+("This work was originally developed as part of the DANSE project funded by"
+"the US NSF under Award DMR-0520547,\n but is currently maintained by a"
+"collaboration between UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft,"
+"DLS, BAM and the scattering community.\n\n SasView also contains code"
+"developed with funding from the EU Horizon 2020 programme under the SINE2020"
+"project (Grant No 654000).\nA list of individual contributors can be found"
+"at: http://www.sasview.org/contact.html")
 
 _homepage = "http://www.sasview.org"
@@ -95,5 +105,6 @@
 _corner_image = os.path.join(icon_path, "angles_flat.png")
 _welcome_image = os.path.join(icon_path, "SVwelcome.png")
-_copyright = "(c) 2009 - 2018, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO, TU Delft, DLS and BAM"
+_copyright = ("(c) 2009 - %s, UTK, UMD, NIST, ORNL, ISIS, ESS, ILL, ANSTO,"
+              "TU Delft, DLS and BAM") % __release_date__
 marketplace_url = "http://marketplace.sasview.org/"
 
Index: st/sasdataloader/test/avg_testdata.txt
===================================================================
--- test/sasdataloader/test/avg_testdata.txt	(revision 8c9ffde290eafed946f800881bf4901b48445d4c)
+++ 	(revision )
@@ -1,21 +1,0 @@
-0.00019987186878 -0.01196215 0.148605728355
-0.000453772721237 0.02091606 0.0680283029334
-0.000750492390439 -0.01337855 0.0444902910757
-0.00103996394336 0.03062 0.0580312894528
-0.0013420198959 0.0811008333333 0.0540469289108
-0.001652061869 0.167022288372 0.0651891320031
-0.00196086470492 27.5554711176 0.735053300957
-0.00226262401224 105.031578947 1.35744586624
-0.00256734439716 82.1791776119 1.10749938588
-0.0028637128388 54.714657971 0.890486416264
-0.00315257408712 36.8455584416 0.691746880003
-0.00344644126616 24.8938701149 0.534917225468
-0.00374248202229 16.5905619565 0.424655384023
-0.00404393067437 11.4714217925 0.328969543128
-0.004346317814 8.05405805556 0.273083524998
-0.00465162170627 5.5823291129 0.21217630209
-0.00495449803049 4.2574845082 0.186808495528
-0.00525641407066 3.30448963768 0.154743584955
-0.00555735057365 2.6995389781 0.140373302568
-0.00585577429002 2.03298512 0.116418358232
-
Index: st/sasdataloader/test/ring_testdata.txt
===================================================================
--- test/sasdataloader/test/ring_testdata.txt	(revision 400155bab01bdb35b3cf83069f57cf9f47005bca)
+++ 	(revision )
@@ -1,21 +1,0 @@
-<X>   <Y>   <dY>
-0.0 0.974491286452 0.0803843574327
-0.314159265359 0.9046853025 0.0768971192264
-0.628318530718 0.964040908176 0.0790933208542
-0.942477796077 0.922142905769 0.0781616076625
-1.25663706144 1.02710537736 0.080875897538
-1.57079632679 1.01448978075 0.0808313893873
-1.88495559215 1.04677136013 0.0828850195035
-2.19911485751 1.00067189877 0.0790510747578
-2.51327412287 1.06280533013 0.0830643956456
-2.82743338823 1.04313751703 0.0824585190353
-3.14159265359 0.993559460696 0.0803376331443
-3.45575191895 0.998101030127 0.0813124293449
-3.76991118431 1.04589910764 0.0821364674302
-4.08407044967 0.997201556522 0.0797466854806
-4.39822971503 1.07289797405 0.0830165798358
-4.71238898038 1.01212391625 0.0803021745794
-5.02654824574 0.995907123899 0.0804649435453
-5.3407075111 0.991431571613 0.0803765721376
-5.65486677646 0.959020086792 0.0787114622667
-5.96902604182 0.945705788519 0.0767669312314
Index: st/sasdataloader/test/sam14_cor.cor
===================================================================
--- test/sasdataloader/test/sam14_cor.cor	(revision fa749b7a4a403e49b9aa36906bc99a8352341221)
+++ 	(revision )
@@ -1,102 +1,0 @@
-COR FILES: SAM14001.bt5,SAM14002.bt5,SAM14003.bt5,SAM14004.bt5,SAM14005.bt5,SAM14006.bt5
-CREATED: Mon, Nov 30, 2015 at  1:00:40 PM
-LABEL: SAM14                                             
-EMP FILES: EMPTY001.bt5,EMPTY002.bt5,EMPTY003.bt5,EMPTY004.bt5,EMPTY005.bt5,EMPTY006.bt5
-Ds = 0.1 cm ; Twide = 0.92765 ; Trock = 0.91404
-SAM PEAK ANGLE: -0.43618 ; EMP PEAK ANGLE: -0.36015
-EMP LEVEL: 0.76 ; BKG LEVEL: 0.62
-    2.97581e-05         3155.39         9147.36          -0.117          -0.117          -0.117
-    3.25331e-05         57443.8         6532.22          -0.117          -0.117          -0.117
-    3.53081e-05         62828.8         5020.64          -0.117          -0.117          -0.117
-    3.80831e-05         63923.2         4398.92          -0.117          -0.117          -0.117
-    4.08581e-05           46286         3768.69          -0.117          -0.117          -0.117
-    4.36331e-05         44828.3         3631.04          -0.117          -0.117          -0.117
-    4.64081e-05         40226.7          3352.9          -0.117          -0.117          -0.117
-    4.91831e-05         38248.1         3100.51          -0.117          -0.117          -0.117
-    5.19581e-05         30714.4         2741.87          -0.117          -0.117          -0.117
-    5.47331e-05         28509.9         871.909          -0.117          -0.117          -0.117
-    5.69531e-05         28029.2         857.318          -0.117          -0.117          -0.117
-    5.91731e-05         24209.2          801.89          -0.117          -0.117          -0.117
-    6.13931e-05         22778.7         776.291          -0.117          -0.117          -0.117
-    6.36131e-05         21470.9         748.725          -0.117          -0.117          -0.117
-    6.58331e-05         20707.2         727.281          -0.117          -0.117          -0.117
-    6.80531e-05         17602.3         681.713          -0.117          -0.117          -0.117
-    7.02731e-05         16153.7         666.679          -0.117          -0.117          -0.117
-    7.24931e-05         15802.7         643.647          -0.117          -0.117          -0.117
-    7.47131e-05         13851.7         612.392          -0.117          -0.117          -0.117
-    7.69331e-05         13902.5          599.02          -0.117          -0.117          -0.117
-    7.91531e-05         11638.6         567.145          -0.117          -0.117          -0.117
-    8.13731e-05         12131.6         561.296          -0.117          -0.117          -0.117
-    8.35931e-05         12153.5         561.465          -0.117          -0.117          -0.117
-    8.58131e-05           10714         523.847          -0.117          -0.117          -0.117
-    8.80331e-05         9002.54         496.181          -0.117          -0.117          -0.117
-    9.02531e-05         9008.16         488.865          -0.117          -0.117          -0.117
-    9.24731e-05         8893.05         480.203          -0.117          -0.117          -0.117
-    9.46931e-05          8259.5          466.35          -0.117          -0.117          -0.117
-    9.69131e-05         7508.49         441.458          -0.117          -0.117          -0.117
-    9.91331e-05         6954.29         429.735          -0.117          -0.117          -0.117
-    0.000101353         8006.56         448.031          -0.117          -0.117          -0.117
-    0.000103573         7082.72         426.573          -0.117          -0.117          -0.117
-    0.000105793         5543.52         397.209          -0.117          -0.117          -0.117
-    0.000108013         5382.44         376.648          -0.117          -0.117          -0.117
-    0.000110233         5218.78         368.222          -0.117          -0.117          -0.117
-    0.000112453         5571.24         376.055          -0.117          -0.117          -0.117
-    0.000114673         4771.04         355.859          -0.117          -0.117          -0.117
-    0.000116893         5116.54         359.527          -0.117          -0.117          -0.117
-    0.000119113         4564.57         348.322          -0.117          -0.117          -0.117
-    0.000121333         4537.71         339.878          -0.117          -0.117          -0.117
-    0.000123553         3610.84         327.422          -0.117          -0.117          -0.117
-    0.000125773         3642.38         323.242          -0.117          -0.117          -0.117
-    0.000127993         3455.76         299.462          -0.117          -0.117          -0.117
-    0.000130213          3798.4         305.674          -0.117          -0.117          -0.117
-    0.000132433         3576.36         296.536          -0.117          -0.117          -0.117
-    0.000135208         3508.78         191.213          -0.117          -0.117          -0.117
-    0.000146308         2806.89         172.894          -0.117          -0.117          -0.117
-    0.000157408         2160.84         151.037          -0.117          -0.117          -0.117
-    0.000168508         2018.35         144.003          -0.117          -0.117          -0.117
-    0.000179608         1617.46         134.382          -0.117          -0.117          -0.117
-    0.000190708         1638.18         133.187          -0.117          -0.117          -0.117
-    0.000201808         1204.65         119.019          -0.117          -0.117          -0.117
-    0.000212908         1066.33         114.817          -0.117          -0.117          -0.117
-    0.000224008         1134.58         117.193          -0.117          -0.117          -0.117
-    0.000235108         985.606         109.112          -0.117          -0.117          -0.117
-    0.000246208         903.218         103.279          -0.117          -0.117          -0.117
-    0.000257308         1122.34         107.924          -0.117          -0.117          -0.117
-    0.000268408         931.559         100.903          -0.117          -0.117          -0.117
-    0.000279508          941.99         102.397          -0.117          -0.117          -0.117
-    0.000290608         987.108         101.917          -0.117          -0.117          -0.117
-    0.000301708         668.371         67.8889          -0.117          -0.117          -0.117
-    0.000329458         723.492         70.5954          -0.117          -0.117          -0.117
-    0.000357208         527.235         65.5549          -0.117          -0.117          -0.117
-    0.000384958         556.159         64.4845          -0.117          -0.117          -0.117
-    0.000412708         391.723         60.2398          -0.117          -0.117          -0.117
-    0.000440458         531.145         63.4185          -0.117          -0.117          -0.117
-    0.000468208         471.565         62.7555          -0.117          -0.117          -0.117
-    0.000495958         407.099         54.2228          -0.117          -0.117          -0.117
-    0.000523708         389.313         56.3202          -0.117          -0.117          -0.117
-    0.000551458          402.55         55.0228          -0.117          -0.117          -0.117
-    0.000579208         362.722          34.936          -0.117          -0.117          -0.117
-    0.000634708          310.08         33.0426          -0.117          -0.117          -0.117
-    0.000690208          387.88         35.7353          -0.117          -0.117          -0.117
-    0.000745708         236.126         31.3446          -0.117          -0.117          -0.117
-    0.000801208         220.429         30.8858          -0.117          -0.117          -0.117
-    0.000856708             239         30.8613          -0.117          -0.117          -0.117
-    0.000912208          175.32          28.957          -0.117          -0.117          -0.117
-    0.000967708         224.415         30.4937          -0.117          -0.117          -0.117
-     0.00102321         218.604         29.2753          -0.117          -0.117          -0.117
-     0.00107871         213.211         29.9653          -0.117          -0.117          -0.117
-     0.00113421         195.005         41.8901          -0.117          -0.117          -0.117
-     0.00124521         162.356         38.3399          -0.117          -0.117          -0.117
-     0.00135621         141.922         38.0223          -0.117          -0.117          -0.117
-     0.00146721         123.419         38.3763          -0.117          -0.117          -0.117
-     0.00157821         127.101         35.5679          -0.117          -0.117          -0.117
-     0.00168921         96.3196         36.1829          -0.117          -0.117          -0.117
-     0.00180021         147.298         38.9743          -0.117          -0.117          -0.117
-     0.00191121          132.85         36.6815          -0.117          -0.117          -0.117
-     0.00202221         121.225         37.3052          -0.117          -0.117          -0.117
-     0.00213321         41.8228         34.8919          -0.117          -0.117          -0.117
-     0.00224421         88.7933         32.6574          -0.117          -0.117          -0.117
-     0.00235521         107.864         34.5534          -0.117          -0.117          -0.117
-     0.00246621         148.713         33.9059          -0.117          -0.117          -0.117
-     0.00257721          97.396         35.7885          -0.117          -0.117          -0.117
-     0.00268821         109.554         28.7279          -0.117          -0.117          -0.117
Index: test/sasdataloader/test/sam14_cor.txt
===================================================================
--- test/sasdataloader/test/sam14_cor.txt	(revision d96744de9a57d30dd495ba032913ed4268252bf5)
+++ test/sasdataloader/test/sam14_cor.txt	(revision d96744de9a57d30dd495ba032913ed4268252bf5)
@@ -0,0 +1,102 @@
+COR FILES: SAM14001.bt5,SAM14002.bt5,SAM14003.bt5,SAM14004.bt5,SAM14005.bt5,SAM14006.bt5
+CREATED: Mon, Nov 30, 2015 at  1:00:40 PM
+LABEL: SAM14                                             
+EMP FILES: EMPTY001.bt5,EMPTY002.bt5,EMPTY003.bt5,EMPTY004.bt5,EMPTY005.bt5,EMPTY006.bt5
+Ds = 0.1 cm ; Twide = 0.92765 ; Trock = 0.91404
+SAM PEAK ANGLE: -0.43618 ; EMP PEAK ANGLE: -0.36015
+EMP LEVEL: 0.76 ; BKG LEVEL: 0.62
+    2.97581e-05         3155.39         9147.36          -0.117          -0.117          -0.117
+    3.25331e-05         57443.8         6532.22          -0.117          -0.117          -0.117
+    3.53081e-05         62828.8         5020.64          -0.117          -0.117          -0.117
+    3.80831e-05         63923.2         4398.92          -0.117          -0.117          -0.117
+    4.08581e-05           46286         3768.69          -0.117          -0.117          -0.117
+    4.36331e-05         44828.3         3631.04          -0.117          -0.117          -0.117
+    4.64081e-05         40226.7          3352.9          -0.117          -0.117          -0.117
+    4.91831e-05         38248.1         3100.51          -0.117          -0.117          -0.117
+    5.19581e-05         30714.4         2741.87          -0.117          -0.117          -0.117
+    5.47331e-05         28509.9         871.909          -0.117          -0.117          -0.117
+    5.69531e-05         28029.2         857.318          -0.117          -0.117          -0.117
+    5.91731e-05         24209.2          801.89          -0.117          -0.117          -0.117
+    6.13931e-05         22778.7         776.291          -0.117          -0.117          -0.117
+    6.36131e-05         21470.9         748.725          -0.117          -0.117          -0.117
+    6.58331e-05         20707.2         727.281          -0.117          -0.117          -0.117
+    6.80531e-05         17602.3         681.713          -0.117          -0.117          -0.117
+    7.02731e-05         16153.7         666.679          -0.117          -0.117          -0.117
+    7.24931e-05         15802.7         643.647          -0.117          -0.117          -0.117
+    7.47131e-05         13851.7         612.392          -0.117          -0.117          -0.117
+    7.69331e-05         13902.5          599.02          -0.117          -0.117          -0.117
+    7.91531e-05         11638.6         567.145          -0.117          -0.117          -0.117
+    8.13731e-05         12131.6         561.296          -0.117          -0.117          -0.117
+    8.35931e-05         12153.5         561.465          -0.117          -0.117          -0.117
+    8.58131e-05           10714         523.847          -0.117          -0.117          -0.117
+    8.80331e-05         9002.54         496.181          -0.117          -0.117          -0.117
+    9.02531e-05         9008.16         488.865          -0.117          -0.117          -0.117
+    9.24731e-05         8893.05         480.203          -0.117          -0.117          -0.117
+    9.46931e-05          8259.5          466.35          -0.117          -0.117          -0.117
+    9.69131e-05         7508.49         441.458          -0.117          -0.117          -0.117
+    9.91331e-05         6954.29         429.735          -0.117          -0.117          -0.117
+    0.000101353         8006.56         448.031          -0.117          -0.117          -0.117
+    0.000103573         7082.72         426.573          -0.117          -0.117          -0.117
+    0.000105793         5543.52         397.209          -0.117          -0.117          -0.117
+    0.000108013         5382.44         376.648          -0.117          -0.117          -0.117
+    0.000110233         5218.78         368.222          -0.117          -0.117          -0.117
+    0.000112453         5571.24         376.055          -0.117          -0.117          -0.117
+    0.000114673         4771.04         355.859          -0.117          -0.117          -0.117
+    0.000116893         5116.54         359.527          -0.117          -0.117          -0.117
+    0.000119113         4564.57         348.322          -0.117          -0.117          -0.117
+    0.000121333         4537.71         339.878          -0.117          -0.117          -0.117
+    0.000123553         3610.84         327.422          -0.117          -0.117          -0.117
+    0.000125773         3642.38         323.242          -0.117          -0.117          -0.117
+    0.000127993         3455.76         299.462          -0.117          -0.117          -0.117
+    0.000130213          3798.4         305.674          -0.117          -0.117          -0.117
+    0.000132433         3576.36         296.536          -0.117          -0.117          -0.117
+    0.000135208         3508.78         191.213          -0.117          -0.117          -0.117
+    0.000146308         2806.89         172.894          -0.117          -0.117          -0.117
+    0.000157408         2160.84         151.037          -0.117          -0.117          -0.117
+    0.000168508         2018.35         144.003          -0.117          -0.117          -0.117
+    0.000179608         1617.46         134.382          -0.117          -0.117          -0.117
+    0.000190708         1638.18         133.187          -0.117          -0.117          -0.117
+    0.000201808         1204.65         119.019          -0.117          -0.117          -0.117
+    0.000212908         1066.33         114.817          -0.117          -0.117          -0.117
+    0.000224008         1134.58         117.193          -0.117          -0.117          -0.117
+    0.000235108         985.606         109.112          -0.117          -0.117          -0.117
+    0.000246208         903.218         103.279          -0.117          -0.117          -0.117
+    0.000257308         1122.34         107.924          -0.117          -0.117          -0.117
+    0.000268408         931.559         100.903          -0.117          -0.117          -0.117
+    0.000279508          941.99         102.397          -0.117          -0.117          -0.117
+    0.000290608         987.108         101.917          -0.117          -0.117          -0.117
+    0.000301708         668.371         67.8889          -0.117          -0.117          -0.117
+    0.000329458         723.492         70.5954          -0.117          -0.117          -0.117
+    0.000357208         527.235         65.5549          -0.117          -0.117          -0.117
+    0.000384958         556.159         64.4845          -0.117          -0.117          -0.117
+    0.000412708         391.723         60.2398          -0.117          -0.117          -0.117
+    0.000440458         531.145         63.4185          -0.117          -0.117          -0.117
+    0.000468208         471.565         62.7555          -0.117          -0.117          -0.117
+    0.000495958         407.099         54.2228          -0.117          -0.117          -0.117
+    0.000523708         389.313         56.3202          -0.117          -0.117          -0.117
+    0.000551458          402.55         55.0228          -0.117          -0.117          -0.117
+    0.000579208         362.722          34.936          -0.117          -0.117          -0.117
+    0.000634708          310.08         33.0426          -0.117          -0.117          -0.117
+    0.000690208          387.88         35.7353          -0.117          -0.117          -0.117
+    0.000745708         236.126         31.3446          -0.117          -0.117          -0.117
+    0.000801208         220.429         30.8858          -0.117          -0.117          -0.117
+    0.000856708             239         30.8613          -0.117          -0.117          -0.117
+    0.000912208          175.32          28.957          -0.117          -0.117          -0.117
+    0.000967708         224.415         30.4937          -0.117          -0.117          -0.117
+     0.00102321         218.604         29.2753          -0.117          -0.117          -0.117
+     0.00107871         213.211         29.9653          -0.117          -0.117          -0.117
+     0.00113421         195.005         41.8901          -0.117          -0.117          -0.117
+     0.00124521         162.356         38.3399          -0.117          -0.117          -0.117
+     0.00135621         141.922         38.0223          -0.117          -0.117          -0.117
+     0.00146721         123.419         38.3763          -0.117          -0.117          -0.117
+     0.00157821         127.101         35.5679          -0.117          -0.117          -0.117
+     0.00168921         96.3196         36.1829          -0.117          -0.117          -0.117
+     0.00180021         147.298         38.9743          -0.117          -0.117          -0.117
+     0.00191121          132.85         36.6815          -0.117          -0.117          -0.117
+     0.00202221         121.225         37.3052          -0.117          -0.117          -0.117
+     0.00213321         41.8228         34.8919          -0.117          -0.117          -0.117
+     0.00224421         88.7933         32.6574          -0.117          -0.117          -0.117
+     0.00235521         107.864         34.5534          -0.117          -0.117          -0.117
+     0.00246621         148.713         33.9059          -0.117          -0.117          -0.117
+     0.00257721          97.396         35.7885          -0.117          -0.117          -0.117
+     0.00268821         109.554         28.7279          -0.117          -0.117          -0.117
Index: st/sasdataloader/test/sectorphi_testdata.txt
===================================================================
--- test/sasdataloader/test/sectorphi_testdata.txt	(revision 8c9ffde290eafed946f800881bf4901b48445d4c)
+++ 	(revision )
@@ -1,20 +1,0 @@
-0.0392699081699 1.1493915878 0.168324806231
-0.11780972451 0.782646832432 0.149121962919
-0.196349540849 0.706119607692 0.144012178287
-0.274889357189 0.911901097436 0.15555152836
-0.353429173529 0.974902392683 0.155253089415
-0.431968989869 1.01648397073 0.159026866657
-0.510508806208 1.00543825 0.162897198136
-0.589048622548 0.939649968421 0.160198723543
-0.667588438888 0.9170403625 0.154535441526
-0.746128255228 0.992733432558 0.155251042188
-0.824668071567 0.896487721622 0.158978849014
-0.903207887907 1.0337120475 0.161651279959
-0.981747704247 0.893411561538 0.151685984204
-1.06028752059 0.86231787 0.152618707077
-1.13882733693 1.0607364925 0.164276150316
-1.21736715327 1.0684421475 0.163649496829
-1.29590696961 1.09330437436 0.167871645263
-1.37444678595 0.88759347 0.150974201439
-1.45298660229 1.1352002 0.172191803977
-1.53152641863 0.940182580556 0.16499913089
Index: st/sasdataloader/test/sectorq_testdata.txt
===================================================================
--- test/sasdataloader/test/sectorq_testdata.txt	(revision 8c9ffde290eafed946f800881bf4901b48445d4c)
+++ 	(revision )
@@ -1,20 +1,0 @@
-0.00511441071783 3.62996057692 0.26421001906
-0.00536794842067 3.08426333333 0.226725360048
-0.00563163488481 2.60796274194 0.205094893141
-0.00588490295032 1.9348162623 0.178096320518
-0.00613345857943 1.7733072 0.16517157513
-0.00638164232075 1.47127022727 0.149304966898
-0.00662784449302 1.20943352174 0.132393436598
-0.00687996935062 1.09260586133 0.121129481208
-0.00713177859748 0.920554827027 0.112093900426
-0.0073754295467 0.722179797333 0.0994122997085
-0.00762120465356 0.806428308642 0.101199828878
-0.00787397172531 0.643935 0.0888805845221
-0.00811861136113 0.545498639506 0.0844090307303
-0.008367621478 0.540828518804 0.0775790478399
-0.00862439560875 0.506315036957 0.0759458433673
-0.00887906032589 0.435769230208 0.0692137718457
-0.00913119845523 0.405669568421 0.0705339106673
-0.00938052380065 0.331241946 0.061307573431
-0.00962825731078 0.237315993939 0.0578654769893
-0.00987552050718 0.296916590385 0.0592796733987
Index: st/sasdataloader/test/slabx_testdata.txt
===================================================================
--- test/sasdataloader/test/slabx_testdata.txt	(revision 8c9ffde290eafed946f800881bf4901b48445d4c)
+++ 	(revision )
@@ -1,50 +1,0 @@
--0.00975856539676 0.5172445 0.508549161832
--0.00934923500682 0.237763 0.243804737444
--0.00893990399468 0.12955415 0.254513408291
--0.0086670162536 0.9157545 0.676666276683
--0.00825768406971 0.65937975 0.406011006624
--0.00784835133627 0.8750275 0.661448221707
--0.00743901794994 1.02208225 0.519554195922
--0.00702968406854 1.079005 0.734508338959
--0.00662034960235 1.2496225 0.558932576435
--0.00621101469558 2.006035 1.00150761355
--0.00580167927212 2.4278325 0.779075172881
--0.00539234346255 3.455125 1.31436771871
--0.00498300720441 4.0214125 1.00267299006
--0.00457367061464 4.505215 1.500868915
--0.0041643336444 9.1015275 1.50843689792
--0.00375499639702 12.9323 2.54286256019
--0.00334565883727 24.9572 2.4978590833
--0.00293632105486 40.0841 4.47683481938
--0.00266342906662 60.4813 5.49914993431
--0.00225409091154 76.368475 4.36945291198
--0.00184475260646 2.40154 1.09579651396
--0.00143541414791 0.065281 0.198049867458
--0.00102607559383 -0.04767235 0.154389685536
--0.000616736954402 -0.0090503 0.0960105462957
--0.000207398273925 0.03109325 0.246629023029
-0.000201940423805 -0.027508775 0.082928847514
-0.000611279108096 0.03251315 0.246951260373
-0.00102061774154 -0.00987975 0.144233534589
-0.00142995630705 0.075937 0.19485507435
-0.00183929475361 10.60918375 1.62858709853
-0.00224863307777 106.2485 7.2886384188
-0.00265797121486 69.731775 4.17527768538
-0.00306730917507 37.64245 4.33834357791
-0.00334020101548 29.14025 3.81708331059
-0.00374953854926 16.858125 2.05293235398
-0.00415887583351 7.860455 1.98248013861
-0.00456821277179 4.8616775 1.1024606002
-0.00497754940605 4.619795 1.51983469496
-0.00538688562624 3.1591075 0.888693915249
-0.00579622148792 1.72058 0.927518193892
-0.00620555686743 1.913115 0.69157700222
-0.00661489183396 1.08108 0.735214254486
-0.0070242262502 1.0834955 0.520455449582
-0.00743356019898 0.4708995 0.485231645712
-0.00784289352938 0.774794 0.440111917585
-0.00825222633782 0.7830585 0.625722981838
-0.00866155845978 0.44196625 0.37397468163
-0.0090708900053 0.1305591 0.306123259489
-0.0093437773029 0.1961264 0.341325065004
-0.00975310762291 0.25845 0.280772594817
Index: st/sasdataloader/test/slaby_testdata.txt
===================================================================
--- test/sasdataloader/test/slaby_testdata.txt	(revision 8c9ffde290eafed946f800881bf4901b48445d4c)
+++ 	(revision )
@@ -1,50 +1,0 @@
--0.00981587154747 0.197046827778 0.0872226309261
--0.00940654133769 0.2466434 0.124972263589
--0.0089972103454 0.218745969444 0.0838510368061
--0.00858787875434 0.126093522222 0.107482002513
--0.00817854644886 0.310427366667 0.100945289852
--0.0077692135991 0.0843802722222 0.103942898914
--0.00735988010303 0.246036369444 0.0916479235889
--0.00695054611716 0.217840922222 0.128330031223
--0.00654121155308 0.379668444444 0.103424340152
--0.00613187655368 0.447654644444 0.166575873418
--0.00585898627901 0.419026583333 0.15428551475
--0.00544965048161 0.401599005556 0.107234964701
--0.00504031432153 0.552085055556 0.178458012837
--0.00463097774216 0.623354058333 0.134112874252
--0.0042216408546 0.653190877778 0.199963470429
--0.00381230361585 0.661400280556 0.136616295765
--0.00340296612338 0.714432968889 0.206518400818
--0.00299362834783 0.653196219444 0.137770239209
--0.00258429037305 0.823240055556 0.215465509543
--0.00217495218329 0.9738398 0.165854141631
--0.00176561384878 0.827869716667 0.217884056409
--0.00135627536739 1.01947547778 0.169285496487
--0.000946936795747 1.1655315 0.256453669437
--0.000537598145326 1.06619988306 0.174316381271
--0.000128259459128 1.03232983333 0.243681074459
-0.000144633007054 1.15035461111 0.254186641595
-0.000553971692162 1.14101948333 0.179426295522
-0.000963310340403 1.07222452222 0.244970006982
-0.00137264890851 1.16437213056 0.185866492018
-0.00178198738526 0.852203596111 0.219166988663
-0.00219132571378 0.901962183333 0.160186399428
-0.00260066389646 0.9240665 0.230158379447
-0.00301000186279 0.617907672222 0.137762238147
-0.00341933962881 0.650284455556 0.191734208711
-0.00382867711038 0.578899836111 0.127147693175
-0.00423801433715 0.507045738889 0.172630602733
-0.00464735121136 0.613949591667 0.131836392307
-0.00505668777629 0.593631783333 0.181602707905
-0.00532957859826 0.310741433333 0.143429472495
-0.00573891447198 0.422394166667 0.111503089837
-0.00614824996377 0.342731566667 0.148392724273
-0.0065575849441 0.286779447222 0.0946855610872
-0.00696691948801 0.223022966667 0.134800066857
-0.00737625345237 0.220648719444 0.0901314425104
-0.00778558692582 0.210920222222 0.13171959555
-0.00819491975161 0.206120872222 0.0877029867729
-0.00860425203202 0.26088625 0.127667879068
-0.00901358359666 0.156064891667 0.0817093355086
-0.00942291456144 0.177010094444 0.134301097823
-0.00983224474235 0.130891508333 0.0796420846741
Index: test/sasdataloader/test/test_data/avg_testdata.txt
===================================================================
--- test/sasdataloader/test/test_data/avg_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
+++ test/sasdataloader/test/test_data/avg_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
@@ -0,0 +1,21 @@
+0.00019987186878 -0.01196215 0.148605728355
+0.000453772721237 0.02091606 0.23372601
+0.000750492390439 -0.01337855 0.17169562
+0.00103996394336 0.03062 0.13136407
+0.0013420198959 0.0811008333333 0.10681163
+0.001652061869 0.167022288372 0.10098903
+0.00196086470492 27.5554711176 0.7350533
+0.00226262401224 105.031578947 1.35744586624
+0.00256734439716 82.1791776119 1.10749938588
+0.0028637128388 54.714657971 0.890486416264
+0.00315257408712 36.8455584416 0.691746880003
+0.00344644126616 24.8938701149 0.534917225468
+0.00374248202229 16.5905619565 0.424655384023
+0.00404393067437 11.4714217925 0.328969543128
+0.004346317814 8.05405805556 0.273083524998
+0.00465162170627 5.5823291129 0.21217630209
+0.00495449803049 4.2574845082 0.186808495528
+0.00525641407066 3.30448963768 0.154743584955
+0.00555735057365 2.6995389781 0.140373302568
+0.00585577429002 2.03298512 0.116418358232
+
Index: test/sasdataloader/test/test_data/ring_testdata.txt
===================================================================
--- test/sasdataloader/test/test_data/ring_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
+++ test/sasdataloader/test/test_data/ring_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
@@ -0,0 +1,21 @@
+<X>   <Y>   <dY>
+0.0 0.974491286452 0.0803843574327
+0.314159265359 0.9046853025 0.0768971192264
+0.628318530718 0.964040908176 0.0790933208542
+0.942477796077 0.922142905769 0.0781616076625
+1.25663706144 1.02710537736 0.08136351514804
+1.57079632679 1.01448978075 0.0808313893873
+1.88495559215 1.04677136013 0.0828850195035
+2.19911485751 1.00067189877 0.0790510747578
+2.51327412287 1.06280533013 0.0830643956456
+2.82743338823 1.04313751703 0.0824585190353
+3.14159265359 0.993559460696 0.0803376331443
+3.45575191895 0.998101030127 0.0813124293449
+3.76991118431 1.04589910764 0.0821364674302
+4.08407044967 0.997201556522 0.0797466854806
+4.39822971503 1.07289797405 0.0830165798358
+4.71238898038 1.01212391625 0.0803021745794
+5.02654824574 0.995907123899 0.0804649435453
+5.3407075111 0.991431571613 0.0803765721376
+5.65486677646 0.959020086792 0.0787114622667
+5.96902604182 0.945705788519 0.0767669312314
Index: test/sasdataloader/test/test_data/sectorphi_testdata.txt
===================================================================
--- test/sasdataloader/test/test_data/sectorphi_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
+++ test/sasdataloader/test/test_data/sectorphi_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
@@ -0,0 +1,20 @@
+0.0392699081699 1.1493915878 0.168324806231
+0.11780972451 0.782646832432 0.149121962919
+0.196349540849 0.706119607692 0.144012178287
+0.274889357189 0.911901097436 0.15555152836
+0.353429173529 0.974902392683 0.155253089415
+0.431968989869 1.01648397073 0.159026866657
+0.510508806208 1.00543825 0.162897198136
+0.589048622548 0.939649968421 0.160198723543
+0.667588438888 0.9170403625 0.154535441526
+0.746128255228 0.992733432558 0.155251042188
+0.824668071567 0.896487721622 0.158978849014
+0.903207887907 1.0337120475 0.161651279959
+0.981747704247 0.893411561538 0.151685984204
+1.06028752059 0.86231787 0.152618707077
+1.13882733693 1.0607364925 0.166167546658
+1.21736715327 1.0684421475 0.163649496829
+1.29590696961 1.09330437436 0.16981858402
+1.37444678595 0.88759347 0.150974201439
+1.45298660229 1.1352002 0.172191803977
+1.53152641863 0.940182580556 0.16499913089
Index: test/sasdataloader/test/test_data/sectorq_testdata.txt
===================================================================
--- test/sasdataloader/test/test_data/sectorq_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
+++ test/sasdataloader/test/test_data/sectorq_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
@@ -0,0 +1,20 @@
+0.00511441071783 3.62996057692 0.26421001906
+0.00536794842067 3.08426333333 0.226725360048
+0.00563163488481 2.60796274194 0.205094893141
+0.00588490295032 1.9348162623 0.178096320518
+0.00613345857943 1.7733072 0.16517157513
+0.00638164232075 1.47127022727 0.149304966898
+0.00662784449302 1.20943352174 0.132393436598
+0.00687996935062 1.09260586133 0.121129481208
+0.00713177859748 0.920554827027 0.112093900426
+0.0073754295467 0.722179797333 0.0994122997085
+0.00762120465356 0.806428308642 0.101199828878
+0.00787397172531 0.643935 0.0888805845221
+0.00811861136113 0.545498639506 0.0844090307303
+0.008367621478 0.540828518804 0.0775790478399
+0.00862439560875 0.506315036957 0.0759458433673
+0.00887906032589 0.435769230208 0.0692137718457
+0.00913119845523 0.405669568421 0.0705339106673
+0.00938052380065 0.331241946 0.061307573431
+0.00962825731078 0.237315993939 0.059602636160850493
+0.00987552050718 0.296916590385 0.0592796733987
Index: test/sasdataloader/test/test_data/slabx_testdata.txt
===================================================================
--- test/sasdataloader/test/test_data/slabx_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
+++ test/sasdataloader/test/test_data/slabx_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
@@ -0,0 +1,50 @@
+-0.00975856539676 0.5172445 0.508549161832
+-0.00934923500682 0.237763 0.243804737444
+-0.00893990399468 0.12955415 0.254513408291
+-0.0086670162536 0.9157545 0.676666276683
+-0.00825768406971 0.65937975 0.406011006624
+-0.00784835133627 0.8750275 0.661448221707
+-0.00743901794994 1.02208225 0.519554195922
+-0.00702968406854 1.079005 0.734508338959
+-0.00662034960235 1.2496225 0.558932576435
+-0.00621101469558 2.006035 1.00150761355
+-0.00580167927212 2.4278325 0.779075172881
+-0.00539234346255 3.455125 1.31436771871
+-0.00498300720441 4.0214125 1.00267299006
+-0.00457367061464 4.505215 1.500868915
+-0.0041643336444 9.1015275 1.50843689792
+-0.00375499639702 12.9323 2.54286256019
+-0.00334565883727 24.9572 2.4978590833
+-0.00293632105486 40.0841 4.47683481938
+-0.00266342906662 60.4813 5.49914993431
+-0.00225409091154 76.368475 4.36945291198
+-0.00184475260646 2.40154 1.09579651396
+-0.00143541414791 0.065281 0.198049867458
+-0.00102607559383 -0.04767235 0.52329358394690839
+-0.000616736954402 -0.0090503 0.36635778277525377
+-0.000207398273925 0.03109325 0.246629023029
+0.000201940423805 -0.027508775 0.36314899662535211
+0.000611279108096 0.03251315 0.246951260373
+0.00102061774154 -0.00987975 0.38184199939241886
+0.00142995630705 0.075937 0.53662696540520582
+0.00183929475361 10.60918375 1.62858709853
+0.00224863307777 106.2485 7.2886384188
+0.00265797121486 69.731775 4.17527768538
+0.00306730917507 37.64245 4.33834357791
+0.00334020101548 29.14025 3.81708331059
+0.00374953854926 16.858125 2.05293235398
+0.00415887583351 7.860455 1.98248013861
+0.00456821277179 4.8616775 1.1024606002
+0.00497754940605 4.619795 1.51983469496
+0.00538688562624 3.1591075 0.888693915249
+0.00579622148792 1.72058 0.927518193892
+0.00620555686743 1.913115 0.69157700222
+0.00661489183396 1.08108 0.735214254486
+0.0070242262502 1.0834955 0.520455449582
+0.00743356019898 0.4708995 0.485231645712
+0.00784289352938 0.774794 0.440111917585
+0.00825222633782 0.7830585 0.625722981838
+0.00866155845978 0.44196625 0.37397468163
+0.0090708900053 0.1305591 0.306123259489
+0.0093437773029 0.1961264 0.341325065004
+0.00975310762291 0.25845 0.280772594817
Index: test/sasdataloader/test/test_data/slaby_testdata.txt
===================================================================
--- test/sasdataloader/test/test_data/slaby_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
+++ test/sasdataloader/test/test_data/slaby_testdata.txt	(revision 7fd5e2abcc660d7481c92bbd68091179ecb0c4a8)
@@ -0,0 +1,50 @@
+-0.00981587154747 0.197046827778 0.09153902
+-0.00940654133769 0.2466434 0.124972263589
+-0.0089972103454 0.218745969444 0.0838510368061
+-0.00858787875434 0.126093522222 0.107482002513
+-0.00817854644886 0.310427366667 0.10469745
+-0.0077692135991 0.0843802722222 0.103942898914
+-0.00735988010303 0.246036369444 0.0916479235889
+-0.00695054611716 0.217840922222 0.128330031223
+-0.00654121155308 0.379668444444 0.103424340152
+-0.00613187655368 0.447654644444 0.166575873418
+-0.00585898627901 0.419026583333 0.15428551475
+-0.00544965048161 0.401599005556 0.107234964701
+-0.00504031432153 0.552085055556 0.178458012837
+-0.00463097774216 0.623354058333 0.134112874252
+-0.0042216408546 0.653190877778 0.199963470429
+-0.00381230361585 0.661400280556 0.136616295765
+-0.00340296612338 0.714432968889 0.206518400818
+-0.00299362834783 0.653196219444 0.137770239209
+-0.00258429037305 0.823240055556 0.215465509543
+-0.00217495218329 0.9738398 0.165854141631
+-0.00176561384878 0.827869716667 0.217884056409
+-0.00135627536739 1.01947547778 0.169285496487
+-0.000946936795747 1.1655315 0.256453669437
+-0.000537598145326 1.06619988306 0.174316381271
+-0.000128259459128 1.03232983333 0.243681074459
+0.000144633007054 1.15035461111 0.254186641595
+0.000553971692162 1.14101948333 0.179426295522
+0.000963310340403 1.07222452222 0.244970006982
+0.00137264890851 1.16437213056 0.185866492018
+0.00178198738526 0.852203596111 0.219166988663
+0.00219132571378 0.901962183333 0.160186399428
+0.00260066389646 0.9240665 0.230158379447
+0.00301000186279 0.617907672222 0.137762238147
+0.00341933962881 0.650284455556 0.191734208711
+0.00382867711038 0.578899836111 0.127147693175
+0.00423801433715 0.507045738889 0.172630602733
+0.00464735121136 0.613949591667 0.131836392307
+0.00505668777629 0.593631783333 0.181602707905
+0.00532957859826 0.310741433333 0.143429472495
+0.00573891447198 0.422394166667 0.111503089837
+0.00614824996377 0.342731566667 0.148392724273
+0.0065575849441 0.286779447222 0.0946855610872
+0.00696691948801 0.223022966667 0.134800066857
+0.00737625345237 0.220648719444 0.0901314425104
+0.00778558692582 0.210920222222 0.13171959555
+0.00819491975161 0.206120872222 0.0877029867729
+0.00860425203202 0.26088625 0.127667879068
+0.00901358359666 0.156064891667 0.0817093355086
+0.00942291456144 0.177010094444 0.134301097823
+0.00983224474235 0.130891508333 0.0796420846741
Index: test/sasdataloader/test/utest_ascii.py
===================================================================
--- test/sasdataloader/test/utest_ascii.py	(revision db5196dd7f9255bf3b6ada8a4fd9ac553d59d362)
+++ test/sasdataloader/test/utest_ascii.py	(revision 9fb4572de33478e1d35c616d65a55afd2bc3e077)
@@ -10,4 +10,5 @@
 import unittest
 from sas.sascalc.dataloader.loader import Loader
+from sas.sascalc.dataloader.data_info import Data2D
 
 
@@ -121,4 +122,5 @@
             self.assertFalse(math.isnan(f_1d.y[i]))
             self.assertFalse(math.isnan(f_1d.dy[i]))
+        self.assertTrue(isinstance(f_2d, Data2D))
         f_2d.data = f_2d.data.flatten()
         f_2d.qx_data = f_2d.qx_data.flatten()
Index: test/sasdataloader/test/utest_averaging.py
===================================================================
--- test/sasdataloader/test/utest_averaging.py	(revision f53d684ed4a54de3601e5f4bc601f78376d98e83)
+++ test/sasdataloader/test/utest_averaging.py	(revision f4e2f22f114f61e70b4756a304d744184be4ab99)
@@ -106,5 +106,5 @@
 
     def setUp(self):
-        filepath = find('MAR07232_rest.h5')
+        filepath = find('test_data' + os.sep + 'MAR07232_rest.h5')
         self.data_list = Loader().load(filepath)
         self.data = self.data_list[0]
@@ -121,5 +121,5 @@
 
         o = r(self.data)
-        filepath = find('ring_testdata.txt')
+        filepath = find('test_data' + os.sep + 'ring_testdata.txt')
         answer_list = Loader().load(filepath)
         answer = answer_list[0]
@@ -142,5 +142,5 @@
         o = r(self.data)
 
-        filepath = find('avg_testdata.txt')
+        filepath = find('test_data' + os.sep + 'avg_testdata.txt')
         answer = Loader().load(filepath)[0]
         for i in range(r.nbins_phi):
@@ -158,5 +158,5 @@
         s, ds, npoints = r(self.data)
         self.assertAlmostEqual(s, 34.278990899999997, 4)
-        self.assertAlmostEqual(ds, 7.8007981835194293, 4)
+        self.assertAlmostEqual(ds, 8.237259999538685, 4)
         self.assertAlmostEqual(npoints, 324.0000, 4)
 
@@ -164,5 +164,5 @@
         s, ds = r(self.data)
         self.assertAlmostEqual(s, 0.10579935462962962, 4)
-        self.assertAlmostEqual(ds, 0.024076537603455028, 4)
+        self.assertAlmostEqual(ds, 0.02542364197388483, 4)
 
     def test_slabX(self):
@@ -177,5 +177,5 @@
         o = r(self.data)
 
-        filepath = find('slabx_testdata.txt')
+        filepath = find('test_data' + os.sep + 'slabx_testdata.txt')
         answer = Loader().load(filepath)[0]
         for i in range(len(o.x)):
@@ -195,5 +195,5 @@
         o = r(self.data)
 
-        filepath = find('slaby_testdata.txt')
+        filepath = find('test_data' + os.sep + 'slaby_testdata.txt')
         answer = Loader().load(filepath)[0]
         for i in range(len(o.x)):
@@ -221,5 +221,5 @@
         o = r(self.data)
 
-        filepath = find('ring_testdata.txt')
+        filepath = find('test_data' + os.sep + 'ring_testdata.txt')
         answer = Loader().load(filepath)[0]
         for i in range(len(o.x)):
@@ -238,5 +238,5 @@
         o = r(self.data)
 
-        filepath = find('sectorphi_testdata.txt')
+        filepath = find('test_data' + os.sep + 'sectorphi_testdata.txt')
         answer = Loader().load(filepath)[0]
         for i in range(len(o.x)):
@@ -255,5 +255,5 @@
         o = r(self.data)
 
-        filepath = find('sectorq_testdata.txt')
+        filepath = find('test_data' + os.sep + 'sectorq_testdata.txt')
         answer = Loader().load(filepath)[0]
         for i in range(len(o.x)):
Index: test/sasdataloader/test/utest_cansas.py
===================================================================
--- test/sasdataloader/test/utest_cansas.py	(revision f53d684ed4a54de3601e5f4bc601f78376d98e83)
+++ test/sasdataloader/test/utest_cansas.py	(revision f4e2f22f114f61e70b4756a304d744184be4ab99)
@@ -91,8 +91,5 @@
         reader = XMLreader(self.xml_valid, self.schema_1_0)
         valid = reader.validate_xml()
-        if valid:
-            self.assertTrue(valid)
-        else:
-            self.assertFalse(valid)
+        self.assertTrue(valid)
 
     def _check_data(self, data):
@@ -193,6 +190,5 @@
     def test_save_cansas_v1_0(self):
         xmlreader = XMLreader(self.isis_1_0, self.schema_1_0)
-        valid = xmlreader.validate_xml()
-        self.assertTrue(valid)
+        self.assertTrue(xmlreader.validate_xml())
         reader_generic = Loader()
         dataloader = reader_generic.load(self.isis_1_0)
@@ -207,7 +203,6 @@
             return_data = reader2.read(self.write_1_0_filename)
             written_data = return_data[0]
-            XMLreader(self.write_1_0_filename, self.schema_1_0)
-            valid = xmlreader.validate_xml()
-            self.assertTrue(valid)
+            xmlreader = XMLreader(self.write_1_0_filename, self.schema_1_0)
+            self.assertTrue(xmlreader.validate_xml())
             self._check_data(written_data)
         if os.path.isfile(self.write_1_0_filename):
@@ -260,7 +255,10 @@
         self.loader = Loader()
         self.datafile_basic = find("simpleexamplefile.h5")
-        self.datafile_multiplesasentry = find("cansas_1Dand2D_samedatafile.h5")
-        self.datafile_multiplesasdata = find("cansas_1Dand2D_samesasentry.h5")
-        self.datafile_multiplesasdata_multiplesasentry = find("cansas_1Dand2D_multiplesasentry_multiplesasdata.h5")
+        self.datafile_multiplesasentry = find(
+            "test_data" + os.sep + "nxcansas_1Dand2D_multisasentry.h5")
+        self.datafile_multiplesasdata = find(
+            "test_data" + os.sep + "nxcansas_1Dand2D_multisasdata.h5")
+        self.datafile_multiplesasdata_multiplesasentry = find(
+            "test_data" + os.sep + "nxcansas_1Dand2D_multisasentry_multisasdata.h5")
 
     def test_real_data(self):
@@ -273,40 +271,75 @@
         self._check_multiple_data(self.data[0])
         self._check_multiple_data(self.data[1])
-        self._check_1d_data(self.data[0])
+        if isinstance(self.data[0], Data1D):
+            self._check_1d_data(self.data[0])
+            self._check_2d_data(self.data[1])
+        else:
+            self._check_1d_data(self.data[1])
+            self._check_2d_data(self.data[0])
+
+    def test_multiple_sasdatas(self):
+        self.data = self.loader.load(self.datafile_multiplesasdata)
+        self.assertTrue(len(self.data) == 2)
+        self._check_multiple_data(self.data[0])
+        self._check_multiple_data(self.data[1])
+        if isinstance(self.data[0], Data1D):
+            self._check_1d_data(self.data[0])
+            self._check_2d_data(self.data[1])
+        else:
+            self._check_1d_data(self.data[1])
+            self._check_2d_data(self.data[0])
+
+    def test_multiple_sasentries_multiplesasdatas(self):
+        self.data = self.loader.load(
+            self.datafile_multiplesasdata_multiplesasentry)
+        self.assertTrue(len(self.data) == 4)
+        self._check_multiple_data(self.data[0])
+        self._check_multiple_data(self.data[1])
+        self._check_multiple_data(self.data[2])
+        self._check_multiple_data(self.data[3])
+        for data in self.data:
+            if isinstance(data, Data1D):
+                self._check_1d_data(data)
+            else:
+                self._check_2d_data(data)
 
     def _check_multiple_data(self, data):
-        self.assertTrue(data.title == "MH4_5deg_16T_SLOW")
-        self.assertTrue(data.run[0] == '33837')
-        self.assertTrue(len(data.run) == 1)
-        self.assertTrue(data.instrument == "SANS2D")
-        self.assertTrue(data.source.radiation == "Spallation Neutron Source")
-        self.assertTrue(len(data.detector) == 1)
-        self.assertTrue(data.detector[0].name == "rear-detector")
-        self.assertTrue(data.detector[0].distance == 4.385281)
-        self.assertTrue(data.detector[0].distance_unit == 'm')
-        self.assertTrue(len(data.trans_spectrum) == 1)
+        self.assertEqual(data.title, "MH4_5deg_16T_SLOW")
+        self.assertEqual(data.run[0], '33837')
+        self.assertEqual(len(data.run), 1)
+        self.assertEqual(data.instrument, "SANS2D")
+        self.assertEqual(data.source.radiation, "Spallation Neutron Source")
+        self.assertEqual(len(data.detector), 2)
+        self.assertTrue(data.detector[0].name == "rear-detector"
+                        or data.detector[1].name == "rear-detector")
+        self.assertTrue(data.detector[0].name == "front-detector"
+                        or data.detector[1].name == "front-detector")
+        self.assertAlmostEqual(data.detector[0].distance +
+                               data.detector[1].distance, 7230.54, 2)
+        self.assertEqual(data.detector[0].distance_unit, 'mm')
+        self.assertEqual(len(data.trans_spectrum), 1)
 
     def _check_1d_data(self, data):
-        self.assertTrue(isinstance(data, Data1D))
-        self.assertTrue(len(data.x) == 66)
-        self.assertTrue(len(data.x) == len(data.y))
-        self.assertTrue(data.dy[10] == 0.20721350111248701)
-        self.assertTrue(data.y[10] == 24.193889608153476)
-        self.assertTrue(data.x[10] == 0.008981127988654792)
+        self.assertEqual(len(data.x), 66)
+        self.assertEqual(len(data.x), len(data.y))
+        self.assertAlmostEqual(data.dy[10], 0.207214)
+        self.assertAlmostEqual(data.y[10], 24.1939)
+        self.assertAlmostEqual(data.x[10], 0.00898113)
 
     def _check_2d_data(self, data):
         self.assertTrue(isinstance(data, Data2D))
-        self.assertTrue(len(data.x) == 66)
-        self.assertTrue(len(data.x) == len(data.y))
-        self.assertTrue(data.dy[10] == 0.20721350111248701)
-        self.assertTrue(data.y[10] == 24.193889608153476)
-        self.assertTrue(data.x[10] == 0.008981127988654792)
+        self.assertEqual(len(data.q_data), 150*150)
+        self.assertEqual(len(data.q_data), len(data.data))
+        self.assertAlmostEqual(data.err_data[10], 0.186723989418)
+        self.assertAlmostEqual(data.data[10], 0.465181)
+        self.assertAlmostEqual(data.qx_data[10], -0.129)
+        self.assertAlmostEqual(data.qy_data[10], -0.149)
 
     def _check_example_data(self, data):
-        self.assertTrue(data.title == "")
-        self.assertTrue(data.x.size == 100)
-        self.assertTrue(data._xunit == "A^{-1}")
-        self.assertTrue(data._yunit == "cm^{-1}")
-        self.assertTrue(data.y.size == 100)
+        self.assertEqual(data.title, "")
+        self.assertEqual(data.x.size, 100)
+        self.assertEqual(data._xunit, "A^{-1}")
+        self.assertEqual(data._yunit, "cm^{-1}")
+        self.assertEqual(data.y.size, 100)
         self.assertAlmostEqual(data.y[40], 0.952749011516985)
         self.assertAlmostEqual(data.x[40], 0.3834415188257777)
Index: test/sasdataloader/test/utest_red2d_reader.py
===================================================================
--- test/sasdataloader/test/utest_red2d_reader.py	(revision f53d684ed4a54de3601e5f4bc601f78376d98e83)
+++ test/sasdataloader/test/utest_red2d_reader.py	(revision fc51d06ca61c96f09100f834da5f2bd421f461f7)
@@ -31,6 +31,6 @@
         self.assertEqual(f.qx_data[0],-0.03573497)
         self.assertEqual(f.qx_data[36863],0.2908819)
-        self.assertEqual(f.Q_unit, '1/A')
-        self.assertEqual(f.I_unit, '1/cm')
+        self.assertEqual(f.Q_unit, 'A^{-1}')
+        self.assertEqual(f.I_unit, 'cm^{-1}')
 
         self.assertEqual(f.meta_data['loader'],"IGOR/DAT 2D Q_map")
Index: test/sasdataloader/test/utest_sesans.py
===================================================================
--- test/sasdataloader/test/utest_sesans.py	(revision f53d684ed4a54de3601e5f4bc601f78376d98e83)
+++ test/sasdataloader/test/utest_sesans.py	(revision f4e2f22f114f61e70b4756a304d744184be4ab99)
@@ -25,5 +25,6 @@
             Test .SES in the full loader to make sure that the file type is correctly accepted
         """
-        file = Loader().load(find("sesans_examples/sphere2micron.ses"))
+        file = Loader().load(find("sesans_examples" + os.sep +
+                                  "sphere2micron.ses"))
         f = file[0]
         # self.assertEqual(f, 5)
@@ -44,5 +45,5 @@
             Test .SES loading on a TOF dataset
         """
-        file = self.loader(find("sesans_examples/sphere_isis.ses"))
+        file = self.loader(find("sesans_examples" + os.sep + "sphere_isis.ses"))
         f = file[0]
         self.assertEqual(len(file), 1)
@@ -62,5 +63,5 @@
             FileContentsException,
             self.loader,
-            find("sesans_examples/sesans_no_data.ses"))
+            find("sesans_examples" + os.sep + "sesans_no_data.ses"))
 
     def test_sesans_no_spin_echo_unit(self):
@@ -71,5 +72,5 @@
             FileContentsException,
             self.loader,
-            find("sesans_examples/no_spin_echo_unit.ses"))
+            find("sesans_examples" + os.sep + "no_spin_echo_unit.ses"))
 
     def test_sesans_future_version(self):
@@ -80,5 +81,5 @@
             FileContentsException,
             self.loader,
-            find("sesans_examples/next_gen.ses"))
+            find("sesans_examples" + os.sep + "next_gen.ses"))
 
     def test_sesans_mandatory_headers(self):
@@ -89,5 +90,5 @@
             FileContentsException,
             self.loader,
-            find("sesans_examples/no_wavelength.ses"))
+            find("sesans_examples" + os.sep + "no_wavelength.ses"))
 
     def test_sesans_columns_match_headers(self):
@@ -98,5 +99,5 @@
             FileContentsException,
             self.loader,
-            find("sesans_examples/too_many_headers.ses"))
+            find("sesans_examples" + os.sep + "too_many_headers.ses"))
 
 if __name__ == "__main__":
