Index: doc/Makefile
===================================================================
--- doc/Makefile	(revision 7bb290c023a5380c0dbdd211a4aec8925839e3da)
+++ doc/Makefile	(revision 63776d3ac756a8c626dc0871fbe9eb1b062fc82f)
@@ -131,4 +131,5 @@
 pdf: latex
 	$(MAKE) -C _build/latex all-pdf
+	$(COPY) _build/latex/SASModels.pdf _build/html
 
 changes:
Index: doc/genmodel.py
===================================================================
--- doc/genmodel.py	(revision 91c5fdc1e57978ebef854d27add589c392a93f3a)
+++ doc/genmodel.py	(revision 70bbb740071fe0e5f444dcd206020bb72862edec)
@@ -1,5 +1,10 @@
-import sys, os
+import sys, os, math, re
+import numpy as np
+import matplotlib.pyplot as plt
 sys.path.insert(0, os.path.abspath('..'))
 from sasmodels import generate, core
+from sasmodels.direct_model import DirectModel
+from sasmodels.data import empty_data1D, empty_data2D
+
 
 # Convert ../sasmodels/models/name.py to name
@@ -8,3 +13,94 @@
 # Load the doc string from the module definition file and store it in rst
 docstr = generate.make_doc(core.load_model_info(model_name))
+    
+# Generate automatically plot of the model and add it to rst documentation
+
+info = core.load_model_info(model_name)
+
+# Calculate 1D curve for default parameters
+pars = dict((p[0], p[2]) for p in info['parameters'])
+
+# Plotting ranges and options
+opts = {
+        'xscale'    : 'log',
+        'yscale'    : 'log' if not info['structure_factor'] else 'linear',
+        'qmin'      : 0.005,
+        'qmax'      : 1.0,
+        'nq'        : 1000,
+        'nq2d'      : 100,
+}
+
+qmin, qmax, nq = opts['qmin'], opts['qmax'], opts['nq']
+qmin = math.log10(qmin)
+qmax = math.log10(qmax)
+q = np.logspace(qmin, qmax, nq)
+data = empty_data1D(q)
+model = core.load_model(model_name)
+calculator = DirectModel(data, model)
+Iq1D = calculator()
+
+# TO DO: Generation of 2D plots 
+# Problem in sasmodels.direct_model._calc_theory
+# There self._kernel.q_input.nq  gets a value of 0 in the 2D case
+# and returns a 0 numpy array (it does not call the C code)
+
+# If 2D model, compute 2D image
+#if info['has_2d'] != []:
+#    qmax, nq2d = opts['qmax'], opts['nq2d']
+#    data2d = empty_data2D(np.linspace(-qmax, qmax, nq2d), resolution=0.0) 
+#    #model = core.load_model(model_name)
+#    calculator = DirectModel(data2d, model)
+#    Iq2D = calculator()
+
+# Generate image (comment IF for 1D/2D for the moment) and generate only 1D
+#if info['has_2d'] == []:
+#    fig = plt.figure()
+#    ax = fig.add_subplot(1,1,1)
+#    ax.plot(q, Iq1D, color='blue', lw=2, label=model_name)
+#    ax.set_xlabel(r'$Q \/(\AA^{-1})$')
+#    ax.set_xscale(opts['xscale'])   
+#    ax.set_ylabel(r'$I(Q) \/(\mathrm{cm}^{-1})$')
+#    ax.set_yscale(opts['yscale'])  
+#    ax.legend()
+#else:
+#    # need figure with 1D + 2D
+#    pass
+fig = plt.figure()
+ax = fig.add_subplot(1,1,1)
+ax.plot(q, Iq1D, color='blue', lw=2, label=model_name)
+ax.set_xlabel(r'$Q \/(\AA^{-1})$')
+ax.set_xscale(opts['xscale'])   
+ax.set_ylabel(r'$I(Q) \/(\mathrm{cm}^{-1})$')
+ax.set_yscale(opts['yscale'])  
+ax.legend()
+ 
+
+# Save image in model/img
+figname = model_name + '_autogenfig.png'
+filename = os.path.join('model', 'img', figname)
+plt.savefig(filename)
+
+# Auto caption for figure
+captionstr = '\n'
+captionstr += '.. figure:: img/' + model_name + '_autogenfig.png\n'
+captionstr += '\n'
+#if info['has_2d'] == []:
+#    captionstr += '    1D plot corresponding to the default parameters of the model.\n'
+#else:
+#    captionstr += '    1D and 2D plots corresponding to the default parameters of the model.\n'
+captionstr += '    1D plot corresponding to the default parameters of the model.\n'
+captionstr += '\n'
+
+# Add figure reference and caption to documentation (at end, before References)
+pattern = '\*\*REFERENCE'
+m = re.search(pattern, docstr.upper())
+
+if m:
+    docstr1 = docstr[:m.start()]
+    docstr2 = docstr[m.start():]
+    docstr = docstr1 + captionstr + docstr2
+else:
+    print 'References NOT FOUND for model: ', model_name
+    docstr = docstr + captionstr
+
 open(sys.argv[2],'w').write(docstr)
Index: sasmodels/bumps_model.py
===================================================================
--- sasmodels/bumps_model.py	(revision 190fc2b167d3d89ca9c3b7d3128bdf8bde9f67d0)
+++ sasmodels/bumps_model.py	(revision c5dadbbaf797cd12844168a3697683ea6cf1c964)
@@ -83,10 +83,9 @@
     pars = {}
     for p in model_info['parameters']:
-        name, default, limits = p[0], p[2], p[3]
-        value = kwargs.pop(name, default)
-        pars[name] = Parameter.default(value, name=name, limits=limits)
+        value = kwargs.pop(p.name, p.default)
+        pars[p.name] = Parameter.default(value, name=p.name, limits=p.limits)
     for name in model_info['partype']['pd-2d']:
         for xpart, xdefault, xlimits in [
-                ('_pd', 0., limits),
+                ('_pd', 0., pars[name].limits),
                 ('_pd_n', 35., (0, 1000)),
                 ('_pd_nsigma', 3., (0, 10)),
Index: sasmodels/compare.py
===================================================================
--- sasmodels/compare.py	(revision 91c5fdc1e57978ebef854d27add589c392a93f3a)
+++ sasmodels/compare.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -681,13 +681,13 @@
     """
     # Get the default values for the parameters
-    pars = dict((p[0], p[2]) for p in model_info['parameters'])
+    pars = dict((p.name, p.default) for p in model_info['parameters'])
 
     # Fill in default values for the polydispersity parameters
     for p in model_info['parameters']:
-        if p[4] in ('volume', 'orientation'):
-            pars[p[0]+'_pd'] = 0.0
-            pars[p[0]+'_pd_n'] = 0
-            pars[p[0]+'_pd_nsigma'] = 3.0
-            pars[p[0]+'_pd_type'] = "gaussian"
+        if p.type in ('volume', 'orientation'):
+            pars[p.name+'_pd'] = 0.0
+            pars[p.name+'_pd_n'] = 0
+            pars[p.name+'_pd_nsigma'] = 3.0
+            pars[p.name+'_pd_type'] = "gaussian"
 
     # Plug in values given in demo
@@ -833,4 +833,5 @@
         pars = suppress_pd(pars)
     pars.update(presets)  # set value after random to control value
+    #import pprint; pprint.pprint(model_info)
     constrain_pars(model_info, pars)
     constrain_new_to_old(model_info, pars)
Index: sasmodels/generate.py
===================================================================
--- sasmodels/generate.py	(revision 2f0c07deb2cb7a8c0c93476fbf1e0ffbe6c278cb)
+++ sasmodels/generate.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -80,6 +80,6 @@
     is selected, or when an initial value is not otherwise specified.
 
-    [*lb*, *ub*] are the hard limits on the parameter value, used to limit
-    the polydispersity density function.  In the fit, the parameter limits
+    *limits = [lb, ub]* are the hard limits on the parameter value, used to
+    limit the polydispersity density function.  In the fit, the parameter limits
     given to the fit are the limits  on the central value of the parameter.
     If there is polydispersity, it will evaluate parameter values outside
@@ -216,6 +216,10 @@
 import re
 import string
+from collections import namedtuple
 
 import numpy as np
+
+PARAMETER_FIELDS = ['name', 'units', 'default', 'limits', 'type', 'description']
+Parameter = namedtuple('Parameter', PARAMETER_FIELDS)
 
 #TODO: determine which functions are useful outside of generate
@@ -293,7 +297,7 @@
     """
     column_widths = [
-        max(len(p[0]) for p in pars),
-        max(len(p[-1]) for p in pars),
-        max(len(format_units(p[1])) for p in pars),
+        max(len(p.name) for p in pars),
+        max(len(p.description) for p in pars),
+        max(len(format_units(p.units)) for p in pars),
         PARTABLE_VALUE_WIDTH,
         ]
@@ -310,8 +314,8 @@
     for p in pars:
         lines.append(" ".join([
-            "%-*s" % (column_widths[0], p[0]),
-            "%-*s" % (column_widths[1], p[-1]),
-            "%-*s" % (column_widths[2], format_units(p[1])),
-            "%*g" % (column_widths[3], p[2]),
+            "%-*s" % (column_widths[0], p.name),
+            "%-*s" % (column_widths[1], p.description),
+            "%-*s" % (column_widths[2], format_units(p.units)),
+            "%*g" % (column_widths[3], p.default),
             ]))
     lines.append(sep)
@@ -469,13 +473,13 @@
     fixed_2d = partype['fixed-1d']
 
-    iq_parameters = [p[0]
+    iq_parameters = [p.name
                      for p in model_info['parameters'][2:]  # skip scale, background
-                     if p[0] in set(fixed_1d + pd_1d)]
-    iqxy_parameters = [p[0]
+                     if p.name in set(fixed_1d + pd_1d)]
+    iqxy_parameters = [p.name
                        for p in model_info['parameters'][2:]  # skip scale, background
-                       if p[0] in set(fixed_2d + pd_2d)]
-    volume_parameters = [p[0]
+                       if p.name in set(fixed_2d + pd_2d)]
+    volume_parameters = [p.name
                          for p in model_info['parameters']
-                         if p[4] == 'volume']
+                         if p.type == 'volume']
 
     # Fill in defintions for volume parameters
@@ -606,19 +610,18 @@
 
     for p in pars:
-        name, ptype = p[0], p[4]
-        if ptype == 'volume':
-            partype['pd-1d'].append(name)
-            partype['pd-2d'].append(name)
-            partype['pd-rel'].add(name)
-        elif ptype == 'magnetic':
-            partype['fixed-2d'].append(name)
-        elif ptype == 'orientation':
-            partype['pd-2d'].append(name)
-        elif ptype == '':
-            partype['fixed-1d'].append(name)
-            partype['fixed-2d'].append(name)
+        if p.type == 'volume':
+            partype['pd-1d'].append(p.name)
+            partype['pd-2d'].append(p.name)
+            partype['pd-rel'].add(p.name)
+        elif p.type == 'magnetic':
+            partype['fixed-2d'].append(p.name)
+        elif p.type == 'orientation':
+            partype['pd-2d'].append(p.name)
+        elif p.type == '':
+            partype['fixed-1d'].append(p.name)
+            partype['fixed-2d'].append(p.name)
         else:
-            raise ValueError("unknown parameter type %r" % ptype)
-        partype[ptype].append(name)
+            raise ValueError("unknown parameter type %r" % p.type)
+        partype[p.type].append(p.name)
 
     return partype
@@ -628,9 +631,12 @@
     Process parameter block, precalculating parameter details.
     """
+    # convert parameters into named tuples
+    pars = [Parameter(*p) for p in model_info['parameters']]
     # Fill in the derived attributes
-    partype = categorize_parameters(model_info['parameters'])
-    model_info['limits'] = dict((p[0], p[3]) for p in model_info['parameters'])
+    model_info['parameters'] = pars
+    partype = categorize_parameters(pars)
+    model_info['limits'] = dict((p.name, p.limits) for p in pars)
     model_info['partype'] = partype
-    model_info['defaults'] = dict((p[0], p[2]) for p in model_info['parameters'])
+    model_info['defaults'] = dict((p.name, p.default) for p in pars)
     if model_info.get('demo', None) is None:
         model_info['demo'] = model_info['defaults']
@@ -649,4 +655,5 @@
     * *id* is the id of the kernel
     * *name* is the display name of the kernel
+    * *filename* is the full path to the module defining the file (if any)
     * *title* is a short description of the kernel
     * *description* is a long description of the kernel (this doesn't seem
Index: sasmodels/kernelpy.py
===================================================================
--- sasmodels/kernelpy.py	(revision 17bbadde9de73711781f748816b06e6956dc8cfa)
+++ sasmodels/kernelpy.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -111,5 +111,5 @@
 
         # First two fixed pars are scale and background
-        pars = [p[0] for p in model_info['parameters'][2:]]
+        pars = [p.name for p in model_info['parameters'][2:]]
         offset = len(self.q_input.q_vectors)
         self.args = self.q_input.q_vectors + [None] * len(pars)
Index: sasmodels/list_pars.py
===================================================================
--- sasmodels/list_pars.py	(revision 17bbadde9de73711781f748816b06e6956dc8cfa)
+++ sasmodels/list_pars.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -26,7 +26,6 @@
         model_info = load_model_info(name)
         for p in model_info['parameters']:
-            pname = p[0]
-            partable.setdefault(pname, [])
-            partable[pname].append(name)
+            partable.setdefault(p.name, [])
+            partable[p.name].append(name)
     return partable
 
Index: sasmodels/model_test.py
===================================================================
--- sasmodels/model_test.py	(revision 17bbadde9de73711781f748816b06e6956dc8cfa)
+++ sasmodels/model_test.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -251,5 +251,6 @@
   python -m sasmodels.model_test [-v] [opencl|dll] model1 model2 ...
 
-If -v is included on the
+If -v is included on the command line, then use verboe output.
+
 If neither opencl nor dll is specified, then models will be tested with
 both opencl and dll; the compute target is ignored for pure python models.
Index: sasmodels/models/be_polyelectrolyte.py
===================================================================
--- sasmodels/models/be_polyelectrolyte.py	(revision 2f0c07deb2cb7a8c0c93476fbf1e0ffbe6c278cb)
+++ sasmodels/models/be_polyelectrolyte.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -170,4 +170,5 @@
       'ionization_degree':      2.0,
       'polymer_concentration': 10.0,
+      'background':             0.0,
      }, 0.1, -3.75693800588],
 
@@ -189,4 +190,5 @@
       'ionization_degree':     0.5,
       'polymer_concentration': 0.1,
+      'background':             0.0,
      }, 200., 1.80664667511e-06],
     ]
Index: sasmodels/models/core_shell_parallelepiped.py
===================================================================
--- sasmodels/models/core_shell_parallelepiped.py	(revision 2f0c07deb2cb7a8c0c93476fbf1e0ffbe6c278cb)
+++ sasmodels/models/core_shell_parallelepiped.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -186,8 +186,8 @@
 
 qx, qy = 0.2 * np.cos(2.5), 0.2 * np.sin(2.5)
-tests = [[{}, 0.2, 0.532149288477],
-         [{}, [0.2], [0.532149288477]],
-         [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.031102135569],
-         [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.031102135569]],
+tests = [[{}, 0.2, 0.533149288477],
+         [{}, [0.2], [0.533149288477]],
+         [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.032102135569],
+         [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.032102135569]],
         ]
 del qx, qy  # not necessary to delete, but cleaner
Index: sasmodels/models/correlation_length.py
===================================================================
--- sasmodels/models/correlation_length.py	(revision 3e6c5c1168c56a700f8cd12b4025aa6a9764fddf)
+++ sasmodels/models/correlation_length.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -84,4 +84,4 @@
 
 tests = [[{}, 0.001, 1009.98],
-         [{}, 0.150141, 0.174645],
-         [{}, 0.442528, 0.0203957]]
+         [{}, 0.150141, 0.175645],
+         [{}, 0.442528, 0.0213957]]
Index: sasmodels/models/cylinder.py
===================================================================
--- sasmodels/models/cylinder.py	(revision 2f0c07deb2cb7a8c0c93476fbf1e0ffbe6c278cb)
+++ sasmodels/models/cylinder.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -167,8 +167,8 @@
 
 qx, qy = 0.2 * np.cos(2.5), 0.2 * np.sin(2.5)
-tests = [[{}, 0.2, 0.041761386790780453],
-         [{}, [0.2], [0.041761386790780453]],
-         [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.03414647218513852],
-         [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.03414647218513852]],
+tests = [[{}, 0.2, 0.042761386790780453],
+         [{}, [0.2], [0.042761386790780453]],
+         [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.03514647218513852],
+         [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.03514647218513852]],
         ]
 del qx, qy  # not necessary to delete, but cleaner
Index: sasmodels/models/gauss_lorentz_gel.py
===================================================================
--- sasmodels/models/gauss_lorentz_gel.py	(revision 168052c5791506d7dfad00173f5636fc5701ad11)
+++ sasmodels/models/gauss_lorentz_gel.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -132,5 +132,5 @@
       'lorentz_scale_factor': 50.0,
       'dynamic_cor_length':   20.0,
-     }, 0.001, 149.481],
+     }, 0.001, 149.482],
 
     [{'gauss_scale_factor':  100.0,
@@ -138,5 +138,5 @@
       'lorentz_scale_factor': 50.0,
       'dynamic_cor_length':   20.0,
-     }, 0.105363, 9.1903],
+     }, 0.105363, 9.1913],
 
     [{'gauss_scale_factor':  100.0,
@@ -144,5 +144,5 @@
       'lorentz_scale_factor': 50.0,
       'dynamic_cor_length':   20.0,
-     }, 0.441623, 0.632811],
+     }, 0.441623, 0.633811],
 
     # Additional tests with larger range of parameters
@@ -151,5 +151,5 @@
       'lorentz_scale_factor': 3.0,
       'dynamic_cor_length':   1.0,
-     }, 0.1, 2.9702970297],
+     }, 0.1, 2.9712970297],
 
     [{'gauss_scale_factor':  10.0,
@@ -158,5 +158,5 @@
       'dynamic_cor_length':   1.0,
       'background':         100.0
-     }, 5.0, 100.115384615],
+     }, 5.0, 100.116384615],
 
     [{'gauss_scale_factor':  10.0,
@@ -164,4 +164,5 @@
       'lorentz_scale_factor': 3.0,
       'dynamic_cor_length':   1.0,
+      'background':           0.0,
      }, 200., 7.49981250469e-05],
     ]
Index: sasmodels/models/gel_fit.py
===================================================================
--- sasmodels/models/gel_fit.py	(revision 5111921153c056b59ff03411e4b7b028d238ae26)
+++ sasmodels/models/gel_fit.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -92,5 +92,6 @@
            'gyration_radius': 10.0,
            'fractal_exp': 10.0,
-           'cor_length': 20.0
+           'cor_length': 20.0,
+           'background': 0.0,
           }, 0.1, 0.716532],
 
Index: sasmodels/models/guinier.py
===================================================================
--- sasmodels/models/guinier.py	(revision 723cebed4612ad396b30ca46c6f1e5e801142cba)
+++ sasmodels/models/guinier.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -57,3 +57,3 @@
 
 # parameters for unit tests
-tests = [[{'rg' : 31.5}, 0.005, 0.991756]]
+tests = [[{'rg' : 31.5}, 0.005, 0.992756]]
Index: sasmodels/models/hardsphere.py
===================================================================
--- sasmodels/models/hardsphere.py	(revision 8e45182d210b32e434250ff0125f4640e9a1dbf8)
+++ sasmodels/models/hardsphere.py	(revision d529d93bd045e44913320de5e1c8db47f680e037)
@@ -3,6 +3,19 @@
 spherical particles interacting through hard sphere (excluded volume)
 interactions.
+May be a reasonable approximation for other shapes of particles that 
+freely rotate, and for moderately polydisperse systems. Though strictly 
+the maths needs to be modified (no \Beta(Q) correction yet in sasview).
 
-The calculation uses the Percus-Yevick closure where the interparticle
+radius_effective is the effective hard sphere radius.
+volfraction is the volume fraction occupied by the spheres.
+
+In sasview the effective radius may be calculated from the parameters
+used in the form factor $P(q)$ that this $S(q)$ is combined with.
+
+For numerical stability the computation uses a Taylor series expansion 
+at very small $qR$, there may be a very minor glitch at the transition point
+in some circumstances.
+
+The S(Q) uses the Percus-Yevick closure where the interparticle
 potential is
 
@@ -44,5 +57,5 @@
         systems. Though strictly the maths needs to be modified -
     which sasview does not do yet.
-    effect_radius is the hard sphere radius
+    radius_effective is the hard sphere radius
     volfraction is the volume fraction occupied by the spheres.
 """
@@ -51,5 +64,5 @@
 
 #             ["name", "units", default, [lower, upper], "type","description"],
-parameters = [["effect_radius", "Ang", 50.0, [0, inf], "volume",
+parameters = [["radius_effective", "Ang", 50.0, [0, inf], "volume",
                "effective radius of hard sphere"],
               ["volfraction", "", 0.2, [0, 0.74], "",
@@ -66,5 +79,5 @@
       double D,A,B,G,X,X2,X4,S,C,FF,HARDSPH;
 
-      if(fabs(effect_radius) < 1.E-12) {
+      if(fabs(radius_effective) < 1.E-12) {
                HARDSPH=1.0;
                return(HARDSPH);
@@ -75,5 +88,5 @@
       A= (1.+2.*volfraction)*D;
       A *=A;
-      X=fabs(q*effect_radius*2.0);
+      X=fabs(q*radius_effective*2.0);
 
       if(X < 5.E-06) {
@@ -138,11 +151,11 @@
 # VR defaults to 1.0
 
-demo = dict(effect_radius=200, volfraction=0.2, effect_radius_pd=0.1, effect_radius_pd_n=40)
+demo = dict(radius_effective=200, volfraction=0.2, radius_effective_pd=0.1, radius_effective_pd_n=40)
 oldname = 'HardsphereStructure'
-oldpars = dict()
+oldpars = dict(radius_effective="effect_radius",radius_effective_pd="effect_radius_pd",radius_effective_pd_n="effect_radius_pd_n")
 # Q=0.001 is in the Taylor series, low Q part, so add Q=0.1, assuming double precision sasview is correct
 tests = [
-        [ {'scale': 1.0, 'background' : 0.0, 'effect_radius' : 50.0, 'volfraction' : 0.2,
-           'effect_radius_pd' : 0}, [0.001,0.1], [0.209128,0.930587]]
+        [ {'scale': 1.0, 'background' : 0.0, 'radius_effective' : 50.0, 'volfraction' : 0.2,
+           'radius_effective_pd' : 0}, [0.001,0.1], [0.209128,0.930587]]
         ]
-
+# ADDED by: RKH  ON: 16Mar2016  using equations from FISH as better than orig sasview, see notes above. Added Taylor expansions at small Q, 
Index: sasmodels/models/hayter_msa.py
===================================================================
--- sasmodels/models/hayter_msa.py	(revision 348557ad6267dc6c27f1b0a9f23dc61b4aae3715)
+++ sasmodels/models/hayter_msa.py	(revision d529d93bd045e44913320de5e1c8db47f680e037)
@@ -9,5 +9,5 @@
 
 **This routine only works for charged particles**. If the charge is set to
-zero the routine will self-destruct! For non-charged particles use a hard
+zero the routine may self-destruct! For non-charged particles use a hard
 sphere potential.
 
@@ -15,5 +15,14 @@
 which in turn is used to compute the Debye screening length. At present
 there is no provision for entering the ionic strength directly nor for use
-of any multivalent salts. The counterions are also assumed to be monovalent.
+of any multivalent salts, though it should be possible to simulate the effect
+of this by increasing the salt concentration. The counterions are also assumed to 
+be monovalent.
+
+In sasview the effective radius may be calculated from the parameters
+used in the form factor $P(q)$ that this $S(q)$ is combined with.
+
+The computation uses a Taylor series expansion at very small rescaled $qR$, to 
+avoid some serious rounding error issues, this may result in a minor artefact 
+in the transition region under some circumstances.
 
 For 2D data, the scattering intensity is calculated in the same way as 1D,
@@ -24,7 +33,4 @@
     q = \sqrt{q_x^2 + q_y^2}
 
-.. figure:: img/HayterMSAsq_227.jpg
-
-    1D plot using the default values (in linear scale).
 
 References
@@ -35,6 +41,11 @@
 J P Hansen and J B Hayter, *Molecular Physics*, 46 (1982) 651-656
 """
+from numpy import inf
 
-#  dp[0] = 2.0*effect_radius();
+category = "structure-factor"
+structure_factor = True
+single = False  # double precision only!
+
+#  dp[0] = 2.0*radius_effective();
 #  dp[1] = fabs(charge());
 #  dp[2] = volfraction();
@@ -43,33 +54,32 @@
 #  dp[5] = dielectconst();
 
-from numpy import inf
 
-source = ["hayter_msa_kernel.c"]
+
 
 name = "hayter_msa"
-title = "Hayter-Penfold MSA charged sphere interparticle S(Q) structure factor"
+title = "Hayter-Penfold rescaled MSA, charged sphere, interparticle S(Q) structure factor"
 description = """\
-    [Hayter-Penfold MSA charged sphere interparticle S(Q) structure factor]
+    [Hayter-Penfold RMSA charged sphere interparticle S(Q) structure factor]
         Interparticle structure factor S(Q)for a charged hard spheres.
         Routine takes absolute value of charge, use HardSphere if charge
         goes to zero.
-        In sasview the effective radius will be calculated from the
-        parameters used in P(Q).
+        In sasview the effective radius and volume fraction may be calculated 
+        from the parameters used in P(Q).
 """
-single = False  # double precision only!
+
 
 # pylint: disable=bad-whitespace, line-too-long
 #             [ "name", "units", default, [lower, upper], "type", "description" ],
 parameters = [
-    ["effect_radius", "Ang", 20.75,   [0, inf],    "volume", "effective radius of hard sphere"],
+    ["radius_effective", "Ang", 20.75,   [0, inf],    "volume", "effective radius of charged sphere"],
     ["charge",        "e",   19.0,    [0, inf],    "", "charge on sphere (in electrons)"],
-    ["volfraction",   "",     0.0192, [0, 0.74],   "", "volume fraction of spheres"],
+    ["volfraction",   "None",     0.0192, [0, 0.74],   "", "volume fraction of spheres"],
     ["temperature",   "K",  318.16,   [0, inf],    "", "temperature, in Kelvin, for Debye length calculation"],
-    ["saltconc",      "M",    0.0,    [-inf, inf], "", "conc of salt, 1:1 electolyte, for Debye length"],
-    ["dielectconst",  "",    71.08,   [-inf, inf], "", "dielectric constant of solvent (default water), for Debye length"],
+    ["saltconc",      "M",    0.0,    [-inf, inf], "", "conc of salt, moles/litre, 1:1 electolyte, for Debye length"],
+    ["dielectconst",  "None",    71.08,   [-inf, inf], "", "dielectric constant (relative permittivity) of solvent, default water, for Debye length"]
     ]
 # pylint: enable=bad-whitespace, line-too-long
-category = "structure-factor"
 
+source = ["hayter_msa_kernel.c"]
 # No volume normalization despite having a volume parameter
 # This should perhaps be volume normalized?
@@ -85,10 +95,12 @@
 
 oldname = 'HayterMSAStructure'
-oldpars = dict()
+#oldpars = dict(effect_radius="radius_effective",effect_radius_pd="radius_effective_pd",effect_radius_pd_n="radius_effective_pd_n")
+oldpars = dict(radius_effective="effect_radius",radius_effective_pd="effect_radius_pd",radius_effective_pd_n="effect_radius_pd_n")
+#oldpars = dict( )
 # default parameter set,  use  compare.sh -midQ -linear
 # note the calculation varies in different limiting cases so a wide range of
 # parameters will be required for a thorough test!
 # odd that the default st has saltconc zero
-demo = dict(effect_radius=20.75,
+demo = dict(radius_effective=20.75,
             charge=19.0,
             volfraction=0.0192,
@@ -96,6 +108,6 @@
             saltconc=0.05,
             dielectconst=71.08,
-            effect_radius_pd=0.1,
-            effect_radius_pd_n=40)
+            radius_effective_pd=0.1,
+            radius_effective_pd_n=40)
 #
 # attempt to use same values as old sasview unit test at Q=.001 was 0.0712928, 
@@ -104,5 +116,5 @@
     [{'scale': 1.0,
       'background': 0.0,
-      'effect_radius': 20.75,
+      'radius_effective': 20.75,
       'charge': 19.0,
       'volfraction': 0.0192,
@@ -110,9 +122,9 @@
       'saltconc': 0,
       'dielectconst': 78.0,
-      'effect_radius_pd': 0},
+      'radius_effective_pd': 0},
      [0.00001,0.0010,0.01,0.075], [0.0711646,0.0712928,0.0847006,1.07150]],
     [{'scale': 1.0,
       'background': 0.0,
-      'effect_radius': 20.75,
+      'radius_effective': 20.75,
       'charge': 19.0,
       'volfraction': 0.0192,
@@ -120,7 +132,7 @@
       'saltconc': 0.05,
       'dielectconst': 78.0,
-      'effect_radius_pd': 0.1,
-      'effect_radius_pd_n': 40},
+      'radius_effective_pd': 0.1,
+      'radius_effective_pd_n': 40},
      [0.00001,0.0010,0.01,0.075], [0.450272,0.450420,0.465116,1.039625]]
     ]
-
+# ADDED by:  RKH  ON: 16Mar2016 converted from sasview, new Taylor expansion at smallest rescaled Q
Index: sasmodels/models/hayter_msa_kernel.c
===================================================================
--- sasmodels/models/hayter_msa_kernel.c	(revision 348557ad6267dc6c27f1b0a9f23dc61b4aae3715)
+++ sasmodels/models/hayter_msa_kernel.c	(revision d529d93bd045e44913320de5e1c8db47f680e037)
@@ -3,5 +3,5 @@
 // C99 needs declarations of routines here
 double Iq(double QQ,
-      double effect_radius, double zz, double VolFrac, double Temp, double csalt, double dialec);
+      double radius_effective, double zz, double VolFrac, double Temp, double csalt, double dialec);
 int
 sqcoef(int ir, double gMSAWave[]);
@@ -14,5 +14,5 @@
   
 double Iq(double QQ,
-      double effect_radius, double zz, double VolFrac, double Temp, double csalt, double dialec)  
+      double radius_effective, double zz, double VolFrac, double Temp, double csalt, double dialec)  
 {
     double gMSAWave[17]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17};
@@ -28,5 +28,5 @@
 	pi = M_PI;
 
-	diam=2*effect_radius;		//in A
+	diam=2*radius_effective;		//in A
 
 						////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Index: sasmodels/models/hollow_rectangular_prism.py
===================================================================
--- sasmodels/models/hollow_rectangular_prism.py	(revision 5111921153c056b59ff03411e4b7b028d238ae26)
+++ sasmodels/models/hollow_rectangular_prism.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -158,6 +158,6 @@
                thickness='thickness', sld='sldPipe', solvent_sld='sldSolv')
 
-tests = [[{}, 0.2, 0.76587283098],
-         [{}, [0.2], [0.76587283098]],
+tests = [[{}, 0.2, 0.76687283098],
+         [{}, [0.2], [0.76687283098]],
         ]
 
Index: sasmodels/models/hollow_rectangular_prism_infinitely_thin_walls.py
===================================================================
--- sasmodels/models/hollow_rectangular_prism_infinitely_thin_walls.py	(revision deb7ee06caa9916d8c0504bdc15ffbc16df623f6)
+++ sasmodels/models/hollow_rectangular_prism_infinitely_thin_walls.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -137,6 +137,6 @@
                sld='sldPipe', solvent_sld='sldSolv')
 
-tests = [[{}, 0.2, 0.836719188592],
-         [{}, [0.2], [0.836719188592]],
+tests = [[{}, 0.2, 0.837719188592],
+         [{}, [0.2], [0.837719188592]],
         ]
 
Index: sasmodels/models/line.py
===================================================================
--- sasmodels/models/line.py	(revision fa8011eb0e6b527e15b594945876ee39b6a46dbd)
+++ sasmodels/models/line.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -80,28 +80,29 @@
     [{'intercept':   1.0,
       'slope': 1.0,
-     }, 1.0, 2.0],
+     }, 1.0, 2.001],
 
     [{'intercept':   1.0,
       'slope': 1.0,
-     }, 0.0, 1.0],
+     }, 0.0, 1.001],
 
     [{'intercept':   1.0,
       'slope': 1.0,
-     }, 0.4, 1.4],
+     }, 0.4, 1.401],
 
     [{'intercept':   1.0,
       'slope': 1.0,
-     }, 1.3, 2.3],
+     }, 1.3, 2.301],
 
     [{'intercept':   1.0,
       'slope': 1.0,
-     }, 0.5, 1.5],
+     }, 0.5, 1.501],
 
     [{'intercept':   1.0,
       'slope': 1.0,
-     }, [0.4, 0.5], [1.4, 1.5]],
+     }, [0.4, 0.5], [1.401, 1.501]],
 
     [{'intercept':   1.0,
       'slope': 1.0,
+      'background': 0.0,
      }, (1.3, 1.57), 5.911],
 ]
Index: sasmodels/models/lorentz.py
===================================================================
--- sasmodels/models/lorentz.py	(revision eb5901bce0a70fc35f2edf395a5b02199feab0cb)
+++ sasmodels/models/lorentz.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -64,3 +64,3 @@
 
 # parameters for unit tests
-tests = [[{'cor_length': 250}, 0.01, 0.137931]]
+tests = [[{'cor_length': 250}, 0.01, 0.138931]]
Index: sasmodels/models/mass_fractal.py
===================================================================
--- sasmodels/models/mass_fractal.py	(revision 168052c5791506d7dfad00173f5636fc5701ad11)
+++ sasmodels/models/mass_fractal.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -106,5 +106,5 @@
       'mass_dim':        1.9,
       'cutoff_length': 100.0,
-     }, 0.05, 279.59322],
+     }, 0.05, 279.59422],
 
     # Additional tests with larger range of parameters
@@ -112,5 +112,5 @@
       'mass_dim':      3.3,
       'cutoff_length': 1.0,
-     }, 0.5, 1.29016774904],
+     }, 0.5, 1.29116774904],
 
     [{'radius':        1.0,
@@ -124,4 +124,4 @@
       'cutoff_length': 1.0,
       'scale':        10.0,
-     }, 0.051, 11.6227966145],
+     }, 0.051, 11.6237966145],
     ]
Index: sasmodels/models/mass_surface_fractal.py
===================================================================
--- sasmodels/models/mass_surface_fractal.py	(revision 168052c5791506d7dfad00173f5636fc5701ad11)
+++ sasmodels/models/mass_surface_fractal.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -115,4 +115,5 @@
       'cluster_rg':   86.7,
       'primary_rg': 4000.0,
+      'background':    0.0,
      }, 0.05, 1.77537e-05],
 
@@ -122,5 +123,5 @@
       'cluster_rg':   90.0,
       'primary_rg': 4000.0,
-     }, 0.001, 0.18462699016],
+     }, 0.001, 0.18562699016],
 
     [{'mass_dim':      1.3,
@@ -136,4 +137,5 @@
       'primary_rg': 1000.0,
       'scale':        10.0,
+      'background':    0.0,
      }, 0.051, 0.000169548800377],
     ]
Index: sasmodels/models/mono_gauss_coil.py
===================================================================
--- sasmodels/models/mono_gauss_coil.py	(revision 4c05f4957956ed9d2a62699971feaa103fc1f7db)
+++ sasmodels/models/mono_gauss_coil.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -61,18 +61,18 @@
 
 # NB: Scale and Background are implicit parameters on every model
-def Iq(q, radius_gyration):
+def Iq(q, i_zero, radius_gyration):
     # pylint: disable = missing-docstring
-    z = (x * radius_gyration) * (x * radius_gyration)
-    if x == 0:
+    z = (q * radius_gyration) ** 2
+    if q == 0:
        inten = 1.0
     else:
        inten = i_zero * 2.0 * (exp(-z) + z - 1.0 ) / (z * z)
     return inten
-Iq.vectorized =  True  # Iq accepts an array of q values
+#Iq.vectorized = True # Iq accepts an array of q values
 
 def Iqxy(qx, qy, *args):
     # pylint: disable = missing-docstring
     return Iq(sqrt(qx ** 2 + qy ** 2), *args)
-Iqxy.vectorized =  True # Iqxy accepts an array of qx, qy values
+#Iqxy.vectorized = True # Iqxy accepts an array of qx, qy values
 
 demo =  dict(scale = 1.0,
Index: sasmodels/models/parallelepiped.py
===================================================================
--- sasmodels/models/parallelepiped.py	(revision 5111921153c056b59ff03411e4b7b028d238ae26)
+++ sasmodels/models/parallelepiped.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -233,8 +233,8 @@
 
 qx, qy = 0.2 * np.cos(2.5), 0.2 * np.sin(2.5)
-tests = [[{}, 0.2, 0.17658004974],
-         [{}, [0.2], [0.17658004974]],
-         [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.00460296014],
-         [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.00460296014]],
+tests = [[{}, 0.2, 0.17758004974],
+         [{}, [0.2], [0.17758004974]],
+         [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.00560296014],
+         [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.00560296014]],
         ]
 del qx, qy  # not necessary to delete, but cleaner
Index: sasmodels/models/poly_gauss_coil.py
===================================================================
--- sasmodels/models/poly_gauss_coil.py	(revision 4c05f4957956ed9d2a62699971feaa103fc1f7db)
+++ sasmodels/models/poly_gauss_coil.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -67,22 +67,22 @@
 
 # NB: Scale and Background are implicit parameters on every model
-def Iq(q, radius_gyration, polydispersity):
+def Iq(q, i_zero, radius_gyration, polydispersity):
     # pylint: disable = missing-docstring
-	u = polydispersity - 1.0
+    u = polydispersity - 1.0
     # TO DO
-	# should trap the case of polydispersity = 1 by switching to a taylor expansion
-	minusoneonu = -1.0 / u
-	z = ((x * radius_gyration) * (x * radius_gyration)) / (1.0 + 2.0 * u)
-	if x == 0:
-	   inten = i_zero * 1.0
-	else:
-	   inten = i_zero * 2.0 * (power((1.0 + u * z),minusoneonu) + z - 1.0 ) / ((1.0 + u) * (z * z))
-	return inten
-Iq.vectorized =  True  # Iq accepts an array of q values
+    # should trap the case of polydispersity = 1 by switching to a taylor expansion
+    minusoneonu = -1.0 / u
+    z = (q * radius_gyration) ** 2 / (1.0 + 2.0 * u)
+    if q == 0:
+        inten = i_zero * 1.0
+    else:
+        inten = i_zero * 2.0 * (power((1.0 + u * z),minusoneonu) + z - 1.0 ) / ((1.0 + u) * (z * z))
+    return inten
+#Iq.vectorized = True # Iq accepts an array of q values
 
 def Iqxy(qx, qy, *args):
     # pylint: disable = missing-docstring
     return Iq(sqrt(qx ** 2 + qy ** 2), *args)
-Iqxy.vectorized =  True # Iqxy accepts an array of qx, qy values
+#Iqxy.vectorized = True # Iqxy accepts an array of qx, qy values
 
 demo =  dict(scale = 1.0,
Index: sasmodels/models/polymer_excl_volume.py
===================================================================
--- sasmodels/models/polymer_excl_volume.py	(revision 168052c5791506d7dfad00173f5636fc5701ad11)
+++ sasmodels/models/polymer_excl_volume.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -168,10 +168,10 @@
 tests = [
     # Accuracy tests based on content in test/polyexclvol_default_igor.txt
-    [{'rg': 60, 'porod_exp': 3.0}, 0.001, 0.998801],
-    [{'rg': 60, 'porod_exp': 3.0}, 0.105363, 0.0162751],
-    [{'rg': 60, 'porod_exp': 3.0}, 0.665075, 6.56261e-05],
+    [{'rg': 60, 'porod_exp': 3.0}, 0.001, 0.999801],
+    [{'rg': 60, 'porod_exp': 3.0}, 0.105363, 0.0172751],
+    [{'rg': 60, 'porod_exp': 3.0, 'background': 0.0}, 0.665075, 6.56261e-05],
 
     # Additional tests with larger range of parameters
-    [{'rg': 10, 'porod_exp': 4.0}, 0.1, 0.723436675809],
+    [{'rg': 10, 'porod_exp': 4.0}, 0.1, 0.724436675809],
     [{'rg': 2.2, 'porod_exp': 22.0, 'background': 100.0}, 5.0, 100.0],
     [{'rg': 1.1, 'porod_exp': 1, 'background': 10.0, 'scale': 1.25},
Index: sasmodels/models/rectangular_prism.py
===================================================================
--- sasmodels/models/rectangular_prism.py	(revision deb7ee06caa9916d8c0504bdc15ffbc16df623f6)
+++ sasmodels/models/rectangular_prism.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -135,5 +135,5 @@
                sld='sldPipe', solvent_sld='sldSolv')
 
-tests = [[{}, 0.2, 0.374248406825],
-         [{}, [0.2], [0.374248406825]],
+tests = [[{}, 0.2, 0.375248406825],
+         [{}, [0.2], [0.375248406825]],
         ]
Index: sasmodels/models/sc_crystal.py
===================================================================
--- sasmodels/models/sc_crystal.py	(revision 5111921153c056b59ff03411e4b7b028d238ae26)
+++ sasmodels/models/sc_crystal.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -152,7 +152,7 @@
 tests = [
     # Accuracy tests based on content in test/utest_extra_models.py
-    [{}, 0.001, 10.3038],
-    [{}, 0.215268, 0.00714889],
-    [{}, (0.414467), 0.000313289]
+    [{}, 0.001, 10.3048],
+    [{}, 0.215268, 0.00814889],
+    [{}, (0.414467), 0.001313289]
     ]
 
Index: sasmodels/models/squarewell.py
===================================================================
--- sasmodels/models/squarewell.py	(revision 5111921153c056b59ff03411e4b7b028d238ae26)
+++ sasmodels/models/squarewell.py	(revision d529d93bd045e44913320de5e1c8db47f680e037)
@@ -8,7 +8,7 @@
 Positive well depths correspond to an attractive potential well. Negative well depths correspond to a potential
 "shoulder", which may or may not be physically reasonable. The stickyhardsphere model may be a better choice in
-some circumstances. Computed values may behave badly at extremely small Q.
+some circumstances. Computed values may behave badly at extremely small $qR$.
 
-The well width (*l*\ ) is defined as multiples of the particle diameter (2\*\ *R*\ )
+The well width (|lambda| ) is defined as multiples of the particle diameter (2\*\ *R*\ )
 
 The interaction potential is:
@@ -22,10 +22,12 @@
     U(r) = \begin{cases}
     \infty & r < 2R \\
-    -\epsilon , 2R \leq < 2R\lambda
-    0 & r \geq 2R
+    -\epsilon & 2R \leq r < 2R\lambda \\
+    0 & r \geq 2R\lambda
     \end{cases}
 
 where $r$ is the distance from the center of the sphere of a radius $R$.
 
+In sasview the effective radius may be calculated from the parameters
+used in the form factor $P(q)$ that this $S(q)$ is combined with.
 
 For 2D data: The 2D scattering intensity is calculated in the same way as 1D, where the *q* vector is defined as
@@ -35,9 +37,4 @@
     q = \sqrt{q_x^2 + q_y^2}
 
-.. comment::
-
-  .. figure:: img/squarewell_226.jpg
-
-    1D plot using the default values (in linear scale).*
 
 REFERENCE
@@ -59,4 +56,5 @@
 """
 category = "structure-factor"
+structure_factor = True
 
 #single = False
@@ -65,5 +63,5 @@
     #   [ "name", "units", default, [lower, upper], "type",
     #     "description" ],
-    ["effect_radius", "Ang", 50.0, [0, inf], "volume",
+    ["radius_effective", "Ang", 50.0, [0, inf], "volume",
      "effective radius of hard sphere"],
     ["volfraction", "", 0.04, [0, 0.08], "",
@@ -71,6 +69,6 @@
     ["welldepth", "kT", 1.5, [0.0, 1.5], "",
      "depth of well, epsilon"],
-    ["wellwidth", "diameters", 1.2, [0, inf], "",
-     "width of well in diameters (=2R) units"],
+    ["wellwidth", "diameters", 1.2, [1.0, inf], "",
+     "width of well in diameters (=2R) units, must be > 1"],
     ]
 
@@ -89,5 +87,5 @@
 	x= q;
 	
-	req = effect_radius;
+	req = radius_effective;
 	phis = volfraction;
 	edibkb = welldepth;
@@ -134,12 +132,12 @@
 
 oldname = 'SquareWellStructure'
-oldpars = dict()
-demo = dict(effect_radius=50, volfraction=0.04, welldepth=1.5,
-            wellwidth=1.2, effect_radius_pd=0, effect_radius_pd_n=0)
+oldpars = dict(radius_effective="effect_radius",radius_effective_pd="effect_radius_pd",radius_effective_pd_n="effect_radius_pd_n")
+demo = dict(radius_effective=50, volfraction=0.04, welldepth=1.5,
+            wellwidth=1.2, radius_effective_pd=0, radius_effective_pd_n=0)
 #
 tests = [
-        [ {'scale': 1.0, 'background' : 0.0, 'effect_radius' : 50.0, 'volfraction' : 0.04,'welldepth' : 1.5, 'wellwidth' : 1.2, 
-           'effect_radius_pd' : 0}, [0.001], [0.97665742]]
+        [ {'scale': 1.0, 'background' : 0.0, 'radius_effective' : 50.0, 'volfraction' : 0.04,'welldepth' : 1.5, 'wellwidth' : 1.2, 
+           'radius_effective_pd' : 0}, [0.001], [0.97665742]]
         ]
-# ADDED by: converting from sasview RKH  ON: 16Mar2016 - in progress
+# ADDED by: converting from sasview RKH  ON: 16Mar2016
 
Index: sasmodels/models/star_polymer.py
===================================================================
--- sasmodels/models/star_polymer.py	(revision 13ed84c3c71257d2df9c2ed4b4e98c0bfa4d7d69)
+++ sasmodels/models/star_polymer.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -76,5 +76,5 @@
 tests = [[{'radius2': 2.0,
            'arms':    3.3,
-          }, 0.5, 0.850646091108],
+          }, 0.5, 0.851646091108],
 
          [{'radius2':    1.0,
Index: sasmodels/models/stickyhardsphere.py
===================================================================
--- sasmodels/models/stickyhardsphere.py	(revision 8e45182d210b32e434250ff0125f4640e9a1dbf8)
+++ sasmodels/models/stickyhardsphere.py	(revision d529d93bd045e44913320de5e1c8db47f680e037)
@@ -49,5 +49,5 @@
 the optimization does not hit the constraints.
 
-In sasview the effective radius will be calculated from the parameters
+In sasview the effective radius may be calculated from the parameters
 used in the form factor $P(q)$ that this $S(q)$ is combined with.
 
Index: sasmodels/models/surface_fractal.py
===================================================================
--- sasmodels/models/surface_fractal.py	(revision 168052c5791506d7dfad00173f5636fc5701ad11)
+++ sasmodels/models/surface_fractal.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -106,5 +106,5 @@
       'surface_dim': 2.0,
       'cutoff_length': 500.0,
-     }, 0.05, 301428.65916],
+     }, 0.05, 301428.66016],
 
     # Additional tests with larger range of parameters
@@ -112,5 +112,5 @@
       'surface_dim': 1.0,
       'cutoff_length': 10.0,
-     }, 0.332070182643, 1125.00321004],
+     }, 0.332070182643, 1125.00421004],
 
     [{'radius': 3.5,
@@ -124,4 +124,4 @@
       'cutoff_length': 33.0,
       'scale': 0.1,
-     }, 0.51, 2.50020147004],
+     }, 0.51, 2.50120147004],
     ]
