Index: sasmodels/gen.py
===================================================================
--- sasmodels/gen.py	(revision 32c160aab45a38358aa878cf4622c2cec2d87725)
+++ sasmodels/gen.py	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -1,9 +1,132 @@
-__all__ = ["make_opencl"]
+"""
+SAS model constructor.
+
+Small angle scattering models are defined by a set of kernel functions:
+
+    *Iq(q, p1, p2, ...)* returns the scattering at q for a form with
+    particular dimensions averaged over all orientations.
+
+    *Iqxy(qx, qy, p1, p2, ...)* returns the scattering at qx,qy for a form
+    with particular dimensions for a single orientation.
+
+    *Imagnetic(qx, qy, result[], p1, p2, ...)* returns the scattering for the
+    polarized neutron spin states (up-up, up-down, down-up, down-down) for
+    a form with particular dimensions for a single orientation.
+
+    *form_volume(p1, p2, ...)* returns the volume of the form with particular
+    dimension.
+
+    *ER(p1, p2, ...)* returns the effective radius of the form with
+    particular dimensions.
+
+    *VR(p1, p2, ...)* returns the volume ratio for core-shell style forms.
+
+These functions are defined in a kernel module .py script and an associated
+set of .c files.  The model constructor will use them to create models with
+polydispersity across volume and orientation parameters, and provide
+scale and background parameters for each model.
+
+*Iq*, *Iqxy*, *Imagnetic* and *form_volume* should be stylized C-99
+functions written for OpenCL.  Floating point values should be
+declared as *real*.  Depending on how the function is called, a macro
+will replace *real* with *float* or *double*.  Unfortunately, MacOSX
+is picky about floating point constants, which should be defined with
+value + 'f' if they are of type *float* or just a bare value if they
+are of type *double*.  The solution is a macro *REAL(value)* which
+adds the 'f' if compiling for single precision floating point.  This
+does make the code ugly, and may someday be replaced by a clever
+regular expression which does the same job.  OpenCL has a *sincos*
+function which can improve performance when both the *sin* and *cos*
+values are needed for a particular argument.  Since this function
+does not exist in C-99, all use of *sincos* should be replaced by the
+macro *SINCOS(value,sn,cn)* where *sn* and *cn* are previously declared
+*real* values.  *value* may be an expression.  When compiled for systems
+without OpenCL, *SINCOS* will be replaced by *sin* and *cos* calls.  All
+functions need prototype declarations even if the are defined before they
+are used -- another present from MacOSX.  OpenCL does not support
+*#include* preprocessor directives; instead the includes must be listed
+in the kernel metadata, with functions defined before they are used.
+The included files should be listed using relative path to the kernel
+source file, or if using one of the standard models, relative to the
+sasmodels source files.
+
+*ER* and *VR* are python functions which operate on parameter vectors.
+The constructor code will generate the necessary vectors for computing
+them with the desired polydispersity.
+
+The kernel module must set variables defining the kernel meta data:
+
+    *name* is the model name
+
+    *title* is a short description of the model, suitable for a tool tip,
+    or a one line model summary in a table of models.
+
+    *description* is an extended description of the model to be displayed
+    while the model parameters are being edited.
+
+    *parameters* is a list of parameters.  Each parameter is itself a
+    list containing *name*, *units*, *default value*,
+    [*lower bound*, *upper bound*], *type* and *description*.
+
+    *source* is the list of C-99 source files that must be joined to
+    create the OpenCL kernel functions.  The files defining the functions
+    need to be listed before the files which use the functions.
+
+    *ER* is a python function defining the effective radius.  If it is
+    not present, the effective radius is 0.
+
+    *VR* is a python function defining the volume ratio.  If it is not
+    present, the volume ratio is 1.
+
+The doc string at the start of the kernel module will be used to
+construct the model documentation web pages.  Embedded figures should
+appear in the subdirectory "img" beside the model definition, and tagged
+with the kernel module name to avoid collision with other models.  Some
+file systems are case-sensitive, so only use lower case characters for
+file names and extensions.
+
+Parameters are defined as follows:
+
+    *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
+    should be lower case, with words separated by underscore.  If
+    acronyms are used, the whole acronym should be upper case.
+
+    *units* should be one of *degrees* for angles, *Ang* for lengths,
+    *1e-6/Ang^2* for SLDs.
+
+    *default value* will be the initial value for  the model when it
+    is selected, or when an initial value is not otherwise specified.
+
+    *limits* are the valid bounds of the parameter, 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
+    the fit limits, but not outside the hard limits specified in the model.
+    If there are no limits, use +/-inf imported from numpy.
+
+    *type* indicates how the parameter will be used.  "volume" parameters
+    will be used in all functions.  "orientation" parameters will be used
+    in *Iqxy* and *Imagnetic*.  "magnetic* parameters will be used in
+    *Imagnetic* only.  If *type* is none, the parameter will be used in
+    all of *Iq*, *Iqxy* and *Imagnetic*.  This will probably be a
+    is the empty string if the parameter is used in all model calculations,
+    it is "volu
+
+    *description* is a short description of the parameter.  This will
+    be displayed in the parameter table and used as a tool tip for the
+    parameter value in the user interface.
+
+The function :func:`make` loads the metadata from the module and returns
+the kernel source.  The function :func:`doc` extracts
+"""
+
+# TODO: identify model files which have changed since loading and reload them.
+
+__all__ = ["make, doc"]
 
 import os.path
 
 import numpy as np
