Index: sasmodels/sasview_model.py
===================================================================
--- sasmodels/sasview_model.py	(revision 2622b3fe39474acb34f0bbd16dccdce0561d8a26)
+++ sasmodels/sasview_model.py	(revision de97440ce3940f84bb8cb52fcf894156a7e63081)
@@ -23,9 +23,12 @@
 from . import core
 
-def make_class(model_info, dtype='single', namestyle='name'):
+def standard_models():
+    return [make_class(model_name) for model_name in core.list_models()]
+
+def make_class(model_name, namestyle='name'):
     """
     Load the sasview model defined in *kernel_module*.
 
-    Returns a class that can be used directly as a sasview model.
+    Returns a class that can be used directly as a sasview model.t
 
     Defaults to using the new name for a model.  Setting
@@ -33,9 +36,9 @@
     compatible with SasView.
     """
-    model = core.build_model(model_info, dtype=dtype)
+    model_info = core.load_model_info(model_name)
     def __init__(self, multfactor=1):
-        SasviewModel.__init__(self, model)
+        SasviewModel.__init__(self, model_info)
     attrs = dict(__init__=__init__)
-    ConstructedModel = type(model.info[namestyle], (SasviewModel,), attrs)
+    ConstructedModel = type(model_info[namestyle], (SasviewModel,), attrs)
     return ConstructedModel
 
@@ -44,11 +47,11 @@
     Sasview wrapper for opencl/ctypes model.
     """
-    def __init__(self, model):
-        """Initialization"""
-        self._model = model
-
-        self.name = model.info['name']
-        self.oldname = model.info['oldname']
-        self.description = model.info['description']
+    def __init__(self, model_info):
+        self._model_info = model_info
+        self._kernel = None
+
+        self.name = model_info['name']
+        self.oldname = model_info['oldname']
+        self.description = model_info['description']
         self.category = None
         self.multiplicity_info = None
@@ -60,7 +63,7 @@
         self.params = collections.OrderedDict()
         self.dispersion = dict()
-        partype = model.info['partype']
-
-        for p in model.info['parameters']:
+        partype = model_info['partype']
+
+        for p in model_info['parameters']:
             self.params[p.name] = p.default
             self.details[p.name] = [p.units] + p.limits
@@ -83,8 +86,8 @@
 
         ## independent parameter name and unit [string]
-        self.input_name = model.info.get("input_name", "Q")
-        self.input_unit = model.info.get("input_unit", "A^{-1}")
-        self.output_name = model.info.get("output_name", "Intensity")
-        self.output_unit = model.info.get("output_unit", "cm^{-1}")
+        self.input_name = model_info.get("input_name", "Q")
+        self.input_unit = model_info.get("input_unit", "A^{-1}")
+        self.output_name = model_info.get("output_name", "Intensity")
+        self.output_unit = model_info.get("output_unit", "cm^{-1}")
 
         ## _persistency_dict is used by sas.perspectives.fitting.basepage
@@ -95,4 +98,17 @@
         ## New fields introduced for opencl rewrite
         self.cutoff = 1e-5
+
+    def __get_state__(self):
+        state = self.__dict__.copy()
+        model_id = self._model_info['id']
+        state.pop('_kernel')
+        # May need to reload model info on set state since it has pointers
+        # to python implementations of Iq, etc.
+        #state.pop('_model_info')
+        return state
+
+    def __set_state__(self, state):
+        self.__dict__ = state
+        self._kernel = None
 
     def __str__(self):
@@ -187,5 +203,5 @@
         # TODO: fix test so that parameter order doesn't matter
         ret = ['%s.%s' % (d.lower(), p)
-               for d in self._model.info['partype']['pd-2d']
+               for d in self._model_info['partype']['pd-2d']
                for p in ('npts', 'nsigmas', 'width')]
         #print(ret)
@@ -261,5 +277,5 @@
             # Check whether we have a list of ndarrays [qx,qy]
             qx, qy = qdist
-            partype = self._model.info['partype']
+            partype = self._model_info['partype']
             if not partype['orientation'] and not partype['magnetic']:
                 return self.calculate_Iq(np.sqrt(qx ** 2 + qy ** 2))
@@ -284,6 +300,8 @@
         to the card for each evaluation.
         """
+        if self._kernel is None:
+            self._kernel = core.build_model(self._model_info)
         q_vectors = [np.asarray(q) for q in args]
-        fn = self._model(q_vectors)
+        fn = self._kernel(q_vectors)
         pars = [self.params[v] for v in fn.fixed_pars]
         pd_pars = [self._get_weights(p) for p in fn.pd_pars]
@@ -299,5 +317,5 @@
         :return: the value of the effective radius
         """
-        ER = self._model.info.get('ER', None)
+        ER = self._model_info.get('ER', None)
         if ER is None:
             return 1.0
@@ -314,5 +332,5 @@
         :return: the value of the volf ratio
         """
-        VR = self._model.info.get('VR', None)
+        VR = self._model_info.get('VR', None)
         if VR is None:
             return 1.0
@@ -358,5 +376,5 @@
         parameter set in the vector.
         """
-        pars = self._model.info['partype']['volume']
+        pars = self._model_info['partype']['volume']
         return core.dispersion_mesh([self._get_weights(p) for p in pars])
 
@@ -368,6 +386,6 @@
         from . import weights
 
-        relative = self._model.info['partype']['pd-rel']
-        limits = self._model.info['limits']
+        relative = self._model_info['partype']['pd-rel']
+        limits = self._model_info['limits']
         dis = self.dispersion[par]
         value, weight = weights.get_weights(
@@ -375,2 +393,3 @@
             self.params[par], limits[par], par in relative)
         return value, weight / np.sum(weight)
+
