Index: sasmodels/compare_many.py
===================================================================
--- sasmodels/compare_many.py	(revision 17bbadde9de73711781f748816b06e6956dc8cfa)
+++ sasmodels/compare_many.py	(revision b8e5e21e2c80b5b2ff0443c55b4ea28248f174bc)
@@ -109,6 +109,5 @@
 
     if is_2d:
-        partype = model_info['partype']
-        if not partype['orientation'] and not partype['magnetic']:
+        if not model_info['has_2d']:
             print(',"1-D only"')
             return
Index: sasmodels/core.py
===================================================================
--- sasmodels/core.py	(revision 17bbadde9de73711781f748816b06e6956dc8cfa)
+++ sasmodels/core.py	(revision b8e5e21e2c80b5b2ff0443c55b4ea28248f174bc)
@@ -34,4 +34,17 @@
     return available_models
 
+def isstr(s):
+    """
+    Return True if *s* is a string-like object.
+    """
+    try: s + ''
+    except: return False
+    return True
+
+def load_model(model_name, **kw):
+    """
+    Load model info and build model.
+    """
+    return build_model(load_model_info(model_name), **kw)
 
 def load_model_info(model_name):
@@ -46,31 +59,4 @@
     return generate.make_model_info(kernel_module)
 
-
-def precompile_dll(model_name, dtype="double"):
-    """
-    Precompile the dll for a model.
-
-    Returns the path to the compiled model, or None if the model is a pure
-    python model.
-
-    This can be used when build the windows distribution of sasmodels
-    (which may be missing the OpenCL driver and the dll compiler), or
-    otherwise sharing models with windows users who do not have a compiler.
-
-    See :func:`sasmodels.kerneldll.make_dll` for details on controlling the
-    dll path and the allowed floating point precision.
-    """
-    model_info = load_model_info(model_name)
-    source = generate.make_source(model_info)
-    return kerneldll.make_dll(source, model_info, dtype=dtype) if source else None
-
-
-def isstr(s):
-    """
-    Return True if *s* is a string-like object.
-    """
-    try: s + ''
-    except: return False
-    return True
 
 def build_model(model_info, dtype=None, platform="ocl"):
@@ -114,4 +100,23 @@
     else:
         return kernelcl.GpuModel(source, model_info, dtype)
+
+def precompile_dll(model_name, dtype="double"):
+    """
+    Precompile the dll for a model.
+
+    Returns the path to the compiled model, or None if the model is a pure
+    python model.
+
+    This can be used when build the windows distribution of sasmodels
+    (which may be missing the OpenCL driver and the dll compiler), or
+    otherwise sharing models with windows users who do not have a compiler.
+
+    See :func:`sasmodels.kerneldll.make_dll` for details on controlling the
+    dll path and the allowed floating point precision.
+    """
+    model_info = load_model_info(model_name)
+    source = generate.make_source(model_info)
+    return kerneldll.make_dll(source, model_info, dtype=dtype) if source else None
+
 
 def make_kernel(model, q_vectors):
Index: sasmodels/generate.py
===================================================================
--- sasmodels/generate.py	(revision 17bbadde9de73711781f748816b06e6956dc8cfa)
+++ sasmodels/generate.py	(revision b8e5e21e2c80b5b2ff0443c55b4ea28248f174bc)
@@ -235,5 +235,5 @@
 COMMON_PARAMETERS = [
     ["scale", "", 1, [0, np.inf], "", "Source intensity"],
-    ["background", "1/cm", 0, [0, np.inf], "", "Source background"],
+    ["background", "1/cm", 1e-3, [0, np.inf], "", "Source background"],
     ]
 
@@ -629,9 +629,11 @@
     """
     # Fill in the derived attributes
+    partype = categorize_parameters(model_info['parameters'])
     model_info['limits'] = dict((p[0], p[3]) for p in model_info['parameters'])
-    model_info['partype'] = categorize_parameters(model_info['parameters'])
+    model_info['partype'] = partype
     model_info['defaults'] = dict((p[0], p[2]) for p in model_info['parameters'])
     if model_info.get('demo', None) is None:
         model_info['demo'] = model_info['defaults']
+    model_info['has_2d'] = partype['orientation'] or partype['magnetic']
 
 def make_model_info(kernel_module):
@@ -655,4 +657,8 @@
     * *parameters* is the model parameter table
     * *single* is True if the model allows single precision
+    * *structure_factor* is True if the model is useable in a product
+    * *variant_info* contains the information required to select between
+      model variants (e.g., the list of cases) or is None if there are no
+      model variants
     * *defaults* is the *{parameter: value}* table built from the parameter
       description table.
@@ -678,14 +684,8 @@
     """
     # TODO: maybe turn model_info into a class ModelDefinition
-    #print(kernelfile)
-    category = getattr(kernel_module, 'category', None)
     parameters = COMMON_PARAMETERS + kernel_module.parameters
-    # Default the demo parameters to the starting values for the individual
-    # parameters if an explicit demo parameter set has not been specified.
-    demo_parameters = getattr(kernel_module, 'demo', None)
     filename = abspath(kernel_module.__file__)
     kernel_id = splitext(basename(filename))[0]
     name = getattr(kernel_module, 'name', None)
-    single = getattr(kernel_module, 'single', True)
     if name is None:
         name = " ".join(w.capitalize() for w in kernel_id.split('_'))
@@ -696,10 +696,12 @@
         title=kernel_module.title,
         description=kernel_module.description,
-        docs=kernel_module.__doc__,
-        category=category,
         parameters=parameters,
         composition=None,
-        single=single,
-        demo=demo_parameters,
+        docs=kernel_module.__doc__,
+        category=getattr(kernel_module, 'category', None),
+        single=getattr(kernel_module, 'single', True),
+        structure_factor=getattr(kernel_module, 'structure_factor', False),
+        variant_info=getattr(kernel_module, 'invariant_info', None),
+        demo=getattr(kernel_module, 'demo', None),
         source=getattr(kernel_module, 'source', []),
         oldname=getattr(kernel_module, 'oldname', None),
@@ -708,5 +710,5 @@
         )
     process_parameters(model_info)
-    # Fill in attributes which default to None
+    # Fill in available functions
     model_info.update((k, getattr(kernel_module, k, None))
                       for k in ('ER', 'VR', 'form_volume', 'Iq', 'Iqxy'))
