Index: sasmodels/conversion_table.py
===================================================================
--- sasmodels/conversion_table.py	(revision bb584b3946fe8b5a6ab2d1a751f4b80ad63cf1b8)
+++ sasmodels/conversion_table.py	(revision d3e3f756c37280a388d39555db40367e494d7182)
@@ -549,5 +549,5 @@
             "radius": "core_radius",
             "sld_solvent": "core_sld",
-            "n_pairs": "n_pairs",
+            "n_shells": "n_pairs",
             "thick_shell": "s_thickness",
             "sld": "shell_sld",
Index: sasmodels/modelinfo.py
===================================================================
--- sasmodels/modelinfo.py	(revision 85fe7f81bca37e67a39808fbf8e07e7d8be316b1)
+++ sasmodels/modelinfo.py	(revision f88e2480698b5dcd90f16c16ecd9d445273a1b9a)
@@ -230,8 +230,11 @@
     defined as a sublist with the following elements:
 
-    *name* is the name that will be used in the call to the kernel
-    function and the name that will be displayed to the user.  Names
+    *name* is the name that will be displayed to the user.  Names
     should be lower case, with words separated by underscore.  If
-    acronyms are used, the whole acronym should be upper case.
+    acronyms are used, the whole acronym should be upper case. For vector
+    parameters, the name will be followed by *[len]* where *len* is an
+    integer length of the vector, or the name of the parameter which
+    controls the length.  The attribute *id* will be created from name
+    without the length.
 
     *units* should be one of *degrees* for angles, *Ang* for lengths,
@@ -603,5 +606,6 @@
         # Using the call_parameters table, we already have expanded forms
         # for each of the vector parameters; put them in a lookup table
-        expanded_pars = dict((p.name, p) for p in self.call_parameters)
+        # Note: p.id and p.name are currently identical for the call parameters
+        expanded_pars = dict((p.id, p) for p in self.call_parameters)
 
         def append_group(name):
Index: sasmodels/models/multilayer_vesicle.c
===================================================================
--- sasmodels/models/multilayer_vesicle.c	(revision 925ad6edca2969db8fb763eb02beee2c5a5f2872)
+++ sasmodels/models/multilayer_vesicle.c	(revision ec1d4bc8d5b651644ea17f20215b21a5870340f9)
@@ -1,4 +1,15 @@
-static
-double multilayer_vesicle_kernel(double q,
+static double
+form_volume(double radius,
+          double thick_shell,
+          double thick_solvent,
+          double fp_n_shells)
+{
+    int n_shells = (int)(fp_n_shells + 0.5);
+    double R_N = radius + n_shells*(thick_shell+thick_solvent) - thick_solvent;
+    return M_4PI_3*cube(R_N);
+}
+
+static double
+multilayer_vesicle_kernel(double q,
           double volfraction,
           double radius,
@@ -7,5 +18,5 @@
           double sld_solvent,
           double sld,
-          int n_pairs)
+          int n_shells)
 {
     //calculate with a loop, two shells at a time
@@ -29,16 +40,14 @@
 
         //do 2 layers at a time
-        ii += 1;
+        ii++;
 
-    } while(ii <= n_pairs-1);  //change to make 0 < n_pairs < 2 correspond to
+    } while(ii <= n_shells-1);  //change to make 0 < n_shells < 2 correspond to
                                //unilamellar vesicles (C. Glinka, 11/24/03)
 
-    fval *= volfraction*1.0e-4*fval/voli;
-
-    return(fval);
+    return 1.0e-4*volfraction*fval*fval;  // Volume normalization happens in caller
 }
 
-static
-double Iq(double q,
+static double
+Iq(double q,
           double volfraction,
           double radius,
@@ -47,7 +56,7 @@
           double sld_solvent,
           double sld,
-          double fp_n_pairs)
+          double fp_n_shells)
 {
-    int n_pairs = (int)(fp_n_pairs + 0.5);
+    int n_shells = (int)(fp_n_shells + 0.5);
     return multilayer_vesicle_kernel(q,
            volfraction,
@@ -57,5 +66,5 @@
            sld_solvent,
            sld,
-           n_pairs);
+           n_shells);
 }
 
Index: sasmodels/models/multilayer_vesicle.py
===================================================================
--- sasmodels/models/multilayer_vesicle.py	(revision 925ad6edca2969db8fb763eb02beee2c5a5f2872)
+++ sasmodels/models/multilayer_vesicle.py	(revision ec1d4bc8d5b651644ea17f20215b21a5870340f9)
@@ -19,28 +19,30 @@
 
 .. math::
