Index: doc/guide/gpu_setup.rst
===================================================================
--- doc/guide/gpu_setup.rst	(revision 63602b15f168fcfb37242dc2e94348a4751243a3)
+++ doc/guide/gpu_setup.rst	(revision 8b31efadb6413d7ae55766f7546c483c7538368e)
@@ -94,4 +94,6 @@
 Device Selection
 ================
+**OpenCL drivers**
+
 If you have multiple GPU devices you can tell the program which device to use.
 By default, the program looks for one GPU and one CPU device from available
@@ -104,8 +106,5 @@
 was used to run the model.
 
-**If you don't want to use OpenCL, you can set** *SAS_OPENCL=None*
-**in your environment settings, and it will only use normal programs.**
-
-If you want to use one of the other devices, you can run the following
+If you want to use a specific driver and devices, you can run the following
 from the python console::
 
@@ -115,5 +114,47 @@
 This will provide a menu of different OpenCL drivers available.
 When one is selected, it will say "set PYOPENCL_CTX=..."
-Use that value as the value of *SAS_OPENCL*.
+Use that value as the value of *SAS_OPENCL=driver:device*.
+
+To use the default OpenCL device (rather than CUDA or None),
+set *SAS_OPENCL=opencl*.
+
+In batch queues, you may need to set *XDG_CACHE_HOME=~/.cache* 
+(Linux only) to a different directory, depending on how the filesystem 
+is configured.  You should also set *SAS_DLL_PATH* for CPU-only modules.
+
+    -DSAS_MODELPATH=path sets directory containing custom models
+    -DSAS_OPENCL=vendor:device|cuda:device|none sets the target GPU device
+    -DXDG_CACHE_HOME=~/.cache sets the pyopencl cache root (linux only)
+    -DSAS_COMPILER=tinycc|msvc|mingw|unix sets the DLL compiler
+    -DSAS_OPENMP=1 turns on OpenMP for the DLLs
+    -DSAS_DLL_PATH=path sets the path to the compiled modules
+
+
+**CUDA drivers**
+
+If OpenCL drivers are not available on your system, but NVidia CUDA
+drivers are available, then set *SAS_OPENCL=cuda* or
+*SAS_OPENCL=cuda:n* for a particular device number *n*.  If no device
+number is specified, then the CUDA drivers looks for look for
+*CUDA_DEVICE=n* or a file ~/.cuda-device containing n for the device number.
+
+In batch queues, the SLURM command *sbatch --gres=gpu:1 ...* will set
+*CUDA_VISIBLE_DEVICES=n*, which ought to set the correct device
+number for *SAS_OPENCL=cuda*.  If not, then set
+*CUDA_DEVICE=$CUDA_VISIBLE_DEVICES* within the batch script.  You may
+need to set the CUDA cache directory to a folder accessible across the
+cluster with *PYCUDA_CACHE_DIR* (or *PYCUDA_DISABLE_CACHE* to disable
+caching), and you may need to set environment specific compiler flags
+with *PYCUDA_DEFAULT_NVCC_FLAGS*.  You should also set *SAS_DLL_PATH* 
+for CPU-only modules.
+
+**No GPU support**
+
+If you don't want to use OpenCL or CUDA, you can set *SAS_OPENCL=None*
+in your environment settings, and it will only use normal programs.
+
+In batch queues, you may need to set *SAS_DLL_PATH* to a directory
+accessible on the compute node.
+
 
 Device Testing
@@ -154,3 +195,3 @@
 *Document History*
 
-| 2017-09-27 Paul Kienzle
+| 2018-10-15 Paul Kienzle
Index: doc/guide/plugin.rst
===================================================================
--- doc/guide/plugin.rst	(revision 94bfa4260b733d3fccfaf1e8ee85838ce89b4230)
+++ doc/guide/plugin.rst	(revision 94bfa4260b733d3fccfaf1e8ee85838ce89b4230)
@@ -302,8 +302,8 @@
 
 **Note: The order of the parameters in the definition will be the order of the
-parameters in the user interface and the order of the parameters in Iq(),
-Iqac(), Iqabc() and form_volume(). And** *scale* **and** *background*
-**parameters are implicit to all models, so they do not need to be included
-in the parameter table.**
+parameters in the user interface and the order of the parameters in Fq(), Iq(),
+Iqac(), Iqabc(), form_volume() and shell_volume().
+And** *scale* **and** *background* **parameters are implicit to all models,
+so they do not need to be included in the parameter table.**
 
 - **"name"** is the name of the parameter shown on the FitPage.
@@ -374,6 +374,6 @@
     scattered intensity.
 
-  - "volume" parameters are passed to Iq(), Iqac(), Iqabc() and form_volume(),
-    and have polydispersity loops generated automatically.
+  - "volume" parameters are passed to Fq(), Iq(), Iqac(), Iqabc(), form_volume()
+    and shell_volume(), and have polydispersity loops generated automatically.
 
   - "orientation" parameters are not passed, but instead are combined with
@@ -503,4 +503,16 @@
 used.
 
+Hollow shapes, where the volume fraction of particle corresponds to the
+material in the shell rather than the volume enclosed by the shape, must
+also define a *shell_volume(par1, par2, ...)* function.  The parameters
+are the same as for *form_volume*.  The *I(q)* calculation should use
+*shell_volume* squared as its scale factor for the volume normalization.
+The structure factor calculation needs *form_volume* in order to properly
+scale the volume fraction parameter, so both functions are required for
+hollow shapes.
+
+Note: Pure python models do not yet support direct computation of the
+average of $F(q)$ and $F^2(q)$.
+
 Embedded C Models
 .................
@@ -514,5 +526,4 @@
 This expands into the equivalent C code::
 
-    #include <math.h>
     double Iq(double q, double par1, double par2, ...);
     double Iq(double q, double par1, double par2, ...)
@@ -523,4 +534,7 @@
 *form_volume* defines the volume of the shape. As in python models, it
 includes only the volume parameters.
+
+*form_volume* defines the volume of the shell for hollow shapes. As in
+python models, it includes only the volume parameters.
 
 **source=['fn.c', ...]** includes the listed C source files in the
@@ -559,4 +573,33 @@
 The INVALID define can go into *Iq*, or *c_code*, or an external C file
 listed in *source*.
+
+Structure Factors
+.................
+
+Structure factor calculations may need the underlying $<F(q)>$ and $<F^2(q)>$
+rather than $I(q)$.  This is used to compute $\beta = <F(q)>^2/<F^2(q)>$ in
+the decoupling approximation to the structure factor.
+
+Instead of defining the *Iq* function, models can define *Fq* as
+something like::
+
+    double Fq(double q, double *F1, double *F2, double par1, double par2, ...);
+    double Fq(double q, double *F1, double *F2, double par1, double par2, ...)
+    {
+        // Polar integration loop over all orientations.
+        ...
+        *F1 = 1e-2 * total_F1 * contrast * volume;
+        *F2 = 1e-4 * total_F2 * square(contrast * volume);
+        return I(q, par1, par2, ...);
+    }
+
+If the volume fraction scale factor is built into the model (as occurs for
+the vesicle model, for example), then scale *F1* by $\surd V_f$ so that
+$\beta$ is computed correctly.
+
+Structure factor calculations are not yet supported for oriented shapes.
+
+Note: only available as a separate C file listed in *source*, or within
+a *c_code* block within the python model definition file.
 
 Oriented Shapes
@@ -1023,10 +1066,11 @@
           "radius": 120., "radius_pd": 0.2, "radius_pd_n":45},
          0.2, 0.228843],
-        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "ER", 120.],
-        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "VR", 1.],
+        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45},
+         0.1, None, None, 120., None, 1.],  # q, F, F^2, R_eff, V, form:shell
+        [{"@S": "hardsphere"}, 0.1, None],
     ]
 
 
-**tests=[[{parameters}, q, result], ...]** is a list of lists.
+**tests=[[{parameters}, q, Iq], ...]** is a list of lists.
 Each list is one test and contains, in order:
 
@@ -1040,7 +1084,13 @@
 - input and output values can themselves be lists if you have several
   $q$ values to test for the same model parameters.
-- for testing *ER* and *VR*, give the inputs as "ER" and "VR" respectively;
-  the output for *VR* should be the sphere/shell ratio, not the individual
-  sphere and shell values.
+- for testing effective radius, volume and form:shell volume ratio, use the
+  extended form of the tests results, with *None, None, R_eff, V, V_r*
+  instead of *Iq*.  This calls the kernel *Fq* function instead of *Iq*.
+- for testing F and F^2 (used for beta approximation) do the same as the
+  effective radius test, but include values for the first two elements,
+  $<F(q)>$ and $<F^2(q)>$.
+- for testing interaction between form factor and structure factor, specify
+  the structure factor name in the parameters as *{"@S": "name", ...}* with
+  the remaining list of parameters defined by the *P@S* product model.
 
 .. _Test_Your_New_Model:
Index: doc/guide/scripting.rst
===================================================================
--- doc/guide/scripting.rst	(revision bd7630de7da8bd67aa24b8fc036b2dcc1bc72a16)
+++ doc/guide/scripting.rst	(revision 23df8335e23a3bb960bb8c3ef9dc709fb7429652)
@@ -188,20 +188,47 @@
 python kernel.  Once the kernel is in hand, we can then marshal a set of
 parameters into a :class:`sasmodels.details.CallDetails` object and ship it to
-the kernel using the :func:`sansmodels.direct_model.call_kernel` function.  An
-example should help, *example/cylinder_eval.py*::
-
-    from numpy import logspace
+the kernel using the :func:`sansmodels.direct_model.call_kernel` function.  To
+accesses the underlying $<F(q)>$ and $<F^2(q)>$, use
+:func:`sasmodels.direct_model.call_Fq` instead.
+
+The following example should
+help, *example/cylinder_eval.py*::
+
+    from numpy import logspace, sqrt
     from matplotlib import pyplot as plt
     from sasmodels.core import load_model
-    from sasmodels.direct_model import call_kernel
+    from sasmodels.direct_model import call_kernel, call_Fq
 
     model = load_model('cylinder')
     q = logspace(-3, -1, 200)
     kernel = model.make_kernel([q])
-    Iq = call_kernel(kernel, dict(radius=200.))
-    plt.loglog(q, Iq)
+    pars = {'radius': 200, 'radius_pd': 0.1, 'scale': 2}
+    Iq = call_kernel(kernel, pars)
+    F, Fsq, Reff, V, Vratio = call_Fq(kernel, pars)
+
+    plt.loglog(q, Iq, label='2 I(q)')
+    plt.loglog(q, F**2/V, label='<F(q)>^2/V')
+    plt.loglog(q, Fsq/V, label='<F^2(q)>/V')
+    plt.xlabel('q (1/A)')
+    plt.ylabel('I(q) (1/cm)')
+    plt.title('Cylinder with radius 200.')
+    plt.legend()
     plt.show()
 
-On windows, this can be called from the cmd prompt using sasview as::
+.. figure:: direct_call.png
+
+    Comparison between $I(q)$, $<F(q)>$ and $<F^2(q)>$ for cylinder model.
+
+This compares $I(q)$ with $<F(q)>$ and $<F^2(q)>$ for a cylinder
+with *radius=200 +/- 20* and *scale=2*. Note that *call_Fq* does not
+include scale and background, nor does it normalize by the average volume.
+The definition of $F = \rho V \hat F$ scaled by the contrast and
+volume, compared to the canonical cylinder $\hat F$, with $\hat F(0) = 1$.
+Integrating over polydispersity and orientation, the returned values are
+$\sum_{r,w\in N(r_o, r_o/10)} \sum_\theta w F(q,r_o,\theta)\sin\theta$ and
+$\sum_{r,w\in N(r_o, r_o/10)} \sum_\theta w F^2(q,r_o,\theta)\sin\theta$.
+
+On windows, this example can be called from the cmd prompt using sasview as
+as the python interpreter::
 
     SasViewCom example/cylinder_eval.py
