Index: doc/guide/gpu_setup.rst
===================================================================
--- doc/guide/gpu_setup.rst	(revision 59485a45e308439e03beddcf6e942c0c3e72534b)
+++ doc/guide/gpu_setup.rst	(revision 63602b15f168fcfb37242dc2e94348a4751243a3)
@@ -139,7 +139,7 @@
 the compiler.
 
-On Windows, set *SASCOMPILER=tinycc* for the tinycc compiler,
-*SASCOMPILER=msvc* for the Microsoft Visual C compiler,
-or *SASCOMPILER=mingw* for the MinGW compiler. If TinyCC is available
+On Windows, set *SAS_COMPILER=tinycc* for the tinycc compiler,
+*SAS_COMPILER=msvc* for the Microsoft Visual C compiler,
+or *SAS_COMPILER=mingw* for the MinGW compiler. If TinyCC is available
 on the python path (it is provided with SasView), that will be the
 default. If you want one of the other compilers, be sure to have it
Index: doc/guide/pd/polydispersity.rst
===================================================================
--- doc/guide/pd/polydispersity.rst	(revision f41027b26e4170d96eda88d25692883aa0b6de7c)
+++ doc/guide/pd/polydispersity.rst	(revision d089a00eb2e0e6bbb032f5e258e960009a322466)
@@ -8,11 +8,15 @@
 .. _polydispersityhelp:
 
-Polydispersity Distributions
-----------------------------
-
-With some models in sasmodels we can calculate the average intensity for a
-population of particles that exhibit size and/or orientational
-polydispersity. The resultant intensity is normalized by the average
-particle volume such that
+Polydispersity & Orientational Distributions
+--------------------------------------------
+
+For some models we can calculate the average intensity for a population of 
+particles that possess size and/or orientational (ie, angular) distributions. 
+In SasView we call the former *polydispersity* but use the parameter *PD* to 
+parameterise both. In other words, the meaning of *PD* in a model depends on 
+the actual parameter it is being applied too.
+
+The resultant intensity is then normalized by the average particle volume such 
+that
 
 .. math::
@@ -21,5 +25,5 @@
 
 where $F$ is the scattering amplitude and $\langle\cdot\rangle$ denotes an 
-average over the size distribution $f(x; \bar x, \sigma)$, giving
+average over the distribution $f(x; \bar x, \sigma)$, giving
 
 .. math::
@@ -30,4 +34,5 @@
 Each distribution is characterized by a center value $\bar x$ or
 $x_\text{med}$, a width parameter $\sigma$ (note this is *not necessarily*
+<<<<<<< HEAD
 the standard deviation, so read the description carefully), the number of
 sigmas $N_\sigma$ to include from the tails of the distribution, and the
@@ -42,4 +47,15 @@
 However, the distribution width applied to *orientation* (ie, angle-describing)
 parameters is just $\sigma = \mathrm{PD}$.
+=======
+the standard deviation, so read the description of the distribution carefully), 
+the number of sigmas $N_\sigma$ to include from the tails of the distribution, 
+and the number of points used to compute the average. The center of the 
+distribution is set by the value of the model parameter.
+
+The distribution width applied to *volume* (ie, shape-describing) parameters 
+is relative to the center value such that $\sigma = \mathrm{PD} \cdot \bar x$. 
+However, the distribution width applied to *orientation* parameters is just 
+$\sigma = \mathrm{PD}$.
+>>>>>>> master
 
 $N_\sigma$ determines how far into the tails to evaluate the distribution,
@@ -51,7 +67,8 @@
 
 Users should note that the averaging computation is very intensive. Applying
-polydispersion to multiple parameters at the same time or increasing the
-number of points in the distribution will require patience! However, the
-calculations are generally more robust with more data points or more angles.
+polydispersion and/or orientational distributions to multiple parameters at 
+the same time, or increasing the number of points in the distribution, will 
+require patience! However, the calculations are generally more robust with 
+more data points or more angles.
 
 The following distribution functions are provided:
@@ -69,21 +86,24 @@
 
 
+**Beware: when the Polydispersity & Orientational Distribution panel in SasView is**
+**first opened, the default distribution for all parameters is the Gaussian Distribution.**
+**This may not be suitable. See Suggested Applications below.**
+
 .. note:: In 2009 IUPAC decided to introduce the new term 'dispersity' to replace 
            the term 'polydispersity' (see `Pure Appl. Chem., (2009), 81(2), 
            351-353 <http://media.iupac.org/publications/pac/2009/pdf/8102x0351.pdf>`_ 
-           in order to make the terminology describing distributions of properties 
-           unambiguous. Throughout the SasView documentation we continue to use the 
-           term polydispersity because one of the consequences of the IUPAC change is 
-           that orientational polydispersity would not meet their new criteria (which 
-           requires dispersity to be dimensionless).
+           in order to make the terminology describing distributions of chemical 
+           properties unambiguous. However, these terms are unrelated to the 
+           proportional size distributions and orientational distributions used in 
+           SasView models.
 
 Suggested Applications
 ^^^^^^^^^^^^^^^^^^^^^^
 
-If applying polydispersion to parameters describing particle sizes, use
+If applying polydispersion to parameters describing particle sizes, consider using
 the Lognormal or Schulz distributions.
 
 If applying polydispersion to parameters describing interfacial thicknesses
-or angular orientations, use the Gaussian or Boltzmann distributions.
+or angular orientations, consider using the Gaussian or Boltzmann distributions.
 
 If applying polydispersion to parameters describing angles, use the Uniform
@@ -422,20 +442,60 @@
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Many commercial Dynamic Light Scattering (DLS) instruments produce a size
-polydispersity parameter, sometimes even given the symbol $p$\ ! This
-parameter is defined as the relative standard deviation coefficient of
-variation of the size distribution and is NOT the same as the polydispersity
-parameters in the Lognormal and Schulz distributions above (though they all
-related) except when the DLS polydispersity parameter is <0.13.
-
-.. math::
-
-    p_{DLS} = \sqrt(\nu / \bar x^2)
-
-where $\nu$ is the variance of the distribution and $\bar x$ is the mean
-value of $x$.
+Several measures of polydispersity abound in Dynamic Light Scattering (DLS) and 
+it should not be assumed that any of the following can be simply equated with 
+the polydispersity *PD* parameter used in SasView.
+
+The dimensionless **Polydispersity Index (PI)** is a measure of the width of the 
+distribution of autocorrelation function decay rates (*not* the distribution of 
+particle sizes itself, though the two are inversely related) and is defined by 
+ISO 22412:2017 as
+
+.. math::
+
+    PI = \mu_{2} / \bar \Gamma^2
+
+where $\mu_\text{2}$ is the second cumulant, and $\bar \Gamma^2$ is the 
+intensity-weighted average value, of the distribution of decay rates.
+
+*If the distribution of decay rates is Gaussian* then
+
+.. math::
+
+    PI = \sigma^2 / 2\bar \Gamma^2
+
+where $\sigma$ is the standard deviation, allowing a **Relative Polydispersity (RP)** 
+to be defined as
+
+.. math::
+
+    RP = \sigma / \bar \Gamma = \sqrt{2 \cdot PI}
+
+PI values smaller than 0.05 indicate a highly monodisperse system. Values 
+greater than 0.7 indicate significant polydispersity.
+
+The **size polydispersity P-parameter** is defined as the relative standard 
+deviation coefficient of variation  
+
+.. math::
+
+    P = \sqrt\nu / \bar R
+
+where $\nu$ is the variance of the distribution and $\bar R$ is the mean
+value of $R$. Here, the product $P \bar R$ is *equal* to the standard 
+deviation of the Lognormal distribution.
+
+P values smaller than 0.13 indicate a monodisperse system.
 
 For more information see:
-S King, C Washington & R Heenan, *Phys Chem Chem Phys*, (2005), 7, 143
+
+`ISO 22412:2017, International Standards Organisation (2017) <https://www.iso.org/standard/65410.html>`_.
+
+`Polydispersity: What does it mean for DLS and Chromatography <http://www.materials-talks.com/blog/2014/10/23/polydispersity-what-does-it-mean-for-dls-and-chromatography/>`_.
+
+`Dynamic Light Scattering: Common Terms Defined, Whitepaper WP111214. Malvern Instruments (2011) <http://www.biophysics.bioc.cam.ac.uk/wp-content/uploads/2011/02/DLS_Terms_defined_Malvern.pdf>`_.
+
+S King, C Washington & R Heenan, *Phys Chem Chem Phys*, (2005), 7, 143.
+
+T Allen, in *Particle Size Measurement*, 4th Edition, Chapman & Hall, London (1990).
 
 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -447,2 +507,3 @@
 | 2018-03-20 Steve King
 | 2018-04-04 Steve King
+| 2018-08-09 Steve King
Index: doc/guide/scripting.rst
===================================================================
--- doc/guide/scripting.rst	(revision 4aa5dce4bff94106f266d81740a2f4e4f2cc8bae)
+++ doc/guide/scripting.rst	(revision bd7630de7da8bd67aa24b8fc036b2dcc1bc72a16)
@@ -10,15 +10,114 @@
 The key functions are :func:`sasmodels.core.load_model` for loading the
 model definition and compiling the kernel and
-:func:`sasmodels.data.load_data` for calling sasview to load the data. Need
-the data because that defines the resolution function and the q values to
-evaluate. If there is no data, then use :func:`sasmodels.data.empty_data1D`
-or :func:`sasmodels.data.empty_data2D` to create some data with a given $q$.
-
-Using sasmodels through bumps
-=============================
-
-With the data and the model, you can wrap it in a *bumps* model with
+:func:`sasmodels.data.load_data` for calling sasview to load the data.
+
+Preparing data
+==============
+
+Usually you will load data via the sasview loader, with the
+:func:`sasmodels.data.load_data` function.  For example::
+
+    from sasmodels.data import load_data
+    data = load_data("sasmodels/example/093191_201.dat")
+
+You may want to apply a data mask, such a beam stop, and trim high $q$::
+
+    from sasmodels.data import set_beam_stop
+    set_beam_stop(data, qmin, qmax)
+
+The :func:`sasmodels.data.set_beam_stop` method simply sets the *mask*
+attribute for the data.
+
+The data defines the resolution function and the q values to evaluate, so
+even if you simulating experiments prior to making measurements, you still
+need a data object for reference. Use :func:`sasmodels.data.empty_data1D`
+or :func:`sasmodels.data.empty_data2D` to create a container with a
+given $q$ and $\Delta q/q$.  For example::
+
+    import numpy as np
+    from sasmodels.data import empty_data1D
+
+    # 120 points logarithmically spaced from 0.005 to 0.2, with dq/q = 5%
+    q = np.logspace(np.log10(5e-3), np.log10(2e-1), 120)
+    data = empty_data1D(q, resolution=0.05)
+
+To use a more realistic model of resolution, or to load data from a file
+format not understood by SasView, you can use :class:`sasmodels.data.Data1D`
+or :class:`sasmodels.data.Data2D` directly.  The 1D data uses
+*x*, *y*, *dx* and *dy* for $x = q$ and $y = I(q)$, and 2D data uses
+*x*, *y*, *z*, *dx*, *dy*, *dz* for $x, y = qx, qy$ and $z = I(qx, qy)$.
+[Note: internally, the Data2D object uses SasView conventions,
+*qx_data*, *qy_data*, *data*, *dqx_data*, *dqy_data*, and *err_data*.]
+
+For USANS data, use 1D data, but set *dxl* and *dxw* attributes to
+indicate slit resolution::
+
+    data.dxl = 0.117
+
+See :func:`sasmodels.resolution.slit_resolution` for details.
+
+SESANS data is more complicated; if your SESANS format is not supported by
+SasView you need to define a number of attributes beyond *x*, *y*.  For
+example::
+
+    SElength = np.linspace(0, 2400, 61) # [A]
+    data = np.ones_like(SElength)
+    err_data = np.ones_like(SElength)*0.03
+
+    class Source:
+        wavelength = 6 # [A]
+        wavelength_unit = "A"
+    class Sample:
+        zacceptance = 0.1 # [A^-1]
+        thickness = 0.2 # [cm]
+
+    class SESANSData1D:
+        #q_zmax = 0.23 # [A^-1]
+        lam = 0.2 # [nm]
+        x = SElength
+        y = data
+        dy = err_data
+        sample = Sample()
+    data = SESANSData1D()
+
+    x, y = ... # create or load sesans
+    data = smd.Data
+
+The *data* module defines various data plotters as well.
+
+Using sasmodels directly
+========================
+
+Once you have a computational kernel and a data object, you can evaluate
+the model for various parameters using
+:class:`sasmodels.direct_model.DirectModel`.  The resulting object *f*
+will be callable as *f(par=value, ...)*, returning the $I(q)$ for the $q$
+values in the data.  For example::
+
+    import numpy as np
+    from sasmodels.data import empty_data1D
+    from sasmodels.core import load_model
+    from sasmodels.direct_model import DirectModel
+
+    # 120 points logarithmically spaced from 0.005 to 0.2, with dq/q = 5%
+    q = np.logspace(np.log10(5e-3), np.log10(2e-1), 120)
+    data = empty_data1D(q, resolution=0.05)
+    kernel = load_model("ellipsoid)
+    f = DirectModel(data, kernel)
+    Iq = f(radius_polar=100)
+
+Polydispersity information is set with special parameter names:
+
+    * *par_pd* for polydispersity width, $\Delta p/p$,
+    * *par_pd_n* for the number of points in the distribution,
+    * *par_pd_type* for the distribution type (as a string), and
+    * *par_pd_nsigmas* for the limits of the distribution.
+
+Using sasmodels through the bumps optimizer
+===========================================
+
+Like DirectModel, you can wrap data and a kernel in a *bumps* model with
 class:`sasmodels.bumps_model.Model` and create an
-class:`sasmodels.bump_model.Experiment` that you can fit with the *bumps*
+class:`sasmodels.bumps_model.Experiment` that you can fit with the *bumps*
 interface. Here is an example from the *example* directory such as
 *example/model.py*::
@@ -75,14 +174,6 @@
     SasViewCom bumps.cli example/model.py --preview
 
-Using sasmodels directly
-========================
-
-Bumps has a notion of parameter boxes in which you can set and retrieve
-values.  Instead of using bumps, you can create a directly callable function
-with :class:`sasmodels.direct_model.DirectModel`.  The resulting object *f*
-will be callable as *f(par=value, ...)*, returning the $I(q)$ for the $q$
-values in the data.  Polydisperse parameters use the same naming conventions
-as in the bumps model, with e.g., radius_pd being the polydispersity associated
-with radius.
+Calling the computation kernel
+==============================
 
 Getting a simple function that you can call on a set of q values and return
Index: doc/rst_prolog
===================================================================
--- doc/rst_prolog	(revision 30b60d21e384fd9fda8e281e787ff2869925e10d)
+++ doc/rst_prolog	(revision 2c120615303c0e5c43e20ee1b5752447440f5f34)
@@ -9,4 +9,5 @@
 .. |Ang^-3| replace:: |Ang|\ :sup:`-3`
 .. |Ang^-4| replace:: |Ang|\ :sup:`-4`
+.. |nm^-1| replace:: nm\ :sup:`-1`
 .. |cm^-1| replace:: cm\ :sup:`-1`
 .. |cm^2| replace:: cm\ :sup:`2`
Index: sasmodels/compare.py
===================================================================
--- sasmodels/compare.py	(revision d0fdba2d18deb51c93a5bc2376505a4ee81ade9c)
+++ sasmodels/compare.py	(revision bd7630de7da8bd67aa24b8fc036b2dcc1bc72a16)
@@ -1289,5 +1289,6 @@
 
     if opts['datafile'] is not None:
-        data = load_data(os.path.expanduser(opts['datafile']))
+        data0 = load_data(os.path.expanduser(opts['datafile']))
+        data = data0, data0
     else:
         # Hack around the fact that make_data doesn't take a pair of resolutions
Index: sasmodels/core.py
===================================================================
--- sasmodels/core.py	(revision 4341dd4940a5037121414aaef66772bc0bd76640)
+++ sasmodels/core.py	(revision 2dcd6e7a1b6c16cef017142936211c8906750cae)
@@ -233,10 +233,10 @@
         if not callable(model_info.Iq):
             source = generate.make_source(model_info)['dll']
-            old_path = kerneldll.DLL_PATH
+            old_path = kerneldll.SAS_DLL_PATH
             try:
-                kerneldll.DLL_PATH = path
+                kerneldll.SAS_DLL_PATH = path
                 dll = kerneldll.make_dll(source, model_info, dtype=numpy_dtype)
             finally:
-                kerneldll.DLL_PATH = old_path
+                kerneldll.SAS_DLL_PATH = old_path
             compiled_dlls.append(dll)
     return compiled_dlls
Index: sasmodels/data.py
===================================================================
--- sasmodels/data.py	(revision 1a8c11c9d9d7223aecf2c56d6742e33302bffda3)
+++ sasmodels/data.py	(revision bd7630de7da8bd67aa24b8fc036b2dcc1bc72a16)
@@ -183,4 +183,5 @@
     *x* is spin echo length and *y* is polarization (P/P0).
     """
+    isSesans = True
     def __init__(self, **kw):
         Data1D.__init__(self, **kw)
@@ -301,4 +302,11 @@
         self.wavelength_unit = "A"
 
+class Sample(object):
+    """
+    Sample attributes.
+    """
+    def __init__(self):
+        # type: () -> None
+        pass
 
 def empty_data1D(q, resolution=0.0, L=0., dL=0.):
@@ -504,5 +512,5 @@
             # and the data mask will be added to it.
             #mtheory = masked_array(theory, data.mask.copy())
-            theory_x = data.x[~data.mask]
+            theory_x = data.x[data.mask == 0]
             mtheory = masked_array(theory)
             mtheory[~np.isfinite(mtheory)] = masked
@@ -545,5 +553,5 @@
 
     if use_resid:
-        theory_x = data.x[~data.mask]
+        theory_x = data.x[data.mask == 0]
         mresid = masked_array(resid)
         mresid[~np.isfinite(mresid)] = masked
Index: sasmodels/direct_model.py
===================================================================
--- sasmodels/direct_model.py	(revision 1a8c11c9d9d7223aecf2c56d6742e33302bffda3)
+++ sasmodels/direct_model.py	(revision 7b9e4ddca7ad3551d8fe3696d2afe75b0018599e)
@@ -31,4 +31,5 @@
 from . import resolution2d
 from .details import make_kernel_args, dispersion_mesh
+from .modelinfo import DEFAULT_BACKGROUND
 
 # pylint: disable=unused-import
@@ -349,5 +350,5 @@
 
         # Need to pull background out of resolution for multiple scattering
-        background = pars.get('background', 0.)
+        background = pars.get('background', DEFAULT_BACKGROUND)
         pars = pars.copy()
         pars['background'] = 0.
Index: sasmodels/generate.py
===================================================================
--- sasmodels/generate.py	(revision d86f0fc0fff835c5ddf398e64c046518fa4536fc)
+++ sasmodels/generate.py	(revision 6e45516f19370dc8d3a8ff3fa00959f6e27d9e19)
@@ -965,10 +965,13 @@
     docs = model_info.docs if model_info.docs is not None else ""
     docs = convert_section_titles_to_boldface(docs)
-    pars = make_partable(model_info.parameters.COMMON
-                         + model_info.parameters.kernel_parameters)
+    if model_info.structure_factor:
+        pars = model_info.parameters.kernel_parameters
+    else:
+        pars = model_info.parameters.COMMON + model_info.parameters.kernel_parameters
+    partable = make_partable(pars)
     subst = dict(id=model_info.id.replace('_', '-'),
                  name=model_info.name,
                  title=model_info.title,
-                 parameters=pars,
+                 parameters=partable,
                  returns=Sq_units if model_info.structure_factor else Iq_units,
                  docs=docs)
Index: sasmodels/kernel_iq.c
===================================================================
--- sasmodels/kernel_iq.c	(revision 7c35fda803d68561ee8433f7c9355dcc9678049e)
+++ sasmodels/kernel_iq.c	(revision 705307783b90bea1a66cdf1ff38974433eb673cb)
@@ -84,5 +84,5 @@
   out_spin = clip(out_spin, 0.0, 1.0);
   // Previous version of this function took the square root of the weights,
-  // under the assumption that 
+  // under the assumption that
   //
   //     w*I(q, rho1, rho2, ...) = I(q, sqrt(w)*rho1, sqrt(w)*rho2, ...)
@@ -188,11 +188,11 @@
     QACRotation *rotation,
     double qx, double qy,
-    double *qa_out, double *qc_out)
+    double *qab_out, double *qc_out)
 {
+    // Indirect calculation of qab, from qab^2 = |q|^2 - qc^2
     const double dqc = rotation->R31*qx + rotation->R32*qy;
-    // Indirect calculation of qab, from qab^2 = |q|^2 - qc^2
-    const double dqa = sqrt(-dqc*dqc + qx*qx + qy*qy);
-
-    *qa_out = dqa;
+    const double dqab_sq = -dqc*dqc + qx*qx + qy*qy;
+    //*qab_out = sqrt(fabs(dqab_sq));
+    *qab_out = dqab_sq > 0.0 ? sqrt(dqab_sq) : 0.0;
     *qc_out = dqc;
 }
Index: sasmodels/model_test.py
===================================================================
--- sasmodels/model_test.py	(revision 3221de0ed9b3480163246ceb0503432126bd5134)
+++ sasmodels/model_test.py	(revision 012cd342ba6d27483147e3401f01fb7b93ea589c)
@@ -376,12 +376,4 @@
         stream.writeln(traceback.format_exc())
         return
-    # Run the test suite
-    suite.run(result)
-
-    # Print the failures and errors
-    for _, tb in result.errors:
-        stream.writeln(tb)
-    for _, tb in result.failures:
-        stream.writeln(tb)
 
     # Warn if there are no user defined tests.
@@ -393,4 +385,7 @@
     # iterator since we don't have direct access to the list of tests in the
     # test suite.
+    # In Qt5 suite.run() will clear all tests in the suite after running
+    # with no way of retaining them for the test below, so let's check
+    # for user tests before running the suite.
     for test in suite:
         if not test.info.tests:
@@ -399,4 +394,13 @@
     else:
         stream.writeln("Note: no test suite created --- this should never happen")
+
+    # Run the test suite
+    suite.run(result)
+
+    # Print the failures and errors
+    for _, tb in result.errors:
+        stream.writeln(tb)
+    for _, tb in result.failures:
+        stream.writeln(tb)
 
     output = stream.getvalue()
Index: sasmodels/modelinfo.py
===================================================================
--- sasmodels/modelinfo.py	(revision 95498a34dd5bf649c8e35fa888ca2bbdab9f3d77)
+++ sasmodels/modelinfo.py	(revision 7b9e4ddca7ad3551d8fe3696d2afe75b0018599e)
@@ -45,7 +45,8 @@
 # Note that scale and background cannot be coordinated parameters whose value
 # depends on the some polydisperse parameter with the current implementation
+DEFAULT_BACKGROUND = 1e-3
 COMMON_PARAMETERS = [
     ("scale", "", 1, (0.0, np.inf), "", "Source intensity"),
-    ("background", "1/cm", 1e-3, (-np.inf, np.inf), "", "Source background"),
+    ("background", "1/cm", DEFAULT_BACKGROUND, (-np.inf, np.inf), "", "Source background"),
 ]
 assert (len(COMMON_PARAMETERS) == 2
@@ -589,5 +590,5 @@
                 Parameter('up:frac_f', '', 0., [0., 1.],
                           'magnetic', 'fraction of spin up final'),
-                Parameter('up:angle', 'degress', 0., [0., 360.],
+                Parameter('up:angle', 'degrees', 0., [0., 360.],
                           'magnetic', 'spin up angle'),
             ])
Index: sasmodels/models/_spherepy.py
===================================================================
--- sasmodels/models/_spherepy.py	(revision 108e70e22154db937a6d46f66be6dd70408cce6d)
+++ sasmodels/models/_spherepy.py	(revision ca4444fb3f1d373b0e94842e6733943d12ce79e9)
@@ -1,5 +1,5 @@
 r"""
 For information about polarised and magnetic scattering, see
-the :doc:`magnetic help <../sasgui/perspectives/fitting/mag_help>` documentation.
+the :ref:`magnetism` documentation.
 
 Definition
Index: sasmodels/models/core_shell_cylinder.py
===================================================================
--- sasmodels/models/core_shell_cylinder.py	(revision 2d81cfe3be42579d563407fb9275b7b516fee234)
+++ sasmodels/models/core_shell_cylinder.py	(revision e31b19a46729ff0f8f1a5eb9847f69524a6ed1d3)
@@ -5,5 +5,11 @@
 The output of the 2D scattering intensity function for oriented core-shell
 cylinders is given by (Kline, 2006 [#kline]_). The form factor is normalized
-by the particle volume.
+by the particle volume. Note that in this model the shell envelops the entire
+core so that besides a "sleeve" around the core, the shell also provides two
+flat end caps of thickness = shell thickness. In other words the length of the
+total cyclinder is the length of the core cylinder plus twice the thickness of
+the shell. If no end caps are desired one should use the
+:ref:`core-shell-bicelle` and set the thickness of the end caps (in this case
+the "thick_face") to zero.
 
 .. math::
@@ -33,6 +39,6 @@
 
 and $\alpha$ is the angle between the axis of the cylinder and $\vec q$,
-$V_s$ is the volume of the outer shell (i.e. the total volume, including
-the shell), $V_c$ is the volume of the core, $L$ is the length of the core,
+$V_s$ is the total volume (i.e. including both the core and the outer shell),
+$V_c$ is the volume of the core, $L$ is the length of the core,
 $R$ is the radius of the core, $T$ is the thickness of the shell, $\rho_c$
 is the scattering length density of the core, $\rho_s$ is the scattering
@@ -135,12 +141,4 @@
     return 0.5 * (ddd) ** (1. / 3.)
 
-def VR(radius, thickness, length):
-    """
-    Returns volume ratio
-    """
-    whole = pi * (radius + thickness) ** 2 * (length + 2 * thickness)
-    core = pi * radius ** 2 * length
-    return whole, whole - core
-
 def random():
     outer_radius = 10**np.random.uniform(1, 4.7)
Index: sasmodels/models/core_shell_sphere.py
===================================================================
--- sasmodels/models/core_shell_sphere.py	(revision dc76240c1dc8dcc0235d0432f3a909bea6e0c6a2)
+++ sasmodels/models/core_shell_sphere.py	(revision da1c8d14693f7a806280e49df578d46f9aa451d8)
@@ -89,15 +89,4 @@
     return radius + thickness
 
-def VR(radius, thickness):
-    """
-        Volume ratio
-        @param radius: core radius
-        @param thickness: shell thickness
-    """
-    return (1, 1)
-    whole = 4.0/3.0 * pi * (radius + thickness)**3
-    core = 4.0/3.0 * pi * radius**3
-    return whole, whole - core
-
 def random():
     outer_radius = 10**np.random.uniform(1.3, 4.3)
@@ -114,7 +103,4 @@
 tests = [
     [{'radius': 20.0, 'thickness': 10.0}, 'ER', 30.0],
-    # TODO: VR test suppressed until we sort out new product model
-    # and determine what to do with volume ratio.
-    #[{'radius': 20.0, 'thickness': 10.0}, 'VR', 0.703703704],
 
     # The SasView test result was 0.00169, with a background of 0.001
Index: sasmodels/models/ellipsoid.py
===================================================================
--- sasmodels/models/ellipsoid.py	(revision 2d81cfe3be42579d563407fb9275b7b516fee234)
+++ sasmodels/models/ellipsoid.py	(revision 01688448fd87fd51ac83d2d724652266c645773a)
@@ -125,4 +125,9 @@
 import numpy as np
 from numpy import inf, sin, cos, pi
+
+try:
+    from numpy import cbrt
+except ImportError:
+    def cbrt(x): return x ** (1.0/3.0)
 
 name = "ellipsoid"
@@ -170,7 +175,5 @@
     idx = radius_polar < radius_equatorial
     ee[idx] = (radius_equatorial[idx] ** 2 - radius_polar[idx] ** 2) / radius_equatorial[idx] ** 2
-    idx = radius_polar == radius_equatorial
-    ee[idx] = 2 * radius_polar[idx]
-    valid = (radius_polar * radius_equatorial != 0)
+    valid = (radius_polar * radius_equatorial != 0) & (radius_polar != radius_equatorial)
     bd = 1.0 - ee[valid]
     e1 = np.sqrt(ee[valid])
@@ -179,8 +182,11 @@
     b2 = 1.0 + bd / 2 / e1 * np.log(bL)
     delta = 0.75 * b1 * b2
-
-    ddd = np.zeros_like(radius_polar)
-    ddd[valid] = 2.0 * (delta + 1.0) * radius_polar * radius_equatorial ** 2
-    return 0.5 * ddd ** (1.0 / 3.0)
+    ddd = 2.0 * (delta + 1.0) * (radius_polar * radius_equatorial**2)[valid]
+
+    r = np.zeros_like(radius_polar)
+    r[valid] = 0.5 * cbrt(ddd)
+    idx = radius_polar == radius_equatorial
+    r[idx] = radius_polar[idx]
+    return r
 
 def random():
Index: sasmodels/models/fractal_core_shell.py
===================================================================
--- sasmodels/models/fractal_core_shell.py	(revision ef07e950965796e2a3a8156fcade98ce5e403001)
+++ sasmodels/models/fractal_core_shell.py	(revision eb3eb38c009cc70439ad74fa78055d6551981520)
@@ -88,5 +88,5 @@
     ["sld_shell",   "1e-6/Ang^2", 2.0,  [-inf, inf], "sld",    "Sphere shell scattering length density"],
     ["sld_solvent", "1e-6/Ang^2", 3.0,  [-inf, inf], "sld",    "Solvent scattering length density"],
-    ["volfraction", "",           1.0,  [0.0, inf],  "",       "Volume fraction of building block spheres"],
+    ["volfraction", "",           0.05,  [0.0, inf],  "",       "Volume fraction of building block spheres"],
     ["fractal_dim",    "",        2.0,  [0.0, 6.0],  "",       "Fractal dimension"],
     ["cor_length",  "Ang",      100.0,  [0.0, inf],  "",       "Correlation length of fractal-like aggregates"],
@@ -134,27 +134,21 @@
     return radius + thickness
 
-def VR(radius, thickness):
-    """
-        Volume ratio
-        @param radius: core radius
-        @param thickness: shell thickness
-    """
-    whole = 4.0/3.0 * pi * (radius + thickness)**3
-    core = 4.0/3.0 * pi * radius**3
-    return whole, whole-core
+tests = [[{'radius': 20.0, 'thickness': 10.0}, 'ER', 30.0],
 
-tests = [[{'radius': 20.0, 'thickness': 10.0}, 'ER', 30.0],
-         [{'radius': 20.0, 'thickness': 10.0}, 'VR', 0.703703704]]
-
-#         # The SasView test result was 0.00169, with a background of 0.001
-#         # They are however wrong as we now know.  IGOR might be a more
-#         # appropriate source. Otherwise will just have to assume this is now
-#         # correct and self generate a correct answer for the future. Until we
-#         # figure it out leave the tests commented out
-#         [{'radius': 60.0,
-#           'thickness': 10.0,
-#           'sld_core': 1.0,
-#           'sld_shell': 2.0,
-#           'sld_solvent': 3.0,
-#           'background': 0.0
-#          }, 0.015211, 692.84]]
+#         # At some point the SasView 3.x test result was deemed incorrect. The
+          #following tests were verified against NIST IGOR macros ver 7.850.
+          #NOTE: NIST macros do only provide for a polydispers core (no option
+          #for a poly shell or for a monodisperse core.  The results seemed
+          #extremely sensitive to the core PD, varying non monotonically all
+          #the way to a PD of 1e-6. From 1e-6 to 1e-9 no changes in the
+          #results were observed and the values below were taken using PD=1e-9.
+          #Non-monotonically = I(0.001)=188 to 140 to 177 back to 160 etc.
+         [{'radius': 20.0,
+           'thickness': 5.0,
+           'sld_core': 3.5,
+           'sld_shell': 1.0,
+           'sld_solvent': 6.35,
+           'volfraction': 0.05,
+           'background': 0.0},
+           [0.001,0.00291,0.0107944,0.029923,0.100726,0.476304],
+           [177.146,165.151,84.1596,20.1466,1.40906,0.00622666]]]
Index: sasmodels/models/hollow_cylinder.py
===================================================================
--- sasmodels/models/hollow_cylinder.py	(revision 2d81cfe3be42579d563407fb9275b7b516fee234)
+++ sasmodels/models/hollow_cylinder.py	(revision 455aaa1fbc231bb1caf309ca6419f0e3ffd5e19c)
@@ -1,6 +1,10 @@
 r"""
+Definition
+----------
+
 This model provides the form factor, $P(q)$, for a monodisperse hollow right
-angle circular cylinder (rigid tube) where the form factor is normalized by the
-volume of the tube (i.e. not by the external volume).
+angle circular cylinder (rigid tube) where the The inside and outside of the
+hollow cylinder are assumed to have the same SLD and the form factor is thus
+normalized by the volume of the tube (i.e. not by the total cylinder volume).
 
 .. math::
@@ -8,10 +12,16 @@
     P(q) = \text{scale} \left<F^2\right>/V_\text{shell} + \text{background}
 
-where the averaging $\left<\ldots\right>$ is applied only for the 1D calculation.
+where the averaging $\left<\ldots\right>$ is applied only for the 1D
+calculation. If Intensity is given on an absolute scale, the scale factor here
+is the volume fraction of the shell.  This differs from
+the :ref:`core-shell-cylinder` in that, in that case, scale is the volume
+fraction of the entire cylinder (core+shell). The application might be for a
+bilayer which wraps into a hollow tube and the volume fraction of material is
+all in the shell, whereas the :ref:`core-shell-cylinder` model might be used for
+a cylindrical micelle where the tails in the core have a different SLD than the
+headgroups (in the shell) and the volume fraction of material comes fromm the
+whole cyclinder.  NOTE: the hollow_cylinder represents a tube whereas the
+core_shell_cylinder includes a shell layer covering the ends (end caps) as well.
 
-The inside and outside of the hollow cylinder are assumed have the same SLD.
-
-Definition
-----------
 
 The 1D scattering intensity is calculated in the following way (Guinier, 1955)
@@ -48,6 +58,6 @@
 ----------
 
-L A Feigin and D I Svergun, *Structure Analysis by Small-Angle X-Ray and
-Neutron Scattering*, Plenum Press, New York, (1987)
+.. [#] L A Feigin and D I Svergun, *Structure Analysis by Small-Angle X-Ray and
+   Neutron Scattering*, Plenum Press, New York, (1987)
 
 Authorship and Verification
@@ -55,7 +65,7 @@
 
 * **Author:** NIST IGOR/DANSE **Date:** pre 2010
-* **Last Modified by:** Richard Heenan **Date:** October 06, 2016
-   (reparametrised to use thickness, not outer radius)
-* **Last Reviewed by:** Richard Heenan **Date:** October 06, 2016
+* **Last Modified by:** Paul Butler **Date:** September 06, 2018
+   (corrected VR calculation)
+* **Last Reviewed by:** Paul Butler **Date:** September 06, 2018
 """
 
@@ -120,5 +130,5 @@
     vol_total = pi*router*router*length
     vol_shell = vol_total - vol_core
-    return vol_shell, vol_total
+    return vol_total, vol_shell
 
 def random():
@@ -151,5 +161,5 @@
 tests = [
     [{}, 0.00005, 1764.926],
-    [{}, 'VR', 1.8],
+    [{}, 'VR', 0.55555556],
     [{}, 0.001, 1756.76],
     [{}, (qx, qy), 2.36885476192],
Index: sasmodels/models/hollow_rectangular_prism.py
===================================================================
--- sasmodels/models/hollow_rectangular_prism.py	(revision 2d81cfe3be42579d563407fb9275b7b516fee234)
+++ sasmodels/models/hollow_rectangular_prism.py	(revision 455aaa1fbc231bb1caf309ca6419f0e3ffd5e19c)
@@ -2,16 +2,12 @@
 # Note: model title and parameter table are inserted automatically
 r"""
-
-This model provides the form factor, $P(q)$, for a hollow rectangular
-parallelepiped with a wall of thickness $\Delta$.
-
-
 Definition
 ----------
 
-The 1D scattering intensity for this model is calculated by forming
-the difference of the amplitudes of two massive parallelepipeds
-differing in their outermost dimensions in each direction by the
-same length increment $2\Delta$ (Nayuk, 2012).
+This model provides the form factor, $P(q)$, for a hollow rectangular
+parallelepiped with a wall of thickness $\Delta$. The 1D scattering intensity
+for this model is calculated by forming the difference of the amplitudes of two
+massive parallelepipeds differing in their outermost dimensions in each
+direction by the same length increment $2\Delta$ (\ [#Nayuk2012]_ Nayuk, 2012).
 
 As in the case of the massive parallelepiped model (:ref:`rectangular-prism`),
@@ -61,8 +57,9 @@
   \rho_\text{solvent})^2 \times P(q) + \text{background}
 
-where $\rho_\text{p}$ is the scattering length of the parallelepiped,
-$\rho_\text{solvent}$ is the scattering length of the solvent,
+where $\rho_\text{p}$ is the scattering length density of the parallelepiped,
+$\rho_\text{solvent}$ is the scattering length density of the solvent,
 and (if the data are in absolute units) *scale* represents the volume fraction
-(which is unitless).
+(which is unitless) of the rectangular shell of material (i.e. not including
+the volume of the solvent filled core).
 
 For 2d data the orientation of the particle is required, described using
@@ -73,6 +70,7 @@
 
 For 2d, constraints must be applied during fitting to ensure that the inequality
-$A < B < C$ is not violated, and hence the correct definition of angles is preserved. The calculation will not report an error,
-but the results may be not correct.
+$A < B < C$ is not violated, and hence the correct definition of angles is
+preserved. The calculation will not report an error if the inequality is *not*
+preserved, but the results may be not correct.
 
 .. figure:: img/parallelepiped_angle_definition.png
@@ -99,5 +97,13 @@
 ----------
 
-R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854
+.. [#Nayuk2012] R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854
+
+
+Authorship and Verification
+----------------------------
+
+* **Author:** Miguel Gonzales **Date:** February 26, 2016
+* **Last Modified by:** Paul Kienzle **Date:** December 14, 2017
+* **Last Reviewed by:** Paul Butler **Date:** September 06, 2018
 """
 
Index: sasmodels/models/hollow_rectangular_prism_thin_walls.py
===================================================================
--- sasmodels/models/hollow_rectangular_prism_thin_walls.py	(revision 2d81cfe3be42579d563407fb9275b7b516fee234)
+++ sasmodels/models/hollow_rectangular_prism_thin_walls.py	(revision 6e7d7b66fc1ec444c4e30ac47db7bbcdc554ecc3)
@@ -2,14 +2,12 @@
 # Note: model title and parameter table are inserted automatically
 r"""
+Definition
+----------
+
 
 This model provides the form factor, $P(q)$, for a hollow rectangular
 prism with infinitely thin walls. It computes only the 1D scattering, not the 2D.
-
-
-Definition
-----------
-
 The 1D scattering intensity for this model is calculated according to the
-equations given by Nayuk and Huber (Nayuk, 2012).
+equations given by Nayuk and Huber\ [#Nayuk2012]_.
 
 Assuming a hollow parallelepiped with infinitely thin walls, edge lengths
@@ -55,8 +53,8 @@
   I(q) = \text{scale} \times V \times (\rho_\text{p} - \rho_\text{solvent})^2 \times P(q)
 
-where $V$ is the volume of the rectangular prism, $\rho_\text{p}$
-is the scattering length of the parallelepiped, $\rho_\text{solvent}$
-is the scattering length of the solvent, and (if the data are in absolute
-units) *scale* represents the volume fraction (which is unitless).
+where $V$ is the surface area of the rectangular prism, $\rho_\text{p}$
+is the scattering length density of the parallelepiped, $\rho_\text{solvent}$
+is the scattering length density of the solvent, and (if the data are in
+absolute units) *scale* is related to the total surface area.
 
 **The 2D scattering intensity is not computed by this model.**
@@ -67,5 +65,5 @@
 
 Validation of the code was conducted  by qualitatively comparing the output
-of the 1D model to the curves shown in (Nayuk, 2012).
+of the 1D model to the curves shown in (Nayuk, 2012\ [#Nayuk2012]_).
 
 
@@ -73,5 +71,13 @@
 ----------
 
-R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854
+.. [#Nayuk2012] R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854
+
+
+Authorship and Verification
+----------------------------
+
+* **Author:** Miguel Gonzales **Date:** February 26, 2016
+* **Last Modified by:** Paul Kienzle **Date:** October 15, 2016
+* **Last Reviewed by:** Paul Butler **Date:** September 07, 2018
 """
 
Index: sasmodels/models/spherical_sld.py
===================================================================
--- sasmodels/models/spherical_sld.py	(revision 2d81cfe3be42579d563407fb9275b7b516fee234)
+++ sasmodels/models/spherical_sld.py	(revision 5601947b596b5a6e24ccffd7b45469b40ae22f9d)
@@ -1,3 +1,6 @@
 r"""
+Definition
+----------
+
 Similarly to the onion, this model provides the form factor, $P(q)$, for
 a multi-shell sphere, where the interface between the each neighboring
@@ -16,14 +19,15 @@
 interface. The form factor is normalized by the total volume of the sphere.
 
-Interface shapes are as follows::
+Interface shapes are as follows:
 
     0: erf($\nu z$)
+    
     1: Rpow($z^\nu$)
+    
     2: Lpow($z^\nu$)
+    
     3: Rexp($-\nu z$)
+    
     4: Lexp($-\nu z$)
-
-Definition
-----------
 
 The form factor $P(q)$ in 1D is calculated by:
@@ -174,8 +178,18 @@
     when $P(Q) * S(Q)$ is applied.
 
+
 References
 ----------
-L A Feigin and D I Svergun, Structure Analysis by Small-Angle X-Ray
-and Neutron Scattering, Plenum Press, New York, (1987)
+
+.. [#] L A Feigin and D I Svergun, Structure Analysis by Small-Angle X-Ray
+   and Neutron Scattering, Plenum Press, New York, (1987)
+
+
+Authorship and Verification
+----------------------------
+
+* **Author:** Jae-Hie Cho **Date:** Nov 1, 2010
+* **Last Modified by:** Paul Kienzle **Date:** Dec 20, 2016
+* **Last Reviewed by:** Paul Butler **Date:** September 8, 2018
 """
 
Index: sasmodels/models/spinodal.py
===================================================================
--- sasmodels/models/spinodal.py	(revision ef07e950965796e2a3a8156fcade98ce5e403001)
+++ sasmodels/models/spinodal.py	(revision 475ff585df3808f7c560003331e4cf2e1ea87fc3)
@@ -3,15 +3,24 @@
 ----------
 
-This model calculates the SAS signal of a phase separating solution
-under spinodal decomposition. The scattering intensity $I(q)$ is calculated as
+This model calculates the SAS signal of a phase separating system 
+undergoing spinodal decomposition. The scattering intensity $I(q)$ is calculated 
+as 
 
 .. math::
     I(q) = I_{max}\frac{(1+\gamma/2)x^2}{\gamma/2+x^{2+\gamma}}+B
 
-where $x=q/q_0$ and $B$ is a flat background. The characteristic structure
-length scales with the correlation peak at $q_0$. The exponent $\gamma$ is
-equal to $d+1$ with d the dimensionality of the off-critical concentration
-mixtures. A transition to $\gamma=2d$ is seen near the percolation threshold
-into the critical concentration regime.
+where $x=q/q_0$, $q_0$ is the peak position, $I_{max}$ is the intensity 
+at $q_0$ (parameterised as the $scale$ parameter), and $B$ is a flat 
+background. The spinodal wavelength is given by $2\pi/q_0$. 
+
+The exponent $\gamma$ is equal to $d+1$ for off-critical concentration 
+mixtures (smooth interfaces) and $2d$ for critical concentration mixtures 
+(entangled interfaces), where $d$ is the dimensionality (ie, 1, 2, 3) of the 
+system. Thus 2 <= $\gamma$ <= 6. A transition from $\gamma=d+1$ to $\gamma=2d$ 
+is expected near the percolation threshold. 
+
+As this function tends to zero as $q$ tends to zero, in practice it may be 
+necessary to combine it with another function describing the low-angle 
+scattering, or to simply omit the low-angle scattering from the fit.
 
 References
@@ -22,8 +31,9 @@
 Physica A 123,497 (1984).
 
-Authorship and Verification
-----------------------------
+Revision History
+----------------
 
-* **Author:** Dirk Honecker **Date:** Oct 7, 2016
+* **Author:**  Dirk Honecker **Date:** Oct 7, 2016
+* **Revised:** Steve King    **Date:** Sep 7, 2018
 """
 
@@ -34,12 +44,14 @@
 title = "Spinodal decomposition model"
 description = """\
-      I(q) = scale ((1+gamma/2)x^2)/(gamma/2+x^(2+gamma))+background
+      I(q) = Imax ((1+gamma/2)x^2)/(gamma/2+x^(2+gamma)) + background
 
       List of default parameters:
-      scale = scaling
-      gamma = exponent
-      x = q/q_0
+      
+      Imax = correlation peak intensity at q_0
+      background = incoherent background
+      gamma = exponent (see model documentation)
       q_0 = correlation peak position [1/A]
-      background = Incoherent background"""
+      x = q/q_0"""
+      
 category = "shape-independent"
 
Index: sasmodels/models/vesicle.py
===================================================================
--- sasmodels/models/vesicle.py	(revision ef07e950965796e2a3a8156fcade98ce5e403001)
+++ sasmodels/models/vesicle.py	(revision b4776059692723f870409527b8054b2a8a5e6797)
@@ -3,5 +3,9 @@
 ----------
 
-The 1D scattering intensity is calculated in the following way (Guinier, 1955)
+This model provides the form factor, *P(q)*, for an unilamellar vesicle and is
+effectively identical to the hollow sphere reparameterized to be
+more intuitive for a vesicle and normalizing the form factor by the volume of
+the shell. The 1D scattering intensity is calculated in the following way
+(Guinier,1955\ [#Guinier1955]_)
 
 .. math::
@@ -53,10 +57,14 @@
 ----------
 
-A Guinier and G. Fournet, *Small-Angle Scattering of X-Rays*, John Wiley and
-Sons, New York, (1955)
+.. [#Guinier1955] A Guinier and G. Fournet, *Small-Angle Scattering of X-Rays*, John Wiley and
+   Sons, New York, (1955)
+
+
+Authorship and Verification
+----------------------------
 
 * **Author:** NIST IGOR/DANSE **Date:** pre 2010
 * **Last Modified by:** Paul Butler **Date:** March 20, 2016
-* **Last Reviewed by:** Paul Butler **Date:** March 20, 2016
+* **Last Reviewed by:** Paul Butler **Date:** September 7, 2018
 """
 
@@ -65,8 +73,5 @@
 
 name = "vesicle"
-title = "This model provides the form factor, *P(q)*, for an unilamellar \
-    vesicle. This is model is effectively identical to the hollow sphere \
-    reparameterized to be more intuitive for a vesicle and normalizing the \
-    form factor by the volume of the shell."
+title = "Vesicle model representing a hollow sphere"
 description = """
     Model parameters:
Index: sasmodels/resolution.py
===================================================================
--- sasmodels/resolution.py	(revision 0b9c6df46513d1c375b80d4d720164332391302a)
+++ sasmodels/resolution.py	(revision 9e7837a27701a2e9059daf0ed4b8c5127a10bf59)
@@ -20,5 +20,8 @@
 MINIMUM_RESOLUTION = 1e-8
 MINIMUM_ABSOLUTE_Q = 0.02  # relative to the minimum q in the data
-PINHOLE_N_SIGMA = 2.5 # From: Barker & Pedersen 1995 JAC
+# According to (Barker & Pedersen 1995 JAC), 2.5 sigma is a good limit.
+# According to simulations with github.com:scattering/sansresolution.git
+# it is better to use asymmetric bounds (2.5, 3.0)
+PINHOLE_N_SIGMA = (2.5, 3.0)
 
 class Resolution(object):
@@ -90,6 +93,6 @@
         # from the geometry, they may appear since we are using a truncated
         # gaussian to represent resolution rather than a skew distribution.
-        cutoff = MINIMUM_ABSOLUTE_Q*np.min(self.q)
-        self.q_calc = self.q_calc[self.q_calc >= cutoff]
+        #cutoff = MINIMUM_ABSOLUTE_Q*np.min(self.q)
+        #self.q_calc = self.q_calc[self.q_calc >= cutoff]
 
         # Build weight matrix from calculated q values
@@ -188,8 +191,12 @@
     cdf = erf((edges[:, None] - q[None, :]) / (sqrt(2.0)*q_width)[None, :])
     weights = cdf[1:] - cdf[:-1]
-    # Limit q range to +/- 2.5 sigma
-    qhigh = q + nsigma*q_width
-    #qlow = q - nsigma*q_width  # linear limits
-    qlow = q*q/qhigh  # log limits
+    # Limit q range to (-2.5,+3) sigma
+    try:
+        nsigma_low, nsigma_high = nsigma
+    except TypeError:
+        nsigma_low = nsigma_high = nsigma
+    qhigh = q + nsigma_high*q_width
+    qlow = q - nsigma_low*q_width  # linear limits
+    ##qlow = q*q/qhigh  # log limits
     weights[q_calc[:, None] < qlow[None, :]] = 0.
     weights[q_calc[:, None] > qhigh[None, :]] = 0.
@@ -365,5 +372,5 @@
 
 
-def pinhole_extend_q(q, q_width, nsigma=3):
+def pinhole_extend_q(q, q_width, nsigma=PINHOLE_N_SIGMA):
     """
     Given *q* and *q_width*, find a set of sampling points *q_calc* so
@@ -371,5 +378,9 @@
     function.
     """
-    q_min, q_max = np.min(q - nsigma*q_width), np.max(q + nsigma*q_width)
+    try:
+        nsigma_low, nsigma_high = nsigma
+    except TypeError:
+        nsigma_low = nsigma_high = nsigma
+    q_min, q_max = np.min(q - nsigma_low*q_width), np.max(q + nsigma_high*q_width)
     return linear_extrapolation(q, q_min, q_max)
 