-
-from .jsonutil import relaxed_loads
 
 F64 = np.dtype('float64')
@@ -183,4 +306,20 @@
   norm_vol += vol_weight;"""
 
+# Documentation header for the module, giving the model name, its short
+# description and its parameter table.  The remainder of the doc comes
+# from the module docstring.
+DOC_HEADER=""".. _%(name)s:
+
+%(name)s
+=======================================================
+
+%(title)s
+
+%(parameters)s
+
+The returned value is scaled to units of |cm^-1|.
+
+%(docs)s
+"""
 
 def indent(s, depth):
@@ -389,8 +528,9 @@
 def make(kernel_module):
     """
-    Build an OpenCL function from the source in *kernelfile*.
-
-    The kernel file needs to define metadata about the parameters.  This
-    will be a JSON definition containing
+    Build an OpenCL/ctypes function from the definition in *kernel_module*.
+
+    The module can be loaded with a normal python import statement if you
+    know which module you need, or with __import__('sasmodels.model.'+name)
+    if the name is in a string.
     """
     # TODO: allow Iq and Iqxy to be defined in python
@@ -416,4 +556,14 @@
     return source, info
 
+def doc(kernel_module):
+    """
+    Return the documentation for the model.
+    """
+    subst = dict(name=kernel_module.name,
+                 title=kernel_module.title,
+                 parameters=make_partable(kernel_module.parameters),
+                 doc=kernel_module.__doc__)
+    return DOC_HEADER%subst
+
 
 def demo_time():
Index: sasmodels/models/README.rst
===================================================================
--- sasmodels/models/README.rst	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
+++ sasmodels/models/README.rst	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -0,0 +1,34 @@
+cylinder.c + cylinder.py is the cylinder model with renamed variables and
+sld scaled by 1e6 so the numbers are nicer.  The model name is "cylinder"
+
+cylinder_clone.c + cylinder_clone.py is the cylinder model using the
+same interface as the sasview, including calling the model CylinderModel,
+so that it can be used as a drop-in replacement for the sasview cylinder
+model.
+
+cylindermodel_onefile.py is cylinder.c+cylinder.py merged into one file.
+This doesn't actually run yet since sasmodels.gen has not been updated
+to support it.  It exists as a proposal.  Note that the function declaration
+has been removed since there is enough information in the parameter
+definitions to generate it automatically.  Note also that "source" which
+used to be all the source has been renamed "includes".
+
+One-file models could coexist with the py+c file models by checking for the
+existence of c_blah and creating the appropriate function wrappers.  These
+would be appended after any include files.  You shouldn't mix the two forms
+within a single model since form_volume needs to be defined before
+Iq/Iqxy but after the libraries.
+
+Note: may want to rename form_volume to calc_volume and Iq/Iqxy to
+calc_Iq/calc_Iqxy in both the c+py and the one file forms so that the
+names are more predictable.  Similarly ER/VR go to calc_ER/calc_VR.
+
+Note: It is possible to translate python code automatically to opencl, using
+something like numba, clyther, shedskin or pypy.
+
+Magnetism hasn't been implemented yet.  We may want a separate Imagnetic
+calculator with the extra parameters and calculations.   We should
+return all desired spin states together so we can share the work of
+computing the form factors for the different magnetic contrasts.  This
+will mean extending the data handler to support multiple cross sections
+in the same data set.
Index: sasmodels/models/cylinder.c
===================================================================
--- sasmodels/models/cylinder.c	(revision 1f21edfa7a55a09027b911fba80c71d4978cb876)
+++ sasmodels/models/cylinder.c	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -1,147 +1,5 @@
-/* PARAMETERS
-{
-name: "cylinder",
-title: "Cylinder with uniform scattering length density",
-include: [ "lib/J1.c", "lib/gauss76.c", "lib/cylkernel.c" ],
-parameters: [
-   // [ "name", "units", default, [lower, upper], "type", "description" ],
-   [ "sld", "1e-6/Ang^2", 4, [-Infinity,Infinity], "",
-     "Cylinder scattering length density" ],
-   [ "solvent_sld", "1e-6/Ang^2", 1, [-Infinity,Infinity], "",
-     "Solvent scattering length density" ],
-   [ "radius", "Ang",  20, [0, Infinity], "volume",
-     "Cylinder radius" ],
-   [ "length", "Ang",  400, [0, Infinity], "volume",
-     "Cylinder length" ],
-   [ "theta", "degrees", 60, [-Infinity, Infinity], "orientation",
-     "In plane angle" ],
-   [ "phi", "degrees", 60, [-Infinity, Infinity], "orientation",
-     "Out of plane angle" ],
-],
-}
-PARAMETERS END
-
-DOCUMENTATION
-.. _CylinderModel:
-
-CylinderModel
-=============
-
-This model provides the form factor for a right circular cylinder with uniform
-scattering length density. The form factor is normalized by the particle volume.
-
-For information about polarised and magnetic scattering, click here_.
-
-Definition
-----------
-
-The output of the 2D scattering intensity function for oriented cylinders is
-given by (Guinier, 1955)
-
-.. math::
-
-    P(q,\alpha) = \frac{\text{scale}}{V}f^2(q) + \text{bkg}
-
-where
-
-.. math::
-
-    f(q) = 2 (\Delta \rho) V
-           \frac{\sin (q L/2 \cos \alpha)}{q L/2 \cos \alpha}
-           \frac{J_1 (q r \sin \alpha)}{q r \sin \alpha}
-
-and $\alpha$ is the angle between the axis of the cylinder and $\vec q$, $V$
-is the volume of the cylinder, $L$ is the length of the cylinder, $r$ is the
-radius of the cylinder, and $d\rho$ (contrast) is the scattering length density
-difference between the scatterer and the solvent. $J_1$ is the first order
-Bessel function.
-
-To provide easy access to the orientation of the cylinder, we define the
-axis of the cylinder using two angles $\theta$ and $\phi$. Those angles
-are defined in Figure :num:`figure #CylinderModel-orientation`.
-
-.. _CylinderModel-orientation:
-
-.. figure:: img/image061.JPG
-
-    Definition of the angles for oriented cylinders.
-
-.. figure:: img/image062.JPG
-
-    Examples of the angles for oriented pp against the detector plane.
-
-NB: The 2nd virial coefficient of the cylinder is calculated based on the
-radius and length values, and used as the effective radius for $S(Q)$
-when $P(Q) \cdot S(Q)$ is applied.
-
-The returned value is scaled to units of |cm^-1| and the parameters of
-the CylinderModel are the following:
-
-%(parameters)s
-
-The output of the 1D scattering intensity function for randomly oriented
-cylinders is then given by
-
-.. math::
-
-    P(q) = \frac{\text{scale}}{V}
-        \int_0^{\pi/2} f^2(q,\alpha) \sin \alpha d\alpha + \text{background}
-
-The *theta* and *phi* parameters are not used for the 1D output. Our
-implementation of the scattering kernel and the 1D scattering intensity
-use the c-library from NIST.
-
-Validation of the CylinderModel
--------------------------------
-
-Validation of our code was done by comparing the output of the 1D model
-to the output of the software provided by the NIST (Kline, 2006).
-Figure :num:`figure #CylinderModel-compare` shows a comparison of
-the 1D output of our model and the output of the NIST software.
-
-.. _CylinderModel-compare:
-
-.. figure:: img/image065.JPG
-
-    Comparison of the SasView scattering intensity for a cylinder with the
-    output of the NIST SANS analysis software.
-    The parameters were set to: *Scale* = 1.0, *Radius* = 20 |Ang|,
-    *Length* = 400 |Ang|, *Contrast* = 3e-6 |Ang^-2|, and
-    *Background* = 0.01 |cm^-1|.
-
-In general, averaging over a distribution of orientations is done by
-evaluating the following
-
-.. math::
-
-    P(q) = \int_0^{\pi/2} d\phi
-        \int_0^\pi p(\theta, \phi) P_0(q,\alpha) \sin \theta d\theta
-
-
-where $p(\theta,\phi)$ is the probability distribution for the orientation
-and $P_0(q,\alpha)$ is the scattering intensity for the fully oriented
-system. Since we have no other software to compare the implementation of
-the intensity for fully oriented cylinders, we can compare the result of
-averaging our 2D output using a uniform distribution $p(\theta, \phi) = 1.0$.
-Figure :num:`figure #CylinderModel-crosscheck` shows the result of
-such a cross-check.
-
-.. _CylinderModel-crosscheck:
-
-.. figure:: img/image066.JPG
-
-    Comparison of the intensity for uniformly distributed cylinders
-    calculated from our 2D model and the intensity from the NIST SANS
-    analysis software.
-    The parameters used were: *Scale* = 1.0, *Radius* = 20 |Ang|,
-    *Length* = 400 |Ang|, *Contrast* = 3e-6 |Ang^-2|, and
-    *Background* = 0.0 |cm^-1|.
-
-DOCUMENTATION END
-*/
 real form_volume(real radius, real length);
 real Iq(real q, real sld, real solvent_sld, real radius, real length);
 real Iqxy(real qx, real qy, real sld, real solvent_sld, real radius, real length, real theta, real phi);
-
 
 real form_volume(real radius, real length)
Index: sasmodels/models/cylinder.py
===================================================================
--- sasmodels/models/cylinder.py	(revision 32c160aab45a38358aa878cf4622c2cec2d87725)
+++ sasmodels/models/cylinder.py	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -1,8 +1,5 @@
+# Note: model title and parameter table are inserted automatically
 r"""
-CylinderModel
-=============
-
-This model provides the form factor for a right circular cylinder with uniform
-scattering length density. The form factor is normalized by the particle volume.
+The form factor is normalized by the particle volume.
 
 For information about polarised and magnetic scattering, click here_.
@@ -38,5 +35,5 @@
 .. _CylinderModel-orientation:
 
-.. figure:: img/image061.JPG
+.. figure:: img/image061.JPG   (should be img/cylinder-1.jpg, or img/cylinder-orientation.jpg)
 
     Definition of the angles for oriented cylinders.
@@ -49,9 +46,4 @@
 radius and length values, and used as the effective radius for $S(Q)$
 when $P(Q) \cdot S(Q)$ is applied.
-
-The returned value is scaled to units of |cm^-1| and the parameters of
-the CylinderModel are the following:
-
-%(parameters)s
 
 The output of the 1D scattering intensity function for randomly oriented
@@ -67,6 +59,6 @@
 use the c-library from NIST.
 
-Validation of the CylinderModel
--------------------------------
+Validation
+----------
 
 Validation of our code was done by comparing the output of the 1D model
@@ -116,44 +108,43 @@
 from numpy import pi, inf
 
+name = "cylinder"
+title = "Right circular cylinder with uniform scattering length density."
+description = """
+     f(q)= 2*(sldCyl - sldSolv)*V*sin(qLcos(alpha/2))
+            /[qLcos(alpha/2)]*J1(qRsin(alpha/2))/[qRsin(alpha)]
+
+            P(q,alpha)= scale/V*f(q)^(2)+background
+            V: Volume of the cylinder
+            R: Radius of the cylinder
+            L: Length of the cylinder
+            J1: The bessel function
+            alpha: angle betweenthe axis of the
+            cylinder and the q-vector for 1D
+            :the ouput is P(q)=scale/V*integral
+            from pi/2 to zero of...
+            f(q)^(2)*sin(alpha)*dalpha+ bkg
+    """
+
+parameters = [
+#   [ "name", "units", default, [lower, upper], "type",
+#     "description" ],
+    [ "sld", "1e-6/Ang^2", 4, [-inf,inf], "",
+      "Cylinder scattering length density" ],
+    [ "solvent_sld", "1e-6/Ang^2", 1, [-inf,inf], "",
+      "Solvent scattering length density" ],
+    [ "radius", "Ang",  20, [0, inf], "volume",
+      "Cylinder radius" ],
+    [ "length", "Ang",  400, [0, inf], "volume",
+      "Cylinder length" ],
+    [ "theta", "degrees", 60, [-inf, inf], "orientation",
+      "In plane angle" ],
+    [ "phi", "degrees", 60, [-inf, inf], "orientation",
+      "Out of plane angle" ],
+    ]
+
+source = [ "lib/J1.c", "lib/gauss76.c", "lib/cylkernel.c", "cylinder.c"]
+
 def ER(radius, length):
     ddd = 0.75*radius*(2*radius*length + (length+radius)*(length+pi*radius))
     return 0.5 * (ddd)**(1./3.)
 
-INFO = {
-    "name": "cylinder",
-    "title": "Cylinder with uniform scattering length density",
-    "source": [ "lib/J1.c", "lib/gauss76.c", "lib/cylkernel.c", "cylinder.c"],
-    "parameters": [
-    #   [ "name", "units", default, [lower, upper], "type",
-    #     "description" ],
-        [ "sld", "1e-6/Ang^2", 4, [-inf,inf], "",
-          "Cylinder scattering length density" ],
-        [ "solvent_sld", "1e-6/Ang^2", 1, [-inf,inf], "",
-          "Solvent scattering length density" ],
-        [ "radius", "Ang",  20, [0, inf], "volume",
-          "Cylinder radius" ],
-        [ "length", "Ang",  400, [0, inf], "volume",
-          "Cylinder length" ],
-        [ "theta", "degrees", 60, [-inf, inf], "orientation",
-          "In plane angle" ],
-        [ "phi", "degrees", 60, [-inf, inf], "orientation",
-          "Out of plane angle" ],
-        ],
-    "description": """
-         f(q)= 2*(sldCyl - sldSolv)*V*sin(qLcos(alpha/2))
-                /[qLcos(alpha/2)]*J1(qRsin(alpha/2))/[qRsin(alpha)]
-
-                P(q,alpha)= scale/V*f(q)^(2)+background
-                V: Volume of the cylinder
-                R: Radius of the cylinder
-                L: Length of the cylinder
-                J1: The bessel function
-                alpha: angle betweenthe axis of the
-                cylinder and the q-vector for 1D
-                :the ouput is P(q)=scale/V*integral
-                from pi/2 to zero of...
-                f(q)^(2)*sin(alpha)*dalpha+ bkg
-        """,
-    "ER": ER,
-    }
-
Index: sasmodels/models/cylinder_clone.py
===================================================================
--- sasmodels/models/cylinder_clone.py	(revision 32c160aab45a38358aa878cf4622c2cec2d87725)
+++ sasmodels/models/cylinder_clone.py	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -118,5 +118,20 @@
 name = "CylinderModel"
 title = "Cylinder with uniform scattering length density"
-source = [ "lib/J1.c", "lib/gauss76.c", "lib/cylkernel.c", "cylinder_clone.c"]
+description = """\
+         f(q)= 2*(sldCyl - sldSolv)*V*sin(qLcos(alpha/2))
+                /[qLcos(alpha/2)]*J1(qRsin(alpha/2))/[qRsin(alpha)]
+
+                P(q,alpha)= scale/V*f(q)^(2)+background
+                V: Volume of the cylinder
+                R: Radius of the cylinder
+                L: Length of the cylinder
+                J1: The bessel function
+                alpha: angle betweenthe axis of the
+                cylinder and the q-vector for 1D
+                :the ouput is P(q)=scale/V*integral
+                from pi/2 to zero of...
+                f(q)^(2)*sin(alpha)*dalpha+ bkg
+"""
+
 parameters = [
     #   [ "name", "units", default, [lower, upper], "type",
@@ -135,19 +150,5 @@
       "Out of plane angle" ],
     ]
-description = """\
-         f(q)= 2*(sldCyl - sldSolv)*V*sin(qLcos(alpha/2))
-                /[qLcos(alpha/2)]*J1(qRsin(alpha/2))/[qRsin(alpha)]
-
-                P(q,alpha)= scale/V*f(q)^(2)+background
-                V: Volume of the cylinder
-                R: Radius of the cylinder
-                L: Length of the cylinder
-                J1: The bessel function
-                alpha: angle betweenthe axis of the
-                cylinder and the q-vector for 1D
-                :the ouput is P(q)=scale/V*integral
-                from pi/2 to zero of...
-                f(q)^(2)*sin(alpha)*dalpha+ bkg
-"""
+source = [ "lib/J1.c", "lib/gauss76.c", "lib/cylkernel.c", "cylinder_clone.c"]
 
 def ER(radius, length):
Index: sasmodels/models/cylinder_onefile.py
===================================================================
--- sasmodels/models/cylinder_onefile.py	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
+++ sasmodels/models/cylinder_onefile.py	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -0,0 +1,211 @@
+# This is how a model would look if we were to stick it all into one file.
+r"""
+CylinderModel
+=============
+
+This model provides the form factor for a right circular cylinder with uniform
+scattering length density. The form factor is normalized by the particle volume.
+
+For information about polarised and magnetic scattering, click here_.
+
+Definition
+----------
+
+The output of the 2D scattering intensity function for oriented cylinders is
+given by (Guinier, 1955)
+
+.. math::
+
+    P(q,\alpha) = \frac{\text{scale}}{V}f^2(q) + \text{bkg}
+
+where
+
+.. math::
+
+    f(q) = 2 (\Delta \rho) V
+           \frac{\sin (q L/2 \cos \alpha)}{q L/2 \cos \alpha}
+           \frac{J_1 (q r \sin \alpha)}{q r \sin \alpha}
+
+and $\alpha$ is the angle between the axis of the cylinder and $\vec q$, $V$
+is the volume of the cylinder, $L$ is the length of the cylinder, $r$ is the
+radius of the cylinder, and $d\rho$ (contrast) is the scattering length density
+difference between the scatterer and the solvent. $J_1$ is the first order
+Bessel function.
+
+To provide easy access to the orientation of the cylinder, we define the
+axis of the cylinder using two angles $\theta$ and $\phi$. Those angles
+are defined in Figure :num:`figure #CylinderModel-orientation`.
+
+.. _CylinderModel-orientation:
+
+.. figure:: img/image061.JPG
+
+    Definition of the angles for oriented cylinders.
+
+.. figure:: img/image062.JPG
+
+    Examples of the angles for oriented pp against the detector plane.
+
+NB: The 2nd virial coefficient of the cylinder is calculated based on the
+radius and length values, and used as the effective radius for $S(Q)$
+when $P(Q) \cdot S(Q)$ is applied.
+
+The returned value is scaled to units of |cm^-1| and the parameters of
+the CylinderModel are the following:
+
+%(parameters)s
+
+The output of the 1D scattering intensity function for randomly oriented
+cylinders is then given by
+
+.. math::
+
+    P(q) = \frac{\text{scale}}{V}
+        \int_0^{\pi/2} f^2(q,\alpha) \sin \alpha d\alpha + \text{background}
+
+The *theta* and *phi* parameters are not used for the 1D output. Our
+implementation of the scattering kernel and the 1D scattering intensity
+use the c-library from NIST.
+
+Validation of the CylinderModel
+-------------------------------
+
+Validation of our code was done by comparing the output of the 1D model
+to the output of the software provided by the NIST (Kline, 2006).
+Figure :num:`figure #CylinderModel-compare` shows a comparison of
+the 1D output of our model and the output of the NIST software.
+
+.. _CylinderModel-compare:
+
+.. figure:: img/image065.JPG
+
+    Comparison of the SasView scattering intensity for a cylinder with the
+    output of the NIST SANS analysis software.
+    The parameters were set to: *Scale* = 1.0, *Radius* = 20 |Ang|,
+    *Length* = 400 |Ang|, *Contrast* = 3e-6 |Ang^-2|, and
+    *Background* = 0.01 |cm^-1|.
+
+In general, averaging over a distribution of orientations is done by
+evaluating the following
+
+.. math::
+
+    P(q) = \int_0^{\pi/2} d\phi
+        \int_0^\pi p(\theta, \phi) P_0(q,\alpha) \sin \theta d\theta
+
+
+where $p(\theta,\phi)$ is the probability distribution for the orientation
+and $P_0(q,\alpha)$ is the scattering intensity for the fully oriented
+system. Since we have no other software to compare the implementation of
+the intensity for fully oriented cylinders, we can compare the result of
+averaging our 2D output using a uniform distribution $p(\theta, \phi) = 1.0$.
+Figure :num:`figure #CylinderModel-crosscheck` shows the result of
+such a cross-check.
+
+.. _CylinderModel-crosscheck:
+
+.. figure:: img/image066.JPG
+
+    Comparison of the intensity for uniformly distributed cylinders
+    calculated from our 2D model and the intensity from the NIST SANS
+    analysis software.
+    The parameters used were: *Scale* = 1.0, *Radius* = 20 |Ang|,
+    *Length* = 400 |Ang|, *Contrast* = 3e-6 |Ang^-2|, and
+    *Background* = 0.0 |cm^-1|.
+"""
+
+from numpy import pi, inf
+
+name = "cylinder"
+title = "Cylinder with uniform scattering length density"
+description = """
+     f(q)= 2*(sldCyl - sldSolv)*V*sin(qLcos(alpha/2))
+            /[qLcos(alpha/2)]*J1(qRsin(alpha/2))/[qRsin(alpha)]
+
+            P(q,alpha)= scale/V*f(q)^(2)+background
+            V: Volume of the cylinder
+            R: Radius of the cylinder
+            L: Length of the cylinder
+            J1: The bessel function
+            alpha: angle betweenthe axis of the
+            cylinder and the q-vector for 1D
+            :the ouput is P(q)=scale/V*integral
+            from pi/2 to zero of...
+            f(q)^(2)*sin(alpha)*dalpha+ bkg
+    """
+
+parameters = [
+#   [ "name", "units", default, [lower, upper], "type",
+#     "description" ],
+    [ "sld", "1e-6/Ang^2", 4, [-inf,inf], "",
+      "Cylinder scattering length density" ],
+    [ "solvent_sld", "1e-6/Ang^2", 1, [-inf,inf], "",
+      "Solvent scattering length density" ],
+    [ "radius", "Ang",  20, [0, inf], "volume",
+      "Cylinder radius" ],
+    [ "length", "Ang",  400, [0, inf], "volume",
+      "Cylinder length" ],
+    [ "theta", "degrees", 60, [-inf, inf], "orientation",
+      "In plane angle" ],
+    [ "phi", "degrees", 60, [-inf, inf], "orientation",
+      "Out of plane angle" ],
+    ]
+
+source = [ "lib/J1.c", "lib/gauss76.c", "lib/cylkernel.c" ]
+
+c_form_volume = """
+    return M_PI*radius*radius*length;
+"""
+
+c_Iq = """
+    const real h = REAL(0.5)*length;
+    real summ = REAL(0.0);
+    for (int i=0; i<76 ;i++) {
+        //const real zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
+        const real zi = REAL(0.5)*(Gauss76Z[i]*M_PI_2 + M_PI_2);
+        summ += Gauss76Wt[i] * CylKernel(q, radius, h, zi);
+    }
+    //const real form = (uplim-lolim)/2.0*summ;
+    const real form = summ * M_PI_4;
+
+    // Multiply by contrast^2, normalize by cylinder volume and convert to cm-1
+    // NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
+    // The additional volume factor is for polydisperse volume normalization.
+    const real s = (sld - solvent_sld) * form_volume(radius, length);
+    return REAL(1.0e-4) * form * s * s;
+"""
+
+c_Iqxy = """
+    real sn, cn; // slots to hold sincos function output
+
+    // Compute angle alpha between q and the cylinder axis
+    SINCOS(theta*M_PI_180, sn, cn);
+    // # The following correction factor exists in sasview, but it can't be
+    // # right, so we are leaving it out for now.
+    // const real correction = fabs(cn)*M_PI_2;
+    const real q = sqrt(qx*qx+qy*qy);
+    const real cos_val = cn*cos(phi*M_PI_180)*(qx/q) + sn*(qy/q);
+    const real alpha = acos(cos_val);
+
+    // The following is CylKernel() / sin(alpha), but we are doing it in place
+    // to avoid sin(alpha)/sin(alpha) for alpha = 0.  It is also a teensy bit
+    // faster since we don't mulitply and divide sin(alpha).
+    SINCOS(alpha, sn, cn);
+    const real besarg = q*radius*sn;
+    const real siarg = REAL(0.5)*q*length*cn;
+    // lim_{x->0} J1(x)/x = 1/2,   lim_{x->0} sin(x)/x = 1
+    const real bj = (besarg == REAL(0.0) ? REAL(0.5) : J1(besarg)/besarg);
+    const real si = (siarg == REAL(0.0) ? REAL(1.0) : sin(siarg)/siarg);
+    const real form = REAL(4.0)*bj*bj*si*si;
+
+    // Multiply by contrast^2, normalize by cylinder volume and convert to cm-1
+    // NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
+    // The additional volume factor is for polydisperse volume normalization.
+    const real s = (sld - solvent_sld) * form_volume(radius, length);
+    return REAL(1.0e-4) * form * s * s; // * correction;
+"""
+
+def ER(radius, length):
+    ddd = 0.75*radius*(2*radius*length + (length+radius)*(length+pi*radius))
+    return 0.5 * (ddd)**(1./3.)
+
Index: sasmodels/sasview_model.py
===================================================================
--- sasmodels/sasview_model.py	(revision 32c160aab45a38358aa878cf4622c2cec2d87725)
+++ sasmodels/sasview_model.py	(revision a7684e5745716d713f91b1ebc1027632a3ff9d36)
@@ -8,12 +8,7 @@
     model =  opencl_model(kernel_module, dtype=dtype)
     def __init__(self, multfactor=1):
-        SasviewModel.__init__(self, self.kernel)
-    attrs = dict(__init__=__init__, kernel=model)
+        SasviewModel.__init__(self, model)
+    attrs = dict(__init__=__init__)
     ConstructedModel = type(model.info['name'],  (SasviewModel,), attrs)
-    #class ConstructedModel(SasviewModel):
-    #    kernel = model
-    #    def __init__(self, multfactor=1):
-    #        SasviewModel.__init__(self, self.kernel)
-    #ConstructedModel.__name__ = model.info['name']
     return ConstructedModel
 