-    P(q) = \text{scale} \cdot \frac{V_f}{V_t} F^2(q) + \text{background}
+    P(q) = \text{scale} \cdot \frac{\phi}{V(R_N)} F^2(q) + \text{background}
+
+where
+
+.. math::
+     F(q) = (\rho_\text{shell}-\rho_\text{solv}) \sum_{i=1}^{N} \left[
+     3V(r_i)\frac{\sin(qr_i) - qr_i\cos(qr_i)}{(qr_i)^3}
+     - 3V(R_i)\frac{\sin(qR_i) - qR_i\cos(qR_i)}{(qR_i)^3}
+     \right]
 
 for
 
 .. math::
-    F(q) = (\rho_\text{shell}-\rho_\text{solv}) \sum_{i=1}^{n_\text{pairs}}
-        \left[
-          3V(R_i)\frac{\sin(qR_i)-qR_i\cos(qR_i)}{(qR_i)^3} \\
-          - 3V(R_i+t_s)\frac{\sin(q(R_i+t_s))-q(R_i+t_s)\cos(q(R_i+t_s))}{(q(R_i+t_s))^3}
-        \right]
 
-and
+     r_i &= r_c + (i-1)(t_s + t_w) && \text{ solvent radius before shell } i \\
+     R_i &= r_i + t_s && \text{ shell radius for shell } i
 
-.. math::
-     R_i = r_c + (i-1)(t_s + t_w)
+$\phi$ is the volume fraction of particles, $V(r)$ is the volume of a sphere
+of radius $r$, $r_c$ is the radius of the core, $t_s$ is the thickness of
+the shell, $t_w$ is the thickness of the solvent layer between the shells,
+$\rho_\text{shell}$ is the scattering length density of a shell, and
+$\rho_\text{solv}$ is the scattering length density of the solvent.
 
-where $V_f$ is the volume fraction of particles, $V_t$ is the volume of the
-whole particle, $V(r)$ is the volume of a sphere of radius $r$, $r_c$ is the
-radius of the core, $\rho_\text{shell}$ is the scattering length density of a
-shell, $\rho_\text{solv}$ is the scattering length density of the solvent.
+The outer-most shell radius $R_N$ is used as the effective radius
+for $P(Q)$ when $P(Q) * S(Q)$ is applied.
 
-The outer most radius, $r_o = R_n + t_s$, is used for both the volume fraction
-normalization and for the effective radius for *S(Q)* when $P(Q) * S(Q)$
-is applied.
 
 The 2D scattering intensity is the same as 1D, regardless of the orientation
@@ -86,5 +88,5 @@
     sld_solvent: solvent scattering length density
     sld: shell scattering length density
-    n_pairs:number of "shell plus solvent" layer pairs
+    n_shells:number of "shell plus solvent" layer pairs
     background: incoherent background
         """
@@ -95,17 +97,21 @@
 parameters = [
     ["volfraction", "",  0.05, [0.0, 1],  "", "volume fraction of vesicles"],
-    ["radius", "Ang", 60.0, [0.0, inf],  "", "radius of solvent filled core"],
-    ["thick_shell", "Ang",        10.0, [0.0, inf],  "", "thickness of one shell"],
-    ["thick_solvent", "Ang",        10.0, [0.0, inf],  "", "solvent thickness between shells"],
+    ["radius", "Ang", 60.0, [0.0, inf],  "volume", "radius of solvent filled core"],
+    ["thick_shell", "Ang",        10.0, [0.0, inf],  "volume", "thickness of one shell"],
+    ["thick_solvent", "Ang",        10.0, [0.0, inf],  "volume", "solvent thickness between shells"],
     ["sld_solvent",    "1e-6/Ang^2",  6.4, [-inf, inf], "sld", "solvent scattering length density"],
     ["sld",   "1e-6/Ang^2",  0.4, [-inf, inf], "sld", "Shell scattering length density"],
-    ["n_pairs",     "",            2.0, [1.0, inf],  "", "Number of shell plus solvent layer pairs"],
+    ["n_shells",     "",            2.0, [1.0, inf],  "volume", "Number of shell plus solvent layer pairs"],
     ]
 # pylint: enable=bad-whitespace, line-too-long
 
+# TODO: proposed syntax for specifying which parameters can be polydisperse
+#polydispersity = ["radius", "thick_shell"]
+
 source = ["lib/sas_3j1x_x.c", "multilayer_vesicle.c"]
 
-# TODO: the following line does nothing
-polydispersity = ["radius", "n_pairs"]
+def ER(radius, thick_shell, thick_solvent, n_shells):
+    n_shells = int(n_shells+0.5)
+    return radius + n_shells * (thick_shell + thick_solvent) - thick_solvent
 
 demo = dict(scale=1, background=0,
@@ -116,5 +122,5 @@
             sld_solvent=6.4,
             sld=0.4,
-            n_pairs=2.0)
+            n_shells=2.0)
 
 tests = [
@@ -125,5 +131,5 @@
       'sld_solvent': 6.4,
       'sld': 0.4,
-      'n_pairs': 2.0,
+      'n_shells': 2.0,
       'scale': 1.0,
       'background': 0.001,
@@ -136,5 +142,5 @@
       'sld_solvent': 6.4,
       'sld': 0.4,
-      'n_pairs': 2.0,
+      'n_shells': 2.0,
       'scale': 1.0,
       'background': 0.001,
Index: sasmodels/product.py
===================================================================
--- sasmodels/product.py	(revision 9951a8625001639d10316280a7192f462e4f720a)
+++ sasmodels/product.py	(revision f88e2480698b5dcd90f16c16ecd9d445273a1b9a)
@@ -45,26 +45,29 @@
     # structure factor calculator.  Structure factors should not
     # have any magnetic parameters
-    assert(s_info.parameters.kernel_parameters[0].id == ER_ID)
-    assert(s_info.parameters.kernel_parameters[1].id == VF_ID)
-    assert(s_info.parameters.magnetism_index == [])
+    if not s_info.parameters.kernel_parameters[0].id == ER_ID:
+        raise TypeError("S needs %s as first parameter"%ER_ID)
+    if not s_info.parameters.kernel_parameters[1].id == VF_ID:
+        raise TypeError("S needs %s as second parameter"%VF_ID)
+    if not s_info.parameters.magnetism_index == []:
+        raise TypeError("S should not have SLD parameters")
     p_id, p_name, p_pars = p_info.id, p_info.name, p_info.parameters
     s_id, s_name, s_pars = s_info.id, s_info.name, s_info.parameters
-    p_set = set(p.id for p in p_pars.call_parameters)
-    s_set = set(p.id for p in s_pars.call_parameters)
-
-    if p_set & s_set:
-        # there is some overlap between the parameter names; tag the
-        # overlapping S parameters with name_S.
-        # Skip the first parameter of s, which is effective radius
-        s_list = [(suffix_parameter(par) if par.id in p_set else par)
-                  for par in s_pars.kernel_parameters[1:]]
-    else:
-        # Skip the first parameter of s, which is effective radius
-        s_list = s_pars.kernel_parameters[1:]
+
+    # Create list of parameters for the combined model.  Skip the first
+    # parameter of S, which we verified above is effective radius.  If there
+    # are any names in P that overlap with those in S, modify the name in S
+    # to distinguish it.
+    p_set = set(p.id for p in p_pars.kernel_parameters)
+    s_list = [(_tag_parameter(par) if par.id in p_set else par)
+              for par in s_pars.kernel_parameters[1:]]
+    # Check if still a collision after renaming.  This could happen if for
+    # example S has volfrac and P has both volfrac and volfrac_S.
+    if any(p.id in p_set for p in s_list):
+        raise TypeError("name collision: P has P.name and P.name_S while S has S.name")
+
     translate_name = dict((old.id, new.id) for old, new
                           in zip(s_pars.kernel_parameters[1:], s_list))
     demo = {}
-    demo.update((k, v) for k, v in p_info.demo.items()
-                if k not in ("background", "scale"))
+    demo.update(p_info.demo.items())
     demo.update((translate_name[k], v) for k, v in s_info.demo.items()
                 if k not in ("background", "scale") and not k.startswith(ER_ID))
@@ -90,11 +93,27 @@
     # Remember the component info blocks so we can build the model
     model_info.composition = ('product', [p_info, s_info])
-    model_info.demo = {}
+    model_info.demo = demo
+
+    ## Show the parameter table with the demo values
+    #from .compare import get_pars, parlist
+    #print("==== %s ====="%model_info.name)
+    #values = get_pars(model_info, use_demo=True)
+    #print(parlist(model_info, values, is2d=True))
     return model_info
 
-def suffix_parameter(par, suffix):
+def _tag_parameter(par):
+    """
+    Tag the parameter name with _S to indicate that the parameter comes from
+    the structure factor parameter set.  This is only necessary if the
+    form factor model includes a parameter of the same name as a parameter
+    in the structure factor.
+    """
     par = copy(par)
-    par.name = par.name + " S"
+    # Protect against a vector parameter in S by appending the vector length
+    # to the renamed parameter.  Note: haven't tested this since no existing
+    # structure factor models contain vector parameters.
+    vector_length = par.name[len(par.id):]
     par.id = par.id + "_S"
+    par.name = par.id + vector_length
     return par
 