Index: sasmodels/models/teubner_strey.py
===================================================================
--- sasmodels/models/teubner_strey.py	(revision eb69cce00f0781ad8f3eec0eb5965a8576d815b5)
+++ sasmodels/models/teubner_strey.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -91,3 +91,3 @@
 oldpars = dict(a2='scale')
 
-tests = [[{}, 0.2, 0.144927536232]]
+tests = [[{}, 0.2, 0.145927536232]]
Index: sasmodels/models/vesicle.py
===================================================================
--- sasmodels/models/vesicle.py	(revision fa8011eb0e6b527e15b594945876ee39b6a46dbd)
+++ sasmodels/models/vesicle.py	(revision 6dd90c1d8aaff9b7299ee215555203db80eaa3a0)
@@ -130,7 +130,8 @@
 
 
-# NOTE: test results taken from values returned by SasView 3.1.2
-tests = [[{}, 0.0010005303255, 17139.8268799],
-         [{}, 0.200027832249, 0.130387268704],
+# NOTE: test results taken from values returned by SasView 3.1.2, with
+# 0.001 added for a non-zero default background.
+tests = [[{}, 0.0010005303255, 17139.8278799],
+         [{}, 0.200027832249, 0.131387268704],
          [{}, 'ER', 130.],
          [{}, 'VR', 0.54483386436],
Index: sasmodels/product.py
===================================================================
--- sasmodels/product.py	(revision 35b4c47271c19171252212163d34c16621a369ba)
+++ sasmodels/product.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -28,9 +28,9 @@
     s_id, s_name, s_pars = s_info['id'], s_info['name'], s_info['parameters']
     # We require models to start with scale and background
-    assert s_pars[SCALE][0] == 'scale'
-    assert s_pars[BACKGROUND][0] == 'background'
+    assert s_pars[SCALE].name == 'scale'
+    assert s_pars[BACKGROUND].name == 'background'
     # We require structure factors to start with effect radius and volfraction
-    assert s_pars[EFFECT_RADIUS][0] == 'effect_radius'
-    assert s_pars[VOLFRACTION][0] == 'volfraction'
+    assert s_pars[EFFECT_RADIUS].name == 'effect_radius'
+    assert s_pars[VOLFRACTION].name == 'volfraction'
     # Combine the parameter sets.  We are skipping the first three
     # parameters of S since scale, background are defined in P and
@@ -38,5 +38,5 @@
     pars = p_pars + s_pars[3:]
     # check for duplicates; can't use assertion since they may never be checked
-    if len(set(p[0] for p in pars)) != len(pars):
+    if len(set(p.name for p in pars)) != len(pars):
         raise ValueError("Duplicate parameters in %s and %s"%(p_id))
     # For comparison with sasview, determine the old parameters.
@@ -52,10 +52,16 @@
     model_info['title'] = 'Product of %s and structure factor %s'%(p_name, s_name)
     model_info['description'] = model_info['title']
+    model_info['docs'] = model_info['title']
     model_info['category'] = "custom"
     model_info['parameters'] = pars
-    # Remember the component info blocks so we can build the product model
-    model_info['composition'] = ('product', [p_info, s_info])
+    #model_info['single'] = p_info['single'] and s_info['single']
+    model_info['structure_factor'] = False
+    model_info['variant_info'] = None
+    #model_info['tests'] = []
+    #model_info['source'] = []
+    # Iq, Iqxy, form_volume, ER, VR and sesans
     model_info['oldname'] = oldname
     model_info['oldpars'] = oldpars
+    model_info['composition'] = ('product', [p_info, s_info])
     process_parameters(model_info)
     return model_info
Index: sasmodels/sasview_model.py
===================================================================
--- sasmodels/sasview_model.py	(revision 28da77d128132a61c3693d27c989d800ea525f89)
+++ sasmodels/sasview_model.py	(revision fcd7bbda85a603b85101ba7ec6495729497e6b3f)
@@ -60,7 +60,7 @@
         self.dispersion = dict()
         partype = model.info['partype']
-        for name, units, default, limits, _, _ in model.info['parameters']:
-            self.params[name] = default
-            self.details[name] = [units] + limits
+        for p in model.info['parameters']:
+            self.params[p.name] = p.default
+            self.details[p.name] = [p.units] + p.limits
 
         for name in partype['pd-2d']:
