Index: sasmodels/compare.py
===================================================================
--- sasmodels/compare.py	(revision 4de145843b2267c4f1e8be16517c48de601151b6)
+++ sasmodels/compare.py	(revision 4de145843b2267c4f1e8be16517c48de601151b6)
@@ -1152,5 +1152,5 @@
         'rel_err'   : True,
         'explore'   : False,
-        'use_demo'  : True,
+        'use_demo'  : False,
         'zero'      : False,
         'html'      : False,
Index: sasmodels/direct_model.py
===================================================================
--- sasmodels/direct_model.py	(revision 5024a563075fb86e48bd868acf2f39ea4af2e90b)
+++ sasmodels/direct_model.py	(revision 5024a563075fb86e48bd868acf2f39ea4af2e90b)
@@ -332,5 +332,6 @@
 
         # Need to pull background out of resolution for multiple scattering
-        background = pars.get('background', DEFAULT_BACKGROUND)
+        default_background = self._model.info.parameters.common_parameters[1].default
+        background = pars.get('background', default_background)
         pars = pars.copy()
         pars['background'] = 0.
Index: sasmodels/generate.py
===================================================================
--- sasmodels/generate.py	(revision cd289474f05b7a39cccd795f21f84befdf2a8788)
+++ sasmodels/generate.py	(revision cd289474f05b7a39cccd795f21f84befdf2a8788)
@@ -1006,5 +1006,6 @@
         pars = model_info.parameters.kernel_parameters
     else:
-        pars = model_info.parameters.COMMON + model_info.parameters.kernel_parameters
+        pars = (model_info.parameters.common_parameters
+                + model_info.parameters.kernel_parameters)
     partable = make_partable(pars)
     subst = dict(id=model_info.id.replace('_', '-'),
Index: sasmodels/jitter.py
===================================================================
--- sasmodels/jitter.py	(revision 1198f905febb85403d3b86dca3d2bec81af13029)
+++ sasmodels/jitter.py	(revision 7d97437443989e8efc020cb89bf176a6b90c56cf)
@@ -15,4 +15,5 @@
     pass
 
+import matplotlib as mpl
 import matplotlib.pyplot as plt
 from matplotlib.widgets import Slider
@@ -746,17 +747,19 @@
         pass
 
-    axcolor = 'lightgoldenrodyellow'
+    # CRUFT: use axisbg instead of facecolor for matplotlib<2
+    facecolor_prop = 'facecolor' if mpl.__version__ > '2' else 'axisbg'
+    props = {facecolor_prop: 'lightgoldenrodyellow'}
 
     ## add control widgets to plot
-    axes_theta = plt.axes([0.1, 0.15, 0.45, 0.04], axisbg=axcolor)
-    axes_phi = plt.axes([0.1, 0.1, 0.45, 0.04], axisbg=axcolor)
-    axes_psi = plt.axes([0.1, 0.05, 0.45, 0.04], axisbg=axcolor)
+    axes_theta = plt.axes([0.1, 0.15, 0.45, 0.04], **props)
+    axes_phi = plt.axes([0.1, 0.1, 0.45, 0.04], **props)
+    axes_psi = plt.axes([0.1, 0.05, 0.45, 0.04], **props)
     stheta = Slider(axes_theta, 'Theta', -90, 90, valinit=theta)
     sphi = Slider(axes_phi, 'Phi', -180, 180, valinit=phi)
     spsi = Slider(axes_psi, 'Psi', -180, 180, valinit=psi)
 
-    axes_dtheta = plt.axes([0.75, 0.15, 0.15, 0.04], axisbg=axcolor)
-    axes_dphi = plt.axes([0.75, 0.1, 0.15, 0.04], axisbg=axcolor)
-    axes_dpsi = plt.axes([0.75, 0.05, 0.15, 0.04], axisbg=axcolor)
+    axes_dtheta = plt.axes([0.75, 0.15, 0.15, 0.04], **props)
+    axes_dphi = plt.axes([0.75, 0.1, 0.15, 0.04], **props)
+    axes_dpsi = plt.axes([0.75, 0.05, 0.15, 0.04], **props)
     # Note: using ridiculous definition of rectangle distribution, whose width
     # in sasmodels is sqrt(3) times the given width.  Divide by sqrt(3) to keep
Index: sasmodels/kernelcl.py
===================================================================
--- sasmodels/kernelcl.py	(revision 3199b177cb91c6bd74017b7f942ddbbbc9bb46c0)
+++ sasmodels/kernelcl.py	(revision 3199b177cb91c6bd74017b7f942ddbbbc9bb46c0)
@@ -58,6 +58,14 @@
 import time
 
+try:
+    from time import perf_counter as clock
+except ImportError: # CRUFT: python < 3.3
+    import sys
+    if sys.platform.count("darwin") > 0:
+        from time import time as clock
+    else:
+        from time import clock
+
 import numpy as np  # type: ignore
-
 
 # Attempt to setup OpenCL. This may fail if the pyopencl package is not
@@ -592,5 +600,5 @@
         #call_details.show(values)
         wait_for = None
-        last_nap = time.clock()
+        last_nap = clock()
         step = 1000000//self.q_input.nq + 1
         for start in range(0, call_details.num_eval, step):
@@ -603,5 +611,5 @@
                 # Allow other processes to run.
                 wait_for[0].wait()
-                current_time = time.clock()
+                current_time = clock()
                 if current_time - last_nap > 0.5:
                     time.sleep(0.001)
Index: sasmodels/modelinfo.py
===================================================================
--- sasmodels/modelinfo.py	(revision 39a06c989ba87dcedc6e5270d59fc4c9dd47ffe5)
+++ sasmodels/modelinfo.py	(revision 39a06c989ba87dcedc6e5270d59fc4c9dd47ffe5)
@@ -404,4 +404,8 @@
       parameters counted as n individual parameters p1, p2, ...
 
+    * *common_parameters* is the list of common parameters, with a unique
+      copy for each model so that structure factors can have a default
+      background of 0.0.
+
     * *call_parameters* is the complete list of parameters to the kernel,
       including scale and background, with vector parameters recorded as
@@ -416,9 +420,12 @@
     parameters don't use vector notation, and instead use p1, p2, ...
     """
-    # scale and background are implicit parameters
-    COMMON = [Parameter(*p) for p in COMMON_PARAMETERS]
-
     def __init__(self, parameters):
         # type: (List[Parameter]) -> None
+
+        # scale and background are implicit parameters
+        # Need them to be unique to each model in case they have different
+        # properties, such as default=0.0 for structure factor backgrounds.
+        self.common_parameters = [Parameter(*p) for p in COMMON_PARAMETERS]
+
         self.kernel_parameters = parameters
         self._set_vector_lengths()
@@ -468,4 +475,15 @@
                          if p.polydisperse and p.type not in ('orientation', 'magnetic'))
         self.pd_2d = set(p.name for p in self.call_parameters if p.polydisperse)
+
+    def set_zero_background(self):
+        """
+        Set the default background to zero for this model.  This is done for
+        structure factor models.
+        """
+        # type: () -> None
+        # Make sure background is the second common parameter.
+        assert self.common_parameters[1].id == "background"
+        self.common_parameters[1].default = 0.0
+        self.defaults = self._get_defaults()
 
     def check_angles(self):
@@ -567,5 +585,5 @@
     def _get_call_parameters(self):
         # type: () -> List[Parameter]
-        full_list = self.COMMON[:]
+        full_list = self.common_parameters[:]
         for p in self.kernel_parameters:
             if p.length == 1:
@@ -670,5 +688,5 @@
 
         # Gather the user parameters in order
-        result = control + self.COMMON
+        result = control + self.common_parameters
         for p in self.kernel_parameters:
             if not is2d and p.type in ('orientation', 'magnetic'):
@@ -770,7 +788,20 @@
 
     info = ModelInfo()
+
+    # Build the parameter table
     #print("make parameter table", kernel_module.parameters)
     parameters = make_parameter_table(getattr(kernel_module, 'parameters', []))
+
+    # background defaults to zero for structure factor models
+    structure_factor = getattr(kernel_module, 'structure_factor', False)
+    if structure_factor:
+        parameters.set_zero_background()
+
+    # TODO: remove demo parameters
+    # The plots in the docs are generated from the model default values.
+    # Sascomp set parameters from the command line, and so doesn't need
+    # demo values for testing.
     demo = expand_pars(parameters, getattr(kernel_module, 'demo', None))
+
     filename = abspath(kernel_module.__file__).replace('.pyc', '.py')
     kernel_id = splitext(basename(filename))[0]
Index: sasmodels/models/hardsphere.py
===================================================================
--- sasmodels/models/hardsphere.py	(revision 304c775207a9dbbadb23ad414848454d66b556d1)
+++ sasmodels/models/hardsphere.py	(revision 304c775207a9dbbadb23ad414848454d66b556d1)
@@ -162,6 +162,4 @@
     return pars
 
-demo = dict(radius_effective=200, volfraction=0.2,
-            radius_effective_pd=0.1, radius_effective_pd_n=40)
 # Q=0.001 is in the Taylor series, low Q part, so add Q=0.1,
 # assuming double precision sasview is correct
Index: sasmodels/resolution.py
===================================================================
--- sasmodels/resolution.py	(revision da3638ff2a2c2b5545bc7ad33fcacddd3b2b65c0)
+++ sasmodels/resolution.py	(revision da3638ff2a2c2b5545bc7ad33fcacddd3b2b65c0)
@@ -445,11 +445,11 @@
     q = np.sort(q)
     if q_min + 2*MINIMUM_RESOLUTION < q[0]:
-        n_low = np.ceil((q[0]-q_min) / (q[1]-q[0])) if q[1] > q[0] else 15
-        q_low = np.linspace(q_min, q[0], int(n_low)+1)[:-1]
+        n_low = int(np.ceil((q[0]-q_min) / (q[1]-q[0]))) if q[1] > q[0] else 15
+        q_low = np.linspace(q_min, q[0], n_low+1)[:-1]
     else:
         q_low = []
     if q_max - 2*MINIMUM_RESOLUTION > q[-1]:
-        n_high = np.ceil((q_max-q[-1]) / (q[-1]-q[-2])) if q[-1] > q[-2] else 15
-        q_high = np.linspace(q[-1], q_max, int(n_high)+1)[1:]
+        n_high = int(np.ceil((q_max-q[-1]) / (q[-1]-q[-2]))) if q[-1] > q[-2] else 15
+        q_high = np.linspace(q[-1], q_max, n_high+1)[1:]
     else:
         q_high = []
@@ -498,11 +498,11 @@
         if q_min < 0:
             q_min = q[0]*MINIMUM_ABSOLUTE_Q
-        n_low = np.ceil(log_delta_q * (log(q[0])-log(q_min)))
-        q_low = np.logspace(log10(q_min), log10(q[0]), int(n_low)+1)[:-1]
+        n_low = int(np.ceil(log_delta_q * (log(q[0])-log(q_min))))
+        q_low = np.logspace(log10(q_min), log10(q[0]), n_low+1)[:-1]
     else:
         q_low = []
     if q_max > q[-1]:
-        n_high = np.ceil(log_delta_q * (log(q_max)-log(q[-1])))
-        q_high = np.logspace(log10(q[-1]), log10(q_max), int(n_high)+1)[1:]
+        n_high = int(np.ceil(log_delta_q * (log(q_max)-log(q[-1]))))
+        q_high = np.logspace(log10(q[-1]), log10(q_max), n_high+1)[1:]
     else:
         q_high = []
Index: sasmodels/sasview_model.py
===================================================================
--- sasmodels/sasview_model.py	(revision 3a1afed813c02d7a1016d5e4fe9bfc3cb41c1ae7)
+++ sasmodels/sasview_model.py	(revision 3a1afed813c02d7a1016d5e4fe9bfc3cb41c1ae7)
@@ -382,5 +382,4 @@
             hidden.add('scale')
             hidden.add('background')
-            self._model_info.parameters.defaults['background'] = 0.
 
         # Update the parameter lists to exclude any hidden parameters
@@ -931,4 +930,32 @@
     CylinderModel().evalDistribution([0.1, 0.1])
 
+def test_structure_factor_background():
+    # type: () -> None
+    """
+    Check that sasview model and direct model match, with background=0.
+    """
+    from .data import empty_data1D
+    from .core import load_model_info, build_model
+    from .direct_model import DirectModel
+
+    model_name = "hardsphere"
+    q = [0.0]
+
+    sasview_model = _make_standard_model(model_name)()
+    sasview_value = sasview_model.evalDistribution(np.array(q))[0]
+
+    data = empty_data1D(q)
+    model_info = load_model_info(model_name)
+    model = build_model(model_info)
+    direct_model = DirectModel(data, model)
+    direct_value_zero_background = direct_model(background=0.0)
+
+    assert sasview_value == direct_value_zero_background
+
+    # Additionally check that direct value background defaults to zero
+    direct_value_default = direct_model()
+    assert sasview_value == direct_value_default
+
+
 def magnetic_demo():
     Model = _make_standard_model('sphere')
@@ -951,2 +978,3 @@
     #print("rpa:", test_rpa())
     #test_empty_distribution()
+    #test_structure_factor_background()
Index: sasmodels/weights.py
===================================================================
--- sasmodels/weights.py	(revision 3d5824792e80506c5c40f05fb2ddc2234a8acedf)
+++ sasmodels/weights.py	(revision e2592f02ab8e424de77e5b72ae9adfc84b47a185)
@@ -23,5 +23,5 @@
     default = dict(npts=35, width=0, nsigmas=3)
     def __init__(self, npts=None, width=None, nsigmas=None):
-        self.npts = self.default['npts'] if npts is None else npts
+        self.npts = self.default['npts'] if npts is None else int(npts)
         self.width = self.default['width'] if width is None else width
         self.nsigmas = self.default['nsigmas'] if nsigmas is None else nsigmas
