Index: park-1.2.1/park/expression.py
===================================================================
--- park-1.2.1/park/expression.py	(revision 3570545bb48d1a639dd12458e3c717368477e67b)
+++ park-1.2.1/park/expression.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
@@ -160,5 +160,5 @@
 """%("\n    ".join(exprs),"\n    ".join(code))
 
-    #print "Function:",function
+    #print "Function:",functiondef
     exec functiondef in globals,locals
     retfn = locals['eval_expressions']
@@ -185,4 +185,5 @@
     # Check symbol rename
     assert substitute(expr,{'a.b.x':'Q'}) == 'Q + sin(4*pi*a.c) + Q/a.b'
+    assert substitute(expr,{'a.b':'Q'}) == 'a.b.x + sin(4*pi*a.c) + a.b.x/Q'
 
 
@@ -249,5 +250,5 @@
     for expr in ['G4.cage', 'M0.cage', 'M1.G1 + *2', 
                  'piddle',
-                 'import sys; print "p0wned"',
+                 '5; import sys; print "p0wned"',
                  '__import__("sys").argv']:
         try:
Index: park-1.2.1/park/fitresult.py
===================================================================
--- park-1.2.1/park/fitresult.py	(revision 3570545bb48d1a639dd12458e3c717368477e67b)
+++ park-1.2.1/park/fitresult.py	(revision 95d58d3a800344be2703a5e297ab0e7b153c6309)
@@ -67,4 +67,5 @@
         improvements.
         """
+        #import traceback; traceback.print_stack()
         self.progress_time = time.time()
         self.progress_percent = 0
@@ -228,4 +229,5 @@
 
     def __str__(self):
+        #import traceback; traceback.print_stack()
         if self.parameters == None: return "No results"
         L = ["P%-3d %s"%(n+1,p.summarize()) for n,p in enumerate(self.parameters)]
Index: park-1.2.1/park/parameter.py
===================================================================
--- park-1.2.1/park/parameter.py	(revision 3570545bb48d1a639dd12458e3c717368477e67b)
+++ park-1.2.1/park/parameter.py	(revision fb7180c8dc1e7aa05eb379b946873bb0faebc57c)
@@ -15,4 +15,5 @@
 __all__ = ['Parameter', 'ParameterSet']
 
+import math
 import numpy
 import expression        
@@ -162,6 +163,6 @@
         """
         range = ['.']*10
-        lo,hi = p.range
-        portion = (p.value-lo)/(hi-lo)
+        lo,hi = self.range
+        portion = (self.value-lo)/(hi-lo)
         if portion < 0: portion = 0.
         elif portion >= 1: portion = 0.99999999
@@ -169,5 +170,5 @@
         range[bar] = '|'
         range = "".join(range)
-        return "%25s %s %g in [%g,%g]"  % (p.name,range,p.value,lo,hi)
+        return "%25s %s %g in [%g,%g]"  % (self.name,range,self.value,lo,hi)
 
     def isfitted(self): return self.status == 'fitted'
@@ -273,8 +274,10 @@
         for p in self:
             if parts[1] == p.name:
-                if len(pars) == 2:
+                if len(parts) == 2:
                     return p
                 elif isinstance(p, ParameterSet):
                     return p._byname(parts[1:])
+                else:
+                    raise
         return None
 
@@ -283,5 +286,5 @@
         parts = name.split('.')
         if parts[0] == self.name:
-            p =  _byname(self, name.split('.'))
+            p =  self._byname(name.split('.'))
             if p: return p
         raise KeyError("parameter %s not in parameter set"%name)
Index: run.py
===================================================================
--- run.py	(revision bbd97e5cc51780c7e00fb5c22b4c92799a7c0216)
+++ run.py	(revision 499639c1f9a84790d2c32a80b51f75ff456e3587)
@@ -8,5 +8,8 @@
 Usage:
 
-./run.py [args]
+./run.py [(module|script) args...]
+
+Without arguments run.py runs sasview.  With arguments, run.py will run
+the given module or script.
 """
 
@@ -49,8 +52,10 @@
     return mod
 
-def import_dll(modname):
+def import_dll(modname, build_path):
     """Import a DLL from the build directory"""
+    import sysconfig
+    ext = sysconfig.get_config_var('SO')
     # build_path comes from context
-    path = glob(joinpath(build_path, *modname.split('.'))+'.*')[0]
+    path = joinpath(build_path, *modname.split('.'))+ext
     #print "importing", modname, "from", path
     return imp.load_dynamic(modname, path)
@@ -81,4 +86,7 @@
     except: addpath(joinpath(root, '..','periodictable'))
 
+    try: import bumps
+    except: addpath(joinpath(root, '..','bumps'))
+
     # select wx version
     #addpath(os.path.join(root, '..','wxPython-src-3.0.0.0','wxPython'))
@@ -107,5 +115,5 @@
     sans.pr.core = import_package('sans.pr.core',
                                   joinpath(build_path, 'sans', 'pr', 'core'))
-    #import_dll('park._modeling')
+    #import_dll('park._modeling', build_path)
 
     #park = import_package('park',os.path.join(build_path,'park'))
@@ -122,8 +130,5 @@
 
 if __name__ == "__main__":
-    # start sasview
-    #import multiprocessing
-    #multiprocessing.freeze_support()
     prepare()
-    from sans.sansview.sansview import SasView
-    SasView()
+    from sans.sansview.sansview import run
+    run()
Index: sansview/sansview.py
===================================================================
--- sansview/sansview.py	(revision e2271c590a75c4a37335432df42e8a22964c061f)
+++ sansview/sansview.py	(revision 6fe51002a81260397b29374005fb3e465ff93b4a)
@@ -36,10 +36,5 @@
 PLUGIN_MODEL_DIR = 'plugin_models'
 APP_NAME = 'SasView'
-def run():
-    sys.path.append(os.path.join("..","..",".."))
-    from multiprocessing import freeze_support
-    freeze_support()
-    sasview = SasView()
-        
+
 class SasViewApp(gui_manager.ViewApp):
     """
@@ -113,13 +108,22 @@
         self.gui.clean_plugin_models(PLUGIN_MODEL_DIR)
         # Start the main loop
-        self.gui.MainLoop()  
-       
+        self.gui.MainLoop()
 
 
-if __name__ == "__main__": 
+def run():
     from multiprocessing import freeze_support
     freeze_support()
-    #Process(target=SasView).start()
-    sasview = SasView()
+    if len(sys.argv) > 1:
+        thing_to_run = sys.argv[1]
+        sys.argv = sys.argv[1:]
+        import runpy
+        if os.path.exists(thing_to_run):
+            runpy.run_path(thing_to_run)
+        else:
+            runpy.run_module(thing_to_run)
+    else:
+        SasView()
 
-   
+if __name__ == "__main__":
+    run()
+
Index: sansview/setup_exe.py
===================================================================
--- sansview/setup_exe.py	(revision 27b7accfe21e1b3456e646ee01adff844993eae3)
+++ sansview/setup_exe.py	(revision 6fe51002a81260397b29374005fb3e465ff93b4a)
@@ -319,4 +319,5 @@
 'reportlab.platypus',
 ])
+packages.append('IPython')
 includes = ['site']
 
Index: setup.py
===================================================================
--- setup.py	(revision 968aa6e55c1878932278d78744f9b0adccd25c0e)
+++ setup.py	(revision 6fe51002a81260397b29374005fb3e465ff93b4a)
@@ -69,5 +69,5 @@
     
     
-enable_openmp = True                    
+enable_openmp = False
 
 if sys.platform =='darwin':
Index: src/sans/fit/AbstractFitEngine.py
===================================================================
--- src/sans/fit/AbstractFitEngine.py	(revision 6c007022258cff8efb5208e90301244c22e30170)
+++ src/sans/fit/AbstractFitEngine.py	(revision 8d074d926d99193a8c902448957d621abd9235d5)
@@ -3,136 +3,103 @@
 #import logging
 import sys
+import math
 import numpy
-import math
-import park
+
 from sans.dataloader.data_info import Data1D
 from sans.dataloader.data_info import Data2D
-_SMALLVALUE = 1.0e-10    
-    
-class SansParameter(park.Parameter):
-    """
-    SANS model parameters for use in the PARK fitting service.
-    The parameter attribute value is redirected to the underlying
-    parameter value in the SANS model.
-    """
-    def __init__(self, name, model, data):
-        """
-            :param name: the name of the model parameter
-            :param model: the sans model to wrap as a park model
-        """
-        park.Parameter.__init__(self, name)
-        self._model, self._name = model, name
-        self.data = data
-        self.model = model
-        #set the value for the parameter of the given name
-        self.set(model.getParam(name))
-         
-    def _getvalue(self):
-        """
-        override the _getvalue of park parameter
-        
-        :return value the parameter associates with self.name
-        
-        """
-        return self._model.getParam(self.name)
-    
-    def _setvalue(self, value):
-        """
-        override the _setvalue pf park parameter
-        
-        :param value: the value to set on a given parameter
-        
-        """
-        self._model.setParam(self.name, value)
-        
-    value = property(_getvalue, _setvalue)
-    
-    def _getrange(self):
-        """
-        Override _getrange of park parameter
-        return the range of parameter
-        """
-        #if not  self.name in self._model.getDispParamList():
-        lo, hi = self._model.details[self.name][1:3]
-        if lo is None: lo = -numpy.inf
-        if hi is None: hi = numpy.inf
-        if lo > hi:
-            raise ValueError, "wrong fit range for parameters"
-        
-        return lo, hi
-    
-    def get_name(self):
-        """
-        """
-        return self._getname()
-    
-    def _setrange(self, r):
-        """
-        override _setrange of park parameter
-        
-        :param r: the value of the range to set
-        
-        """
-        self._model.details[self.name][1:3] = r
-    range = property(_getrange, _setrange)
-    
-    
-class Model(park.Model):
-    """
-    PARK wrapper for SANS models.
+_SMALLVALUE = 1.0e-10
+
+# Note: duplicated from park
+class FitHandler(object):
+    """
+    Abstract interface for fit thread handler.
+
+    The methods in this class are called by the optimizer as the fit
+    progresses.
+
+    Note that it is up to the optimizer to call the fit handler correctly,
+    reporting all status changes and maintaining the 'done' flag.
+    """
+    done = False
+    """True when the fit job is complete"""
+    result = None
+    """The current best result of the fit"""
+
+    def improvement(self):
+        """
+        Called when a result is observed which is better than previous
+        results from the fit.
+
+        result is a FitResult object, with parameters, #calls and fitness.
+        """
+    def error(self, msg):
+        """
+        Model had an error; print traceback
+        """
+    def progress(self, current, expected):
+        """
+        Called each cycle of the fit, reporting the current and the
+        expected amount of work.   The meaning of these values is
+        optimizer dependent, but they can be converted into a percent
+        complete using (100*current)//expected.
+
+        Progress is updated each iteration of the fit, whatever that
+        means for the particular optimization algorithm.  It is called
+        after any calls to improvement for the iteration so that the
+        update handler can control I/O bandwidth by suppressing
+        intermediate improvements until the fit is complete.
+        """
+    def finalize(self):
+        """
+        Fit is complete; best results are reported
+        """
+    def abort(self):
+        """
+        Fit was aborted.
+        """
+
+    # TODO: not sure how these are used, but they are needed for running the fit
+    def update_fit(self, last=False): pass
+    def set_result(self, result=None): self.result = result
+
+class Model:
+    """
+    Fit wrapper for SANS models.
     """
     def __init__(self, sans_model, sans_data=None, **kw):
         """
         :param sans_model: the sans model to wrap using park interface
-        
-        """
-        park.Model.__init__(self, **kw)
+
+        """
         self.model = sans_model
         self.name = sans_model.name
         self.data = sans_data
-        #list of parameters names
-        self.sansp = sans_model.getParamList()
-        #list of park parameter
-        self.parkp = [SansParameter(p, sans_model, sans_data) for p in self.sansp]
-        #list of parameter set
-        self.parameterset = park.ParameterSet(sans_model.name, pars=self.parkp)
-        self.pars = []
-  
+
     def get_params(self, fitparams):
         """
         return a list of value of paramter to fit
-        
+
         :param fitparams: list of paramaters name to fit
-        
-        """
-        list_params = []
-        self.pars = []
-        self.pars = fitparams
-        for item in fitparams:
-            for element in self.parkp:
-                if element.name == str(item):
-                    list_params.append(element.value)
-        return list_params
-    
+
+        """
+        return [self.model.getParam(k) for k in fitparams]
+
     def set_params(self, paramlist, params):
         """
         Set value for parameters to fit
-        
+
         :param params: list of value for parameters to fit
-        
-        """
-        try:
-            for i in range(len(self.parkp)):
-                for j in range(len(paramlist)):
-                    if self.parkp[i].name == paramlist[j]:
-                        self.parkp[i].value = params[j]
-                        self.model.setParam(self.parkp[i].name, params[j])
-        except:
-            raise
-  
+
+        """
+        for k,v in zip(paramlist, params):
+            self.model.setParam(k,v)
+
+    def set(self, **kw):
+        self.set_params(*zip(*kw.items()))
+
     def eval(self, x):
         """
             Override eval method of park model.
-        
+
             :param x: the x value used to compute a function
         """
@@ -141,5 +108,5 @@
         except:
             raise
-        
+
     def eval_derivs(self, x, pars=[]):
         """
@@ -154,7 +121,9 @@
         instead of calling eval.
         """
-        return []
-
-    
+        raise NotImplementedError('no derivatives available')
+
+    def __call__(self, x):
+        return self.eval(x)
+
 class FitData1D(Data1D):
     """
@@ -185,4 +154,5 @@
         """
         Data1D.__init__(self, x=x, y=y, dx=dx, dy=dy)
+        self.num_points = len(x)
         self.sans_data = data
         self.smearer = smearer
@@ -251,5 +221,11 @@
         """
         return self.qmin, self.qmax
-        
+
+    def size(self):
+        """
+        Number of measurement points in data set after masking, etc.
+        """
+        return len(self.x)
+
     def residuals(self, fn):
         """
@@ -293,9 +269,7 @@
     def __init__(self, sans_data2d, data=None, err_data=None):
         Data2D.__init__(self, data=data, err_data=err_data)
-        """
-            Data can be initital with a data (sans plottable)
-            or with vectors.
-        """
+        # Data can be initialized with a sans plottable or with vectors.
         self.res_err_image = []
+        self.num_points = 0 # will be set by set_data
         self.idx = []
         self.qmin = None
@@ -339,4 +313,5 @@
         self.idx = (self.idx) & (self.mask)
         self.idx = (self.idx) & (numpy.isfinite(self.data))
+        self.num_points = numpy.sum(self.idx)
 
     def set_smearer(self, smearer):
@@ -372,5 +347,11 @@
         """
         return self.qmin, self.qmax
-     
+
+    def size(self):
+        """
+        Number of measurement points in data set after masking, etc.
+        """
+        return numpy.sum(self.idx)
+
     def residuals(self, fn):
         """
@@ -409,136 +390,5 @@
 
 
-class SansAssembly:
-    """
-    Sans Assembly class a class wrapper to be call in optimizer.leastsq method
-    """
-    def __init__(self, paramlist, model=None, data=None, fitresult=None,
-                 handler=None, curr_thread=None, msg_q=None):
-        """
-        :param Model: the model wrapper fro sans -model
-        :param Data: the data wrapper for sans data
-        
-        """
-        self.model = model
-        self.data = data
-        self.paramlist = paramlist
-        self.msg_q = msg_q
-        self.curr_thread = curr_thread
-        self.handler = handler
-        self.fitresult = fitresult
-        self.res = []
-        self.true_res = []
-        self.func_name = "Functor"
-        self.theory = None
-        
-    def chisq(self):
-        """
-        Calculates chi^2
-        
-        :param params: list of parameter values
-        
-        :return: chi^2
-        
-        """
-        total = 0
-        for item in self.true_res:
-            total += item * item
-        if len(self.true_res) == 0:
-            return None
-        return total / len(self.true_res)
-    
-    def __call__(self, params):
-        """
-            Compute residuals
-            :param params: value of parameters to fit
-        """
-        #import thread
-        self.model.set_params(self.paramlist, params)
-        #print "params", params
-        self.true_res, theory = self.data.residuals(self.model.eval)
-        self.theory = copy.deepcopy(theory)
-        # check parameters range
-        if self.check_param_range():
-            # if the param value is outside of the bound
-            # just silent return res = inf
-            return self.res
-        self.res = self.true_res
-        
-        if self.fitresult is not None:
-            self.fitresult.set_model(model=self.model)
-            self.fitresult.residuals = self.true_res
-            self.fitresult.iterations += 1
-            self.fitresult.theory = theory
-           
-            #fitness = self.chisq(params=params)
-            fitness = self.chisq()
-            self.fitresult.pvec = params
-            self.fitresult.set_fitness(fitness=fitness)
-            if self.msg_q is not None:
-                self.msg_q.put(self.fitresult)
-                
-            if self.handler is not None:
-                self.handler.set_result(result=self.fitresult)
-                self.handler.update_fit()
-
-            if self.curr_thread != None:
-                try:
-                    self.curr_thread.isquit()
-                except:
-                    #msg = "Fitting: Terminated...       Note: Forcing to stop "
-                    #msg += "fitting may cause a 'Functor error message' "
-                    #msg += "being recorded in the log file....."
-                    #self.handler.stop(msg)
-                    raise
-         
-        return self.res
-    
-    def check_param_range(self):
-        """
-        Check the lower and upper bound of the parameter value
-        and set res to the inf if the value is outside of the
-        range
-        :limitation: the initial values must be within range.
-        """
-
-        #time.sleep(0.01)
-        is_outofbound = False
-        # loop through the fit parameters
-        for p in self.model.parameterset:
-            param_name = p.get_name()
-            if param_name in self.paramlist:
-                
-                # if the range was defined, check the range
-                if numpy.isfinite(p.range[0]):
-                    if p.value == 0:
-                        # This value works on Scipy
-                        # Do not change numbers below
-                        value = _SMALLVALUE
-                    else:
-                        value = p.value
-                    # For leastsq, it needs a bit step back from the boundary
-                    val = p.range[0] - value * _SMALLVALUE
-                    if p.value < val:
-                        self.res *= 1e+6
-                        
-                        is_outofbound = True
-                        break
-                if numpy.isfinite(p.range[1]):
-                    # This value works on Scipy
-                    # Do not change numbers below
-                    if p.value == 0:
-                        value = _SMALLVALUE
-                    else:
-                        value = p.value
-                    # For leastsq, it needs a bit step back from the boundary
-                    val = p.range[1] + value * _SMALLVALUE
-                    if p.value > val:
-                        self.res *= 1e+6
-                        is_outofbound = True
-                        break
-
-        return is_outofbound
-    
-    
+
 class FitEngine:
     def __init__(self):
@@ -571,52 +421,30 @@
         
         """
-        if model == None:
-            raise ValueError, "AbstractFitEngine: Need to set model to fit"
-        
-        new_model = model
+        if not pars:
+            raise ValueError("no fitting parameters")
+
+        if model is None:
+            raise ValueError("no model to fit")
+
         if not issubclass(model.__class__, Model):
-            new_model = Model(model, data)
-        
-        if len(constraints) > 0:
-            for constraint in constraints:
-                name, value = constraint
-                try:
-                    new_model.parameterset[str(name)].set(str(value))
-                except:
-                    msg = "Fit Engine: Error occurs when setting the constraint"
-                    msg += " %s for parameter %s " % (value, name)
-                    raise ValueError, msg
-                
-        if len(pars) > 0:
-            temp = []
-            for item in pars:
-                if item in new_model.model.getParamList():
-                    temp.append(item)
-                    self.param_list.append(item)
-                else:
-                    
-                    msg = "wrong parameter %s used " % str(item)
-                    msg += "to set model %s. Choose " % str(new_model.model.name)
-                    msg += "parameter name within %s" % \
-                                str(new_model.model.getParamList())
-                    raise ValueError, msg
-              
-            #A fitArrange is already created but contains data_list only at id
-            if self.fit_arrange_dict.has_key(id):
-                self.fit_arrange_dict[id].set_model(new_model)
-                self.fit_arrange_dict[id].pars = pars
-            else:
-            #no fitArrange object has been create with this id
-                fitproblem = FitArrange()
-                fitproblem.set_model(new_model)
-                fitproblem.pars = pars
-                self.fit_arrange_dict[id] = fitproblem
-                vals = []
-                for name in pars:
-                    vals.append(new_model.model.getParam(name))
-                self.fit_arrange_dict[id].vals = vals
-        else:
-            raise ValueError, "park_integration:missing parameters"
-    
+            model = Model(model, data)
+
+        sasmodel = model.model
+        available_parameters = sasmodel.getParamList()
+        for p in pars:
+            if p not in available_parameters:
+                raise ValueError("parameter %s not available in model %s; use one of [%s] instead"
+                                 %(p, sasmodel.name, ", ".join(available_parameters)))
+
+        if id not in self.fit_arrange_dict:
+            self.fit_arrange_dict[id] = FitArrange()
+
+        self.fit_arrange_dict[id].set_model(model)
+        self.fit_arrange_dict[id].pars = pars
+        self.fit_arrange_dict[id].vals = [sasmodel.getParam(name) for name in pars]
+        self.fit_arrange_dict[id].constraints = constraints
+
+        self.param_list.extend(pars)
+
     def set_data(self, data, id, smearer=None, qmin=None, qmax=None):
         """
@@ -700,5 +528,5 @@
         self.vals = []
         self.selected = 0
-        
+
     def set_model(self, model):
         """
@@ -752,10 +580,4 @@
         """
         return self.selected
-    
-    
-IS_MAC = True
-if sys.platform.count("win32") > 0:
-    IS_MAC = False
-
 
 class FResult(object):
@@ -765,5 +587,4 @@
     def __init__(self, model=None, param_list=None, data=None):
         self.calls = None
-        self.pars = []
         self.fitness = None
         self.chisqr = None
@@ -776,6 +597,4 @@
         self.residuals = []
         self.index = []
-        self.parameters = None
-        self.is_mac = IS_MAC
         self.model = model
         self.data = data
@@ -803,21 +622,16 @@
         if self.pvec == None and self.model is None and self.param_list is None:
             return "No results"
-        n = len(self.model.parameterset)
-        
-        result_param = zip(xrange(n), self.model.parameterset)
-        msg1 = ["[Iteration #: %s ]" % self.iterations]
-        msg3 = ["=== goodness of fit: %s ===" % (str(self.fitness))]
-        if not self.is_mac:
-            msg2 = ["P%-3d  %s......|.....%s" % \
-                (p[0], p[1], p[1].value)\
-                  for p in result_param if p[1].name in self.param_list]
-            msg = msg1 + msg3 + msg2
-        else:
-            msg = msg1 + msg3
-        msg = "\n".join(msg)
-        return msg
+
+        sasmodel = self.model.model
+        pars = enumerate(sasmodel.getParamList())
+        msg1 = "[Iteration #: %s ]" % self.iterations
+        msg3 = "=== goodness of fit: %s ===" % (str(self.fitness))
+        msg2 = ["P%-3d  %s......|.....%s" % (i, v, sasmodel.getParam(v))
+                for i,v in pars if v in self.param_list]
+        msg = [msg1, msg3] + msg2
+        return "\n".join(msg)
     
     def print_summary(self):
         """
         """
-        print self
+        print str(self)
Index: src/sans/fit/BumpsFitting.py
===================================================================
--- src/sans/fit/BumpsFitting.py	(revision eff93b8d577de85b34ffd99e484da07484c35580)
+++ src/sans/fit/BumpsFitting.py	(revision eff93b8d577de85b34ffd99e484da07484c35580)
@@ -0,0 +1,270 @@
+"""
+BumpsFitting module runs the bumps optimizer.
+"""
+import numpy
+
+from bumps import fitters
+from bumps.mapper import SerialMapper
+from bumps import parameter
+from bumps.fitproblem import FitProblem
+
+from .AbstractFitEngine import FitEngine
+from .AbstractFitEngine import FResult
+from .expression import compile_constraints
+
+class BumpsMonitor(object):
+    def __init__(self, handler, max_step=0):
+        self.handler = handler
+        self.max_step = max_step
+
+    def config_history(self, history):
+        history.requires(time=1, value=2, point=1, step=1)
+
+    def __call__(self, history):
+        if self.handler is None: return
+        self.handler.progress(history.step[0], self.max_step)
+        if len(history.step)>1 and history.step[1] > history.step[0]:
+            self.handler.improvement()
+        self.handler.update_fit()
+
+class ConvergenceMonitor(object):
+    """
+    ConvergenceMonitor contains population summary statistics to show progress
+    of the fit.  This is a list [ (best, 0%, 25%, 50%, 75%, 100%) ] or
+    just a list [ (best, ) ] if population size is 1.
+    """
+    def __init__(self):
+        self.convergence = []
+
+    def config_history(self, history):
+        history.requires(value=1, population_values=1)
+
+    def __call__(self, history):
+        best = history.value[0]
+        try:
+            p = history.population_values[0]
+            n,p = len(p), numpy.sort(p)
+            QI,Qmid, = int(0.2*n),int(0.5*n)
+            self.convergence.append((best, p[0],p[QI],p[Qmid],p[-1-QI],p[-1]))
+        except:
+            self.convergence.append((best, best,best,best,best,best))
+
+
+# Note: currently using bumps parameters for each parameter object so that
+# a SasFitness can be used directly in bumps with the usual semantics.
+# The disadvantage of this technique is that we need to copy every parameter
+# back into the model each time the function is evaluated.  We could instead
+# define reference parameters for each sans parameter, but then we would not
+# be able to express constraints using python expressions in the usual way
+# from bumps, and would instead need to use string expressions.
+class SasFitness(object):
+    """
+    Wrap SAS model as a bumps fitness object
+    """
+    def __init__(self, model, data, fitted=[], constraints={}, **kw):
+        self.name = model.name
+        self.model = model.model
+        self.data = data
+        self._define_pars()
+        self._init_pars(kw)
+        self.constraints = dict(constraints)
+        self.set_fitted(fitted)
+        self._dirty = True
+
+    def _define_pars(self):
+        self._pars = {}
+        for k in self.model.getParamList():
+            name = ".".join((self.name,k))
+            value = self.model.getParam(k)
+            bounds = self.model.details.get(k,["",None,None])[1:3]
+            self._pars[k] = parameter.Parameter(value=value, bounds=bounds,
+                                                fixed=True, name=name)
+        #print parameter.summarize(self._pars.values())
+
+    def _init_pars(self, kw):
+        for k,v in kw.items():
+            # dispersion parameters initialized with _field instead of .field
+            if k.endswith('_width'): k = k[:-6]+'.width'
+            elif k.endswith('_npts'): k = k[:-5]+'.npts'
+            elif k.endswith('_nsigmas'): k = k[:-7]+'.nsigmas'
+            elif k.endswith('_type'): k = k[:-5]+'.type'
+            if k not in self._pars:
+                formatted_pars = ", ".join(sorted(self._pars.keys()))
+                raise KeyError("invalid parameter %r for %s--use one of: %s"
+                               %(k, self.model, formatted_pars))
+            if '.' in k and not k.endswith('.width'):
+                self.model.setParam(k, v)
+            elif isinstance(v, parameter.BaseParameter):
+                self._pars[k] = v
+            elif isinstance(v, (tuple,list)):
+                low, high = v
+                self._pars[k].value = (low+high)/2
+                self._pars[k].range(low,high)
+            else:
+                self._pars[k].value = v
+        self.update()
+
+    def set_fitted(self, param_list):
+        """
+        Flag a set of parameters as fitted parameters.
+        """
+        for k,p in self._pars.items():
+            p.fixed = (k not in param_list or k in self.constraints)
+        self.fitted_pars = [self._pars[k] for k in param_list if k not in self.constraints]
+        self.fitted_par_names = [k for k in param_list if k not in self.constraints]
+
+    # ===== Fitness interface ====
+    def parameters(self):
+        return self._pars
+
+    def update(self):
+        for k,v in self._pars.items():
+            #print "updating",k,v,v.value
+            self.model.setParam(k,v.value)
+        self._dirty = True
+
+    def _recalculate(self):
+        if self._dirty:
+            self._residuals, self._theory = self.data.residuals(self.model.evalDistribution)
+            self._dirty = False
+
+    def numpoints(self):
+        return numpy.sum(self.data.idx) # number of fitted points
+
+    def nllf(self):
+        return 0.5*numpy.sum(self.residuals()**2)
+
+    def theory(self):
+        self._recalculate()
+        return self._theory
+
+    def residuals(self):
+        self._recalculate()
+        return self._residuals
+
+    # Not implementing the data methods for now:
+    #
+    #     resynth_data/restore_data/save/plot
+
+class BumpsFit(FitEngine):
+    """
+    Fit a model using bumps.
+    """
+    def __init__(self):
+        """
+        Creates a dictionary (self.fit_arrange_dict={})of FitArrange elements
+        with Uid as keys
+        """
+        FitEngine.__init__(self)
+        self.curr_thread = None
+
+    def fit(self, msg_q=None,
+            q=None, handler=None, curr_thread=None,
+            ftol=1.49012e-8, reset_flag=False):
+        # Build collection of bumps fitness calculators
+        models = [ SasFitness(model=M.get_model(),
+                              data=M.get_data(),
+                              constraints=M.constraints,
+                              fitted=M.pars)
+                   for i,M in enumerate(self.fit_arrange_dict.values())
+                   if M.get_to_fit() == 1 ]
+        if len(models) == 0:
+            raise RuntimeError("Nothing to fit")
+        problem = FitProblem(models)
+
+
+        # Build constraint expressions
+        exprs = {}
+        for M in models:
+            exprs.update((".".join((M.name,k)),v) for k,v in M.constraints.items())
+        if exprs:
+            symtab = dict((".".join((M.name,k)),p)
+                          for M in models
+                          for k,p in M.parameters().items())
+            constraints = compile_constraints(symtab,exprs)
+        else:
+            constraints = lambda: 0
+
+        # Override model update so that parameter constraints are applied
+        problem._model_update = problem.model_update
+        def model_update():
+            constraints()
+            problem._model_update()
+        problem.model_update = model_update
+
+        # Run the fit
+        result = run_bumps(problem, handler, curr_thread)
+        if handler is not None:
+            handler.update_fit(last=True)
+
+        # TODO: shouldn't reference internal parameters of fit problem
+        varying = problem._parameters
+        # collect the results
+        all_results = []
+        for M in problem.models:
+            fitness = M.fitness
+            fitted_index = [varying.index(p) for p in fitness.fitted_pars]
+            R = FResult(model=fitness.model, data=fitness.data,
+                        param_list=fitness.fitted_par_names)
+            R.theory = fitness.theory()
+            R.residuals = fitness.residuals()
+            R.fitter_id = self.fitter_id
+            # TODO: should scale stderr by sqrt(chisq/DOF) if dy is unknown
+            R.stderr = result['stderr'][fitted_index]
+            R.pvec = result['value'][fitted_index]
+            R.success = result['success']
+            R.fitness = numpy.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index))
+            R.convergence = result['convergence']
+            if result['uncertainty'] is not None:
+                R.uncertainty_state = result['uncertainty']
+            all_results.append(R)
+
+        if q is not None:
+            q.put(all_results)
+            return q
+        else:
+            return all_results
+
+def run_bumps(problem, handler, curr_thread):
+    def abort_test():
+        if curr_thread is None: return False
+        try: curr_thread.isquit()
+        except KeyboardInterrupt:
+            if handler is not None:
+                handler.stop("Fitting: Terminated!!!")
+            return True
+        return False
+
+    fitopts = fitters.FIT_OPTIONS[fitters.FIT_DEFAULT]
+    fitclass = fitopts.fitclass
+    options = fitopts.options.copy()
+    max_step = fitopts.options.get('steps', 0) + fitopts.options.get('burn', 0)
+    options['monitors'] = [
+        BumpsMonitor(handler, max_step),
+        ConvergenceMonitor(),
+        ]
+    fitdriver = fitters.FitDriver(fitclass, problem=problem,
+                                  abort_test=abort_test, **options)
+    mapper = SerialMapper 
+    fitdriver.mapper = mapper.start_mapper(problem, None)
+    #import time; T0 = time.time()
+    try:
+        best, fbest = fitdriver.fit()
+    except:
+        import traceback; traceback.print_exc()
+        raise
+    finally:
+        mapper.stop_mapper(fitdriver.mapper)
+
+
+    convergence_list = options['monitors'][-1].convergence
+    convergence = (2*numpy.asarray(convergence_list)/problem.dof
+                   if convergence_list else numpy.empty((0,1),'d'))
+    return {
+        'value': best,
+        'stderr': fitdriver.stderr(),
+        'success': True, # better success reporting in bumps
+        'convergence': convergence,
+        'uncertainty': getattr(fitdriver.fitter, 'state', None),
+        }
+
Index: src/sans/fit/Fitting.py
===================================================================
--- src/sans/fit/Fitting.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/fit/Fitting.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
@@ -8,5 +8,11 @@
 from sans.fit.ScipyFitting import ScipyFit
 from sans.fit.ParkFitting import ParkFit
+from sans.fit.BumpsFitting import BumpsFit
 
+ENGINES={
+    'scipy': ScipyFit,
+    'park': ParkFit,
+    'bumps': BumpsFit,
+}
 
 class Fit(object):
@@ -26,5 +32,5 @@
         
     """  
-    def __init__(self, engine='scipy'):
+    def __init__(self, engine='scipy', *args, **kw):
         """
         """
@@ -32,5 +38,5 @@
         self._engine = None
         self.fitter_id = None
-        self.set_engine(engine)
+        self.set_engine(engine, *args, **kw)
           
     def __setattr__(self, name, value):
@@ -49,5 +55,5 @@
             self.__dict__[name] = value
                 
-    def set_engine(self, word):
+    def set_engine(self, word, *args, **kw):
         """
         Select the type of Fit 
@@ -59,10 +65,8 @@
              
         """
-        if word == "scipy":
-            self._engine = ScipyFit()
-        elif word == "park":
-            self._engine = ParkFit()
-        else:
-            raise ValueError, "enter the keyword scipy or park"
+        try:
+            self._engine = ENGINES[word](*args, **kw)
+        except KeyError, exc:
+            raise KeyError("fit engine should be one of scipy, park or bumps")
 
     def fit(self, msg_q=None, q=None, handler=None, 
Index: src/sans/fit/Loader.py
===================================================================
--- src/sans/fit/Loader.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/fit/Loader.py	(revision 6fe51002a81260397b29374005fb3e465ff93b4a)
@@ -8,6 +8,6 @@
     This class is loading values from given file or value giving by the user
     """
-    
     def __init__(self, x=None, y=None, dx=None, dy=None):
+        raise NotImplementedError("a code search shows that this code is not active, and you are not seeing this message")
         # variable to store loaded values
         self.x = x
Index: src/sans/fit/ParkFitting.py
===================================================================
--- src/sans/fit/ParkFitting.py	(revision 9d6d5bac0acbf70af7fa2fc5a5951c6d7a8c9f91)
+++ src/sans/fit/ParkFitting.py	(revision 8d074d926d99193a8c902448957d621abd9235d5)
@@ -24,5 +24,156 @@
 from sans.fit.AbstractFitEngine import FitEngine
 from sans.fit.AbstractFitEngine import FResult
-  
+
+class SansParameter(park.Parameter):
+    """
+    SANS model parameters for use in the PARK fitting service.
+    The parameter attribute value is redirected to the underlying
+    parameter value in the SANS model.
+    """
+    def __init__(self, name, model, data):
+        """
+            :param name: the name of the model parameter
+            :param model: the sans model to wrap as a park model
+        """
+        park.Parameter.__init__(self, name)
+        #self._model, self._name = model, name
+        self.data = data
+        self.model = model
+        #set the value for the parameter of the given name
+        self.set(model.getParam(name))
+
+        # TODO: model is missing parameter ranges for dispersion parameters
+        if name not in model.details:
+            #print "setting details for",name
+            model.details[name] = ["", None, None]
+
+    def _getvalue(self):
+        """
+        override the _getvalue of park parameter
+
+        :return value the parameter associates with self.name
+
+        """
+        return self.model.getParam(self.name)
+
+    def _setvalue(self, value):
+        """
+        override the _setvalue pf park parameter
+
+        :param value: the value to set on a given parameter
+
+        """
+        self.model.setParam(self.name, value)
+
+    value = property(_getvalue, _setvalue)
+
+    def _getrange(self):
+        """
+        Override _getrange of park parameter
+        return the range of parameter
+        """
+        #if not  self.name in self._model.getDispParamList():
+        lo, hi = self.model.details[self.name][1:3]
+        if lo is None: lo = -numpy.inf
+        if hi is None: hi = numpy.inf
+        if lo > hi:
+            raise ValueError, "wrong fit range for parameters"
+
+        return lo, hi
+
+    def get_name(self):
+        """
+        """
+        return self._getname()
+
+    def _setrange(self, r):
+        """
+        override _setrange of park parameter
+
+        :param r: the value of the range to set
+
+        """
+        self.model.details[self.name][1:3] = r
+    range = property(_getrange, _setrange)
+
+
+class ParkModel(park.Model):
+    """
+    PARK wrapper for SANS models.
+    """
+    def __init__(self, sans_model, sans_data=None, **kw):
+        """
+        :param sans_model: the sans model to wrap using park interface
+
+        """
+        park.Model.__init__(self, **kw)
+        self.model = sans_model
+        self.name = sans_model.name
+        self.data = sans_data
+        #list of parameters names
+        self.sansp = sans_model.getParamList()
+        #list of park parameter
+        self.parkp = [SansParameter(p, sans_model, sans_data) for p in self.sansp]
+        #list of parameter set
+        self.parameterset = park.ParameterSet(sans_model.name, pars=self.parkp)
+        self.pars = []
+
+    def get_params(self, fitparams):
+        """
+        return a list of value of paramter to fit
+
+        :param fitparams: list of paramaters name to fit
+
+        """
+        list_params = []
+        self.pars = fitparams
+        for item in fitparams:
+            for element in self.parkp:
+                if element.name == str(item):
+                    list_params.append(element.value)
+        return list_params
+
+    def set_params(self, paramlist, params):
+        """
+        Set value for parameters to fit
+
+        :param params: list of value for parameters to fit
+
+        """
+        try:
+            for i in range(len(self.parkp)):
+                for j in range(len(paramlist)):
+                    if self.parkp[i].name == paramlist[j]:
+                        self.parkp[i].value = params[j]
+                        self.model.setParam(self.parkp[i].name, params[j])
+        except:
+            raise
+
+    def eval(self, x):
+        """
+            Override eval method of park model.
+
+            :param x: the x value used to compute a function
+        """
+        try:
+            return self.model.evalDistribution(x)
+        except:
+            raise
+
+    def eval_derivs(self, x, pars=[]):
+        """
+        Evaluate the model and derivatives wrt pars at x.
+
+        pars is a list of the names of the parameters for which derivatives
+        are desired.
+
+        This method needs to be specialized in the model to evaluate the
+        model function.  Alternatively, the model can implement is own
+        version of residuals which calculates the residuals directly
+        instead of calling eval.
+        """
+        return []
+
+
 class SansFitResult(fitresult.FitResult):
     def __init__(self, *args, **kwrds):
@@ -244,5 +395,5 @@
         return fitpars
     
-    def all_results(self, result):
+    def extend_results_with_calculated_parameters(self, result):
         """
         Extend result from the fit with the calculated parameters.
@@ -292,10 +443,10 @@
                 # dividing residuals by N in order to be consistent with Scipy
                 m.chisq = numpy.sum(m.residuals**2/N) 
-                resid.append(m.weight*m.residuals/math.sqrt(N))
+                resid.append(m.weight*m.residuals)
         self.residuals = numpy.hstack(resid)
         N = len(self.residuals)
         self.degrees_of_freedom = N-k if N>k else 1
         self.chisq = numpy.sum(self.residuals**2)
-        return self.chisq
+        return self.chisq/self.degrees_of_freedom
     
 class ParkFit(FitEngine):
@@ -354,9 +505,10 @@
             if fproblem.get_to_fit() == 1:
                 fitproblems.append(fproblem)
-        if len(fitproblems) == 0: 
+        if len(fitproblems) == 0:
             raise RuntimeError, "No Assembly scheduled for Park fitting."
-            return
         for item in fitproblems:
-            parkmodel = item.get_model()
+            model = item.get_model()
+            parkmodel = ParkModel(model.model, model.data)
+            parkmodel.pars = item.pars
             if reset_flag:
                 # reset the initial value; useful for batch
@@ -364,9 +516,13 @@
                     ind = item.pars.index(name)
                     parkmodel.model.setParam(name, item.vals[ind])
+
+            # set the constraints into the model
+            for p,v in item.constraints:
+                parkmodel.parameterset[str(p)].set(str(v))
             
             for p in parkmodel.parameterset:
                 ## does not allow status change for constraint parameters
                 if p.status != 'computed':
-                    if p.get_name()in item.pars:
+                    if p.get_name() in item.pars:
                         ## make parameters selected for 
                         #fit will be between boundaries
@@ -383,5 +539,5 @@
     def fit(self, msg_q=None, 
             q=None, handler=None, curr_thread=None, 
-                                        ftol=1.49012e-8, reset_flag=False):
+            ftol=1.49012e-8, reset_flag=False):
         """
         Performs fit with park.fit module.It can  perform fit with one model
@@ -407,5 +563,6 @@
         localfit = SansFitSimplex()
         localfit.ftol = ftol
-        
+        localfit.xtol = 1e-6
+
         # See `park.fitresult.FitHandler` for details.
         fitter = SansFitMC(localfit=localfit, start_points=1)
@@ -416,8 +573,11 @@
         try:
             result = fit.fit(self.problem, fitter=fitter, handler=handler)
-            self.problem.all_results(result)
+            self.problem.extend_results_with_calculated_parameters(result)
             
         except LinAlgError:
             raise ValueError, "SVD did not converge"
+
+        if result is None:
+            raise RuntimeError("park did not return a fit result")
     
         for m in self.problem.parts:
@@ -427,22 +587,26 @@
             small_result.theory = theory
             small_result.residuals = residuals
-            small_result.pvec = []
-            small_result.cov = []
-            small_result.stderr = []
-            small_result.param_list = []
-            small_result.residuals = m.residuals
-            if result is not None:
-                for p in result.parameters:
-                    if p.data.name == small_result.data.name and \
-                            p.model.name == small_result.model.name:
-                        small_result.index = m.data.idx
-                        small_result.fitness = result.fitness
-                        small_result.pvec.append(p.value)
-                        small_result.stderr.append(p.stderr)
-                        name_split = p.name.split('.')
-                        name = name_split[1].strip()
-                        if len(name_split) > 2:
-                            name += '.' + name_split[2].strip()
-                        small_result.param_list.append(name)
+            small_result.index = m.data.idx
+            small_result.fitness = result.fitness
+
+            # Extract the parameters that are part of this model; make sure
+            # they match the fitted parameters for this model, and place them
+            # in the same order as they occur in the model.
+            pars = {}
+            for p in result.parameters:
+                #if p.data.name == small_result.data.name and
+                if p.model.name == small_result.model.name:
+                    model_name, par_name = p.name.split('.', 1)
+                    pars[par_name] = (p.value, p.stderr)
+            #assert len(pars.keys()) == len(m.model.pars)
+            v,dv = zip(*[pars[p] for p in m.model.pars])
+            small_result.pvec = v
+            small_result.stderr = dv
+            small_result.param_list = m.model.pars
+
+            # normalize chisq by degrees of freedom
+            dof = len(small_result.residuals)-len(small_result.pvec)
+            small_result.fitness = numpy.sum(residuals**2)/dof
+
             result_list.append(small_result)    
         if q != None:
Index: src/sans/fit/ScipyFitting.py
===================================================================
--- src/sans/fit/ScipyFitting.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/fit/ScipyFitting.py	(revision 8d074d926d99193a8c902448957d621abd9235d5)
@@ -1,4 +1,2 @@
-
-
 """
 ScipyFitting module contains FitArrange , ScipyFit,
@@ -6,14 +4,136 @@
 simple fit with scipy optimizer.
 """
+import sys
+import copy
 
 import numpy 
-import sys
-
 
 from sans.fit.AbstractFitEngine import FitEngine
-from sans.fit.AbstractFitEngine import SansAssembly
-from sans.fit.AbstractFitEngine import FitAbort
-from sans.fit.AbstractFitEngine import Model
-from sans.fit.AbstractFitEngine import FResult 
+from sans.fit.AbstractFitEngine import FResult
+
+class SansAssembly:
+    """
+    Sans Assembly class a class wrapper to be call in optimizer.leastsq method
+    """
+    def __init__(self, paramlist, model=None, data=None, fitresult=None,
+                 handler=None, curr_thread=None, msg_q=None):
+        """
+        :param Model: the model wrapper fro sans -model
+        :param Data: the data wrapper for sans data
+
+        """
+        self.model = model
+        self.data = data
+        self.paramlist = paramlist
+        self.msg_q = msg_q
+        self.curr_thread = curr_thread
+        self.handler = handler
+        self.fitresult = fitresult
+        self.res = []
+        self.true_res = []
+        self.func_name = "Functor"
+        self.theory = None
+
+    def chisq(self):
+        """
+        Calculates chi^2
+
+        :param params: list of parameter values
+
+        :return: chi^2
+
+        """
+        total = 0
+        for item in self.true_res:
+            total += item * item
+        if len(self.true_res) == 0:
+            return None
+        return total / (len(self.true_res) - len(self.paramlist))
+
+    def __call__(self, params):
+        """
+            Compute residuals
+            :param params: value of parameters to fit
+        """
+        #import thread
+        self.model.set_params(self.paramlist, params)
+        #print "params", params
+        self.true_res, theory = self.data.residuals(self.model.eval)
+        self.theory = copy.deepcopy(theory)
+        # check parameters range
+        if self.check_param_range():
+            # if the param value is outside of the bound
+            # just silent return res = inf
+            return self.res
+        self.res = self.true_res
+
+        if self.fitresult is not None:
+            self.fitresult.set_model(model=self.model)
+            self.fitresult.residuals = self.true_res
+            self.fitresult.iterations += 1
+            self.fitresult.theory = theory
+
+            #fitness = self.chisq(params=params)
+            fitness = self.chisq()
+            self.fitresult.pvec = params
+            self.fitresult.set_fitness(fitness=fitness)
+            if self.msg_q is not None:
+                self.msg_q.put(self.fitresult)
+
+            if self.handler is not None:
+                self.handler.set_result(result=self.fitresult)
+                self.handler.update_fit()
+
+            if self.curr_thread != None:
+                try:
+                    self.curr_thread.isquit()
+                except:
+                    #msg = "Fitting: Terminated...       Note: Forcing to stop "
+                    #msg += "fitting may cause a 'Functor error message' "
+                    #msg += "being recorded in the log file....."
+                    #self.handler.stop(msg)
+                    raise
+
+        return self.res
+
+    def check_param_range(self):
+        """
+        Check the lower and upper bound of the parameter value
+        and set res to the inf if the value is outside of the
+        range
+        :limitation: the initial values must be within range.
+        """
+
+        #time.sleep(0.01)
+        is_outofbound = False
+        # loop through the fit parameters
+        model = self.model.model
+        for p in self.paramlist:
+            value = model.getParam(p)
+            low,high = model.details[p][1:3]
+            if low is not None and numpy.isfinite(low):
+                if p.value == 0:
+                    # This value works on Scipy
+                    # Do not change numbers below
+                    value = _SMALLVALUE
+                # For leastsq, it needs a bit step back from the boundary
+                val = low - value * _SMALLVALUE
+                if value < val:
+                    self.res *= 1e+6
+                    is_outofbound = True
+                    break
+            if high is not None and numpy.isfinite(high):
+                # This value works on Scipy
+                # Do not change numbers below
+                if value == 0:
+                    value = _SMALLVALUE
+                # For leastsq, it needs a bit step back from the boundary
+                val = high + value * _SMALLVALUE
+                if value > val:
+                    self.res *= 1e+6
+                    is_outofbound = True
+                    break
+
+        return is_outofbound
 
 class ScipyFit(FitEngine):
@@ -50,6 +170,4 @@
         """
         FitEngine.__init__(self)
-        self.fit_arrange_dict = {}
-        self.param_list = []
         self.curr_thread = None
     #def fit(self, *args, **kw):
@@ -68,8 +186,6 @@
             msg = "Scipy can't fit more than a single fit problem at a time."
             raise RuntimeError, msg
-            return
-        elif len(fitproblem) == 0 : 
+        elif len(fitproblem) == 0 :
             raise RuntimeError, "No Assembly scheduled for Scipy fitting."
-            return
         model = fitproblem[0].get_model()
         if reset_flag:
@@ -87,11 +203,17 @@
         
         # Check the initial value if it is within range
-        self._check_param_range(model)
+        _check_param_range(model.model, self.param_list)
         
-        result = FResult(model=model, data=data, param_list=self.param_list)
-        result.pars = fitproblem[0].pars
+        result = FResult(model=model.model, data=data, param_list=self.param_list)
         result.fitter_id = self.fitter_id
         if handler is not None:
             handler.set_result(result=result)
+        functor = SansAssembly(paramlist=self.param_list,
+                               model=model,
+                               data=data,
+                               handler=handler,
+                               fitresult=result,
+                               curr_thread=curr_thread,
+                               msg_q=msg_q)
         try:
             # This import must be here; otherwise it will be confused when more
@@ -99,15 +221,8 @@
             from scipy import optimize
             
-            functor = SansAssembly(paramlist=self.param_list, 
-                                   model=model, 
-                                   data=data,
-                                    handler=handler,
-                                    fitresult=result,
-                                     curr_thread=curr_thread,
-                                     msg_q=msg_q)
             out, cov_x, _, mesg, success = optimize.leastsq(functor,
                                             model.get_params(self.param_list),
-                                                    ftol=ftol,
-                                                    full_output=1)
+                                            ftol=ftol,
+                                            full_output=1)
         except:
             if hasattr(sys, 'last_type') and sys.last_type == KeyboardInterrupt:
@@ -142,58 +257,35 @@
 
         
-    def _check_param_range(self, model):
-        """
-        Check parameter range and set the initial value inside 
-        if it is out of range.
-        
-        : model: park model object
-        """
-        is_outofbound = False
-        # loop through parameterset
-        for p in model.parameterset:        
-            param_name = p.get_name()
-            # proceed only if the parameter name is in the list of fitting
-            if param_name in self.param_list:
-                # if the range was defined, check the range
-                if numpy.isfinite(p.range[0]):
-                    if p.value <= p.range[0]: 
-                        # 10 % backing up from the border if not zero
-                        # for Scipy engine to work properly.
-                        shift = self._get_zero_shift(p.range[0])
-                        new_value = p.range[0] + shift
-                        p.value =  new_value
-                        is_outofbound = True
-                if numpy.isfinite(p.range[1]):
-                    if p.value >= p.range[1]:
-                        shift = self._get_zero_shift(p.range[1])
-                        # 10 % backing up from the border if not zero
-                        # for Scipy engine to work properly.
-                        new_value = p.range[1] - shift
-                        # Check one more time if the new value goes below
-                        # the low bound, If so, re-evaluate the value 
-                        # with the mean of the range.
-                        if numpy.isfinite(p.range[0]):
-                            if new_value < p.range[0]:
-                                new_value = (p.range[0] + p.range[1]) / 2.0
-                        # Todo: 
-                        # Need to think about when both min and max are same.
-                        p.value =  new_value
-                        is_outofbound = True
-                        
-        return is_outofbound
-    
-    def _get_zero_shift(self, range):
-        """
-        Get 10% shift of the param value = 0 based on the range value
-        
-        : param range: min or max value of the bounds
-        """
-        if range == 0:
-            shift = 0.1
-        else:
-            shift = 0.1 * range
-            
-        return shift
-    
+def _check_param_range(model, param_list):
+    """
+    Check parameter range and set the initial value inside
+    if it is out of range.
+
+    : model: park model object
+    """
+    # loop through parameterset
+    for p in param_list:
+        value = model.getParam(p)
+        low,high = model.details.setdefault(p,["",None,None])[1:3]
+        # if the range was defined, check the range
+        if low is not None and value <= low:
+            value = low + _get_zero_shift(low)
+        if high is not None and value > high:
+            value = high - _get_zero_shift(high)
+            # Check one more time if the new value goes below
+            # the low bound, If so, re-evaluate the value
+            # with the mean of the range.
+            if low is not None and value < low:
+                value = 0.5 * (low+high)
+        model.setParam(p, value)
+
+def _get_zero_shift(limit):
+    """
+    Get 10% shift of the param value = 0 based on the range value
+
+    : param range: min or max value of the bounds
+    """
+    return 0.1 * (limit if limit != 0.0 else 1.0)
+
     
 #def profile(fn, *args, **kw):
Index: src/sans/fit/__init__.py
===================================================================
--- src/sans/fit/__init__.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/fit/__init__.py	(revision 6fe51002a81260397b29374005fb3e465ff93b4a)
@@ -0,0 +1,1 @@
+from .AbstractFitEngine import FitHandler
Index: src/sans/fit/expression.py
===================================================================
--- src/sans/fit/expression.py	(revision 4e9f22702695459c7a6c8721061aab9d9e4ef437)
+++ src/sans/fit/expression.py	(revision 4e9f22702695459c7a6c8721061aab9d9e4ef437)
@@ -0,0 +1,400 @@
+# This program is public domain
+"""
+Parameter expression evaluator.
+
+For systems in which constraints are expressed as string expressions rather
+than python code, :func:`compile_constraints` can construct an expression
+evaluator that substitutes the computed values of the expressions into the
+parameters.
+
+The compiler requires a symbol table, an expression set and a context.
+The symbol table maps strings containing fully qualified names such as
+'M1.c[3].full_width' to parameter objects with a 'value' property that
+can be queried and set.  The expression set maps symbol names from the
+symbol table to string expressions.  The context provides additional symbols
+for the expressions in addition to the usual mathematical functions and
+constants.
+
+The expressions are compiled and interpreted by python, with only minimal
+effort to make sure that they don't contain bad code.  The resulting
+constraints function returns 0 so it can be used directly in a fit problem
+definition.
+
+Extracting the symbol table from the model depends on the structure of the
+model.  If fitness.parameters() is set correctly, then this should simply
+be a matter of walking the parameter data, remembering the path to each
+parameter in the symbol table.  For compactness, dictionary elements should
+be referenced by .name rather than ["name"].  Model name can be used as the
+top level.
+
+Getting the parameter expressions applied correctly is challenging.
+The following monkey patch works by overriding model_update in FitProblem
+so that after setp(p) is called and, the constraints expression can be
+applied before telling the underlying fitness function that the model
+is out of date::
+
+        # Override model update so that parameter constraints are applied
+        problem._model_update = problem.model_update
+        def model_update():
+            constraints()
+            problem._model_update()
+        problem.model_update = model_update
+
+Ideally, this interface will change
+"""
+import math
+import re
+
+# simple pattern which matches symbols.  Note that it will also match
+# invalid substrings such as a3...9, but given syntactically correct
+# input it will only match symbols.
+_symbol_pattern = re.compile('([a-zA-Z_][a-zA-Z_0-9.]*)')
+
+def _symbols(expr,symtab):
+    """
+    Given an expression string and a symbol table, return the set of symbols
+    used in the expression.  Symbols are only returned once even if they
+    occur multiple times.  The return value is a set with the elements in
+    no particular order.
+    
+    This is the first step in computing a dependency graph.
+    """
+    matches = [m.group(0) for m in _symbol_pattern.finditer(expr)]
+    return set([symtab[m] for m in matches if m in symtab])
+
+def _substitute(expr,mapping):
+    """
+    Replace all occurrences of symbol s with mapping[s] for s in mapping.
+    """
+    # Find the symbols and the mapping
+    matches = [(m.start(),m.end(),mapping[m.group(1)])
+               for m in _symbol_pattern.finditer(expr)
+               if m.group(1) in mapping]
+
+    # Split the expression in to pieces, with new symbols replacing old
+    pieces = []
+    offset = 0
+    for start,end,text in matches:
+        pieces += [expr[offset:start],text]
+        offset = end
+    pieces.append(expr[offset:])
+    
+    # Join the pieces and return them
+    return "".join(pieces)
+
+def _find_dependencies(symtab, exprs):
+    """
+    Returns a list of pair-wise dependencies from the parameter expressions.
+    
+    For example, if p3 = p1+p2, then find_dependencies([p1,p2,p3]) will
+    return [(p3,p1),(p3,p2)].  For base expressions without dependencies,
+    such as p4 = 2*pi, this should return [(p4, None)]
+    """
+    deps = [(target,source)
+            for target,expr in exprs.items()
+            for source in _symbols_or_none(expr,symtab)]
+    return deps
+
+# Hack to deal with expressions without dependencies --- return a fake
+# dependency of None.
+# The better solution is fix order_dependencies so that it takes a
+# dictionary of {symbol: dependency_list}, for which no dependencies
+# is simply []; fix in parameter_mapping as well
+def _symbols_or_none(expr,symtab):
+    syms = _symbols(expr,symtab)
+    return syms if len(syms) else [None]
+
+def _parameter_mapping(pairs):
+    """
+    Find the parameter substitution we need so that expressions can
+    be evaluated without having to traverse a chain of 
+    model.layer.parameter.value
+    """
+    left,right = zip(*pairs)
+    pars = list(sorted(p for p in set(left+right) if p is not None))
+    definition = dict( ('P%d'%i,p)  for i,p in enumerate(pars) )
+    # p is None when there is an expression with no dependencies
+    substitution = dict( (p,'P%d.value'%i)
+                    for i,p in enumerate(sorted(pars))
+                    if p is not None)
+    return definition, substitution
+
+def no_constraints(): 
+    """
+    This parameter set has no constraints between the parameters.
+    """
+    pass
+
+def compile_constraints(symtab, exprs, context={}):
+    """
+    Build and return a function to evaluate all parameter expressions in
+    the proper order.
+
+    Input:
+
+        *symtab* is the symbol table for the model: { 'name': parameter }
+
+        *exprs* is the set of computed symbols: { 'name': 'expression' }
+
+        *context* is any additional context needed to evaluate the expression
+
+    Return:
+
+        updater function which sets parameter.value for each expression
+
+    Raises:
+
+       AssertionError - model, parameter or function is missing
+
+       SyntaxError - improper expression syntax
+
+       ValueError - expressions have circular dependencies
+
+    This function is not terribly sophisticated, and it would be easy to
+    trick.  However it handles the common cases cleanly and generates
+    reasonable messages for the common errors.
+
+    This code has not been fully audited for security.  While we have
+    removed the builtins and the ability to import modules, there may
+    be other vectors for users to perform more than simple function
+    evaluations.  Unauthenticated users should not be running this code.
+
+    Parameter names are assumed to contain only _.a-zA-Z0-9#[]
+    
+    Both names are provided for inverse functions, e.g., acos and arccos.
+
+    Should try running the function to identify syntax errors before
+    running it in a fit.
+    
+    Use help(fn) to see the code generated for the returned function fn.
+    dis.dis(fn) will show the corresponding python vm instructions.
+    """
+
+    # Sort the parameters in the order they need to be evaluated
+    deps = _find_dependencies(symtab, exprs)
+    if deps == []: return no_constraints
+    order = order_dependencies(deps)
+
+
+    # Rather than using the full path to the parameters in the parameter
+    # expressions, instead use Pn, and substitute Pn.value for each occurrence
+    # of the parameter in the expression.
+    names = list(sorted(symtab.keys()))
+    parameters = dict(('P%d'%i, symtab[k]) for i,k in enumerate(names))
+    mapping = dict((k, 'P%d.value'%i) for i,k in enumerate(names))
+
+
+    # Initialize dictionary with available functions
+    globals = {}
+    globals.update(math.__dict__)
+    globals.update(dict(arcsin=math.asin,arccos=math.acos,
+                        arctan=math.atan,arctan2=math.atan2))
+    globals.update(context)
+    globals.update(parameters)
+    globals['id'] = id
+    locals = {}
+
+    # Define the constraints function
+    assignments = ["=".join((p,exprs[p])) for p in order]
+    code = [_substitute(s, mapping) for s in assignments]
+    functiondef = """
+def eval_expressions():
+    '''
+    %s
+    '''
+    %s
+    return 0
+"""%("\n    ".join(assignments),"\n    ".join(code))
+
+    #print("Function: "+functiondef)
+    exec functiondef in globals,locals
+    retfn = locals['eval_expressions']
+
+    # Remove garbage added to globals by exec
+    globals.pop('__doc__',None)
+    globals.pop('__name__',None)
+    globals.pop('__file__',None)
+    globals.pop('__builtins__')
+    #print globals.keys()
+
+    return retfn
+
+def order_dependencies(pairs):
+    """
+    Order elements from pairs so that b comes before a in the
+    ordered list for all pairs (a,b).
+    """
+    #print "order_dependencies",pairs
+    emptyset = set()
+    order = []
+
+    # Break pairs into left set and right set
+    left,right = [set(s) for s in zip(*pairs)] if pairs != [] else ([],[])
+    while pairs != []:
+        #print "within",pairs
+        # Find which items only occur on the right
+        independent = right - left
+        if independent == emptyset:
+            cycleset = ", ".join(str(s) for s in left)
+            raise ValueError,"Cyclic dependencies amongst %s"%cycleset
+
+        # The possibly resolvable items are those that depend on the independents
+        dependent = set([a for a,b in pairs if b in independent])
+        pairs = [(a,b) for a,b in pairs if b not in independent]
+        if pairs == []:
+            resolved = dependent
+        else:
+            left,right = [set(s) for s in zip(*pairs)]
+            resolved = dependent - left
+        #print "independent",independent,"dependent",dependent,"resolvable",resolved
+        order += resolved
+        #print "new order",order
+    order.reverse()
+    return order
+
+# ========= Test code ========
+def _check(msg,pairs):
+    """
+    Verify that the list n contains the given items, and that the list
+    satisfies the partial ordering given by the pairs in partial order.
+    """
+    left,right = zip(*pairs) if pairs != [] else ([],[])
+    items = set(left)
+    n = order_dependencies(pairs)
+    if set(n) != items or len(n) != len(items):
+        n.sort()
+        items = list(items); items.sort()
+        raise Exception,"%s expect %s to contain %s for %s"%(msg,n,items,pairs)
+    for lo,hi in pairs:
+        if lo in n and hi in n and n.index(lo) >= n.index(hi):
+            raise Exception,"%s expect %s before %s in %s for %s"%(msg,lo,hi,n,pairs)
+
+def test_deps():
+    import numpy
+
+    # Null case
+    _check("test empty",[])
+
+    # Some dependencies
+    _check("test1",[(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)])
+    _check("test1 renumbered",[(6,1),(7,3),(7,4),(6,7),(5,7),(3,2)])
+    _check("test1 numpy",numpy.array([(2,7),(1,5),(1,4),(2,1),(3,1),(5,6)]))
+
+    # No dependencies
+    _check("test2",[(4,1),(3,2),(8,4)])
+
+    # Cycle test
+    pairs = [(1,4),(4,3),(4,5),(5,1)]
+    try: n = order_dependencies(pairs)
+    except ValueError: pass
+    else: raise Exception,"test3 expect ValueError exception for %s"%(pairs,)
+
+    # large test for gross speed check
+    A = numpy.random.randint(4000,size=(1000,2))
+    A[:,1] += 4000  # Avoid cycles
+    _check("test-large",A)
+
+    # depth tests
+    k = 200
+    A = numpy.array([range(0,k),range(1,k+1)]).T
+    _check("depth-1",A)
+
+    A = numpy.array([range(1,k+1),range(0,k)]).T
+    _check("depth-2",A)
+
+def test_expr():
+    import inspect, dis
+    import math
+    
+    symtab = {'a.b.x':1, 'a.c':2, 'a.b':3, 'b.x':4}
+    expr = 'a.b.x + sin(4*pi*a.c) + a.b.x/a.b'
+    
+    # Check symbol lookup
+    assert _symbols(expr, symtab) == set([1,2,3])
+
+    # Check symbol rename
+    assert _substitute(expr,{'a.b.x':'Q'}) == 'Q + sin(4*pi*a.c) + Q/a.b'
+    assert _substitute(expr,{'a.b':'Q'}) == 'a.b.x + sin(4*pi*a.c) + a.b.x/Q'
+
+
+    # Check dependency builder
+    # Fake parameter class
+    class Parameter:
+        def __init__(self, name, value=0, expression=''):
+            self.path = name
+            self.value = value
+            self.expression = expression
+        def iscomputed(self): return (self.expression != '')
+        def __repr__(self): return self.path
+    def world(*pars):
+        symtab = dict((p.path,p) for p in pars)
+        exprs = dict((p.path,p.expression) for p in pars if p.iscomputed())
+        return symtab, exprs
+    p1 = Parameter('G0.sigma',5)
+    p2 = Parameter('other',expression='2*pi*sin(G0.sigma/.1875) + M1.G1')
+    p3 = Parameter('M1.G1',6)
+    p4 = Parameter('constant',expression='2*pi*35')
+    # Simple chain
+    assert set(_find_dependencies(*world(p1,p2,p3))) == set([(p2.path,p1),(p2.path,p3)])
+    # Constant expression
+    assert set(_find_dependencies(*world(p1,p4))) == set([(p4.path,None)])
+    # No dependencies
+    assert set(_find_dependencies(*world(p1,p3))) == set([])
+
+    # Check function builder
+    fn = compile_constraints(*world(p1,p2,p3))
+
+    # Inspect the resulting function
+    if 0:
+        print(inspect.getdoc(fn))
+        print(dis.dis(fn))
+
+    # Evaluate the function and see if it updates the
+    # target value as expected
+    fn()
+    expected = 2*math.pi*math.sin(5/.1875) + 6
+    assert p2.value == expected,"Value was %s, not %s"%(p2.value,expected)
+    
+    # Check empty dependency set doesn't crash
+    fn = compile_constraints(*world(p1,p3))
+    fn()
+
+    # Check that constants are evaluated properly
+    fn = compile_constraints(*world(p4))
+    fn()
+    assert p4.value == 2*math.pi*35
+
+    # Check additional context example; this also tests multiple
+    # expressions
+    class Table:
+        Si = 2.09
+        values = {'Si': 2.07}
+    tbl = Table()
+    p5 = Parameter('lookup',expression="tbl.Si")
+    fn = compile_constraints(*world(p1,p2,p3,p5),context=dict(tbl=tbl))
+    fn()
+    assert p5.value == 2.09,"Value for %s was %s"%(p5.expression,p5.value)
+    p5.expression = "tbl.values['Si']"
+    fn = compile_constraints(*world(p1,p2,p3,p5),context=dict(tbl=tbl))
+    fn()
+    assert p5.value == 2.07,"Value for %s was %s"%(p5.expression,p5.value)
+    
+
+    # Verify that we capture invalid expressions
+    for expr in ['G4.cage', 'M0.cage', 'M1.G1 + *2', 
+                 'piddle',
+                 '5; import sys; print "p0wned"',
+                 '__import__("sys").argv']:
+        try:
+            p6 = Parameter('broken',expression=expr)
+            fn = compile_constraints(*world(p6))
+            fn()
+        except Exception as msg:
+            #print(msg)
+            pass
+        else:
+            raise "Failed to raise error for %s"%expr
+
+if __name__ == "__main__":
+    test_expr()
+    test_deps()
Index: src/sans/perspectives/fitting/basepage.py
===================================================================
--- src/sans/perspectives/fitting/basepage.py	(revision 116e1a745c824ae90452a0a866bede4b161d79f5)
+++ src/sans/perspectives/fitting/basepage.py	(revision 116e1a745c824ae90452a0a866bede4b161d79f5)
@@ -835,6 +835,6 @@
             infor = "warning"
         else:
-            msg = "Error was occured "
-            msg += ": No valid parameter values to paste from the clipboard..."
+            msg = "Error occured: "
+            msg += "No valid parameter values to paste from the clipboard..."
             infor = "error"
             wx.PostEvent(self._manager.parent,
@@ -2183,10 +2183,10 @@
                 else:
                     tcrtl.SetBackgroundColour("pink")
-                    msg = "Model Error:wrong value entered: %s" % sys.exc_value
+                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
                     wx.PostEvent(self.parent, StatusEvent(status=msg))
                     return
             except:
                 tcrtl.SetBackgroundColour("pink")
-                msg = "Model Error:wrong value entered: %s" % sys.exc_value
+                msg = "Model Error: wrong value entered: %s" % sys.exc_value
                 wx.PostEvent(self.parent, StatusEvent(status=msg))
                 return
@@ -2199,9 +2199,9 @@
                         #is_modified = True
                 else:
-                    msg = "Cannot Plot :No npts in that Qrange!!!  "
+                    msg = "Cannot plot: No points in Q range!!!  "
                     wx.PostEvent(self.parent, StatusEvent(status=msg))
         else:
             tcrtl.SetBackgroundColour("pink")
-            msg = "Model Error:wrong value entered!!!"
+            msg = "Model Error: wrong value entered!!!"
             wx.PostEvent(self.parent, StatusEvent(status=msg))
         self.save_current_state()
@@ -2240,10 +2240,10 @@
                 else:
                     tcrtl.SetBackgroundColour("pink")
-                    msg = "Model Error:wrong value entered: %s" % sys.exc_value
+                    msg = "Model Error: wrong value entered: %s" % sys.exc_value
                     wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
                     return
             except:
                 tcrtl.SetBackgroundColour("pink")
-                msg = "Model Error:wrong value entered: %s" % sys.exc_value
+                msg = "Model Error: wrong value entered: %s" % sys.exc_value
                 wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
                 return
@@ -2256,9 +2256,9 @@
                         is_modified = True
                 else:
-                    msg = "Cannot Plot :No npts in that Qrange!!!  "
+                    msg = "Cannot Plot: No points in Q range!!!  "
                     wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
         else:
             tcrtl.SetBackgroundColour("pink")
-            msg = "Model Error:wrong value entered!!!"
+            msg = "Model Error: wrong value entered!!!"
             wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
         self.save_current_state()
@@ -2431,6 +2431,6 @@
                 self.qmax.SetBackgroundColour("pink")
                 self.qmax.Refresh()
-                msg = "Npts of Data Error :"
-                msg += "No or too little npts of %s." % data.name
+                msg = "Data Error: "
+                msg += "Too few points in %s." % data.name
                 wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
                 self.fitrange = False
@@ -2466,6 +2466,6 @@
                 self.qmax.SetBackgroundColour("pink")
                 self.qmax.Refresh()
-                msg = "Npts of Data Error :"
-                msg += "No or too little npts of %s." % data.name
+                msg = "Data Error: "
+                msg += "Too few points in %s." % data.name
                 wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
                 self.fitrange = False
@@ -2518,5 +2518,5 @@
                                            
                         except:
-                            msg = "Wrong Fit parameter range entered "
+                            msg = "Wrong fit parameter range entered"
                             wx.PostEvent(self._manager.parent,
                                          StatusEvent(status=msg))
Index: src/sans/perspectives/fitting/console.py
===================================================================
--- src/sans/perspectives/fitting/console.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/perspectives/fitting/console.py	(revision 644ca73017baa0189f6424c93e070248941b265a)
@@ -5,6 +5,5 @@
 import time
 import wx
-import park
-from park.fitresult import FitHandler
+from sans.fit import FitHandler
 
 class ConsoleUpdate(FitHandler):
@@ -88,5 +87,5 @@
         Print result object
         """
-        msg = " \n %s \n" % self.result.__str__()
+        msg = " \n %s \n" % str(self.result)
         wx.PostEvent(self.parent, StatusEvent(status=msg))
                      
@@ -137,5 +136,5 @@
         self.fit_duration += self.elapsed_time
         str_time = time.strftime("%a, %d %b %Y %H:%M:%S ", time.localtime(t1))
-        UPDATE_INTERVAL = 0.5
+        UPDATE_INTERVAL = 5.0
         u_flag = False
         if self.fit_duration >= UPDATE_INTERVAL:
Index: src/sans/perspectives/fitting/fit_thread.py
===================================================================
--- src/sans/perspectives/fitting/fit_thread.py	(revision a855fec9ef18808f7423a1337764d7758ed5a7b8)
+++ src/sans/perspectives/fitting/fit_thread.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
@@ -18,10 +18,10 @@
     
     def __init__(self, 
-                  fn,
-                  page_id,
-                   handler,
-                    batch_outputs,
-                    batch_inputs=None,             
-                  pars=None,
+                 fn,
+                 page_id,
+                 handler,
+                 batch_outputs,
+                 batch_inputs=None,
+                 pars=None,
                  completefn = None,
                  updatefn   = None,
@@ -30,5 +30,6 @@
                  ftol       = None,
                  reset_flag = False):
-        CalcThread.__init__(self,completefn,
+        CalcThread.__init__(self,
+                 completefn,
                  updatefn,
                  yieldtime,
@@ -80,6 +81,6 @@
                 list_map_get_attr.append(map_getattr)
             #from multiprocessing import Pool
-            inputs = zip(list_map_get_attr,self.fitter, list_fit_function,
-                          list_q, list_q, list_handler,list_curr_thread,list_ftol,
+            inputs = zip(list_map_get_attr, self.fitter, list_fit_function,
+                         list_q, list_q, list_handler,list_curr_thread,list_ftol,
                          list_reset_flag)
             result =  map(map_apply, inputs)
@@ -87,5 +88,5 @@
             self.complete(result=result,
                           batch_inputs=self.batch_inputs,
-                           batch_outputs=self.batch_outputs,
+                          batch_outputs=self.batch_outputs,
                           page_id=self.page_id,
                           pars = self.pars,
Index: src/sans/perspectives/fitting/fitpage.py
===================================================================
--- src/sans/perspectives/fitting/fitpage.py	(revision d44648e2796f06ea09546b0c972320f42957b07f)
+++ src/sans/perspectives/fitting/fitpage.py	(revision 4e9f22702695459c7a6c8721061aab9d9e4ef437)
@@ -661,5 +661,5 @@
                           wx.EXPAND | wx.ADJUST_MINSIZE, 0)
         
-        if self.engine_type == "park":
+        if self.engine_type in ("park","bumps"):
             self.text_disp_max.Show(True)
             self.text_disp_min.Show(True)
@@ -738,5 +738,5 @@
                                           wx.EXPAND | wx.ADJUST_MINSIZE, 0)
 
-                        if self.engine_type == "park":
+                        if self.engine_type in ("park","bumps"):
                             ctl3.Show(True)
                             ctl4.Show(True)
@@ -1005,8 +1005,8 @@
             return
 
-        if len(self._manager.fit_thread_list) > 0 and\
-                    self._manager._fit_engine != "park" and\
-                    self._manager.sim_page != None and \
-                    self._manager.sim_page.uid == self.uid:
+        if (len(self._manager.fit_thread_list) > 0
+                and self._manager._fit_engine not in ("park","bumps")
+                and self._manager.sim_page != None
+                and self._manager.sim_page.uid == self.uid):
             msg = "The FitEnging will be set to 'ParkMC'\n"
             msg += " to fit with more than one data set..."
@@ -2068,19 +2068,4 @@
         return self.tcChi.GetValue()
         
-    def get_param_list(self):
-        """
-        :return self.param_toFit: list containing  references to TextCtrl
-            checked.Theses TextCtrl will allow reference to parameters to fit.
-        
-        :raise: if return an empty list of parameter fit will nnote work
-            properly so raise ValueError,"missing parameter to fit"
-        """
-        if self.param_toFit != []:
-            return self.param_toFit
-        else:
-            msg = "missing parameters to fit"
-            wx.MessageBox(msg, 'warning')
-            return False
-      
     def onsetValues(self, chisqr, p_name, out, cov):
         """
@@ -2108,5 +2093,5 @@
         if chisqr != None and numpy.isfinite(chisqr):
             #format chi2
-            if self.engine_type == "park":
+            if self.engine_type in ("park","bumps"):
                 npt_fit = float(self.get_npts2fit())
             chi2 = format_number(chisqr, True)
Index: src/sans/perspectives/fitting/fitpanel.py
===================================================================
--- src/sans/perspectives/fitting/fitpanel.py	(revision b6a181b3c69394fc4ac616d07590369465589b85)
+++ src/sans/perspectives/fitting/fitpanel.py	(revision eff93b8d577de85b34ffd99e484da07484c35580)
@@ -64,5 +64,5 @@
         self.sim_page = None
         self.batch_page = None
-        self.fit_engine_type = "scipy"
+        self.fit_engine_type = "bumps"
         ## get the state of a page
         self.Bind(basepage.EVT_PAGE_INFO, self._onGetstate)
Index: src/sans/perspectives/fitting/fitproblem.py
===================================================================
--- src/sans/perspectives/fitting/fitproblem.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/perspectives/fitting/fitproblem.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
@@ -454,5 +454,5 @@
         return self.itervalues()
     
-    def  set_result(self, result, fid):
+    def set_result(self, result, fid):
         """
         """
Index: src/sans/perspectives/fitting/fitting.py
===================================================================
--- src/sans/perspectives/fitting/fitting.py	(revision 767514afc7aa3ac5ba01c3f093481cdb65966863)
+++ src/sans/perspectives/fitting/fitting.py	(revision eff93b8d577de85b34ffd99e484da07484c35580)
@@ -36,4 +36,6 @@
 from .fitproblem import FitProblemDictionary
 from .fitpanel import FitPanel
+from .resultpanel import ResultPanel, PlotResultEvent
+
 from .fit_thread import FitThread
 from .pagestate import Reader
@@ -42,4 +44,9 @@
 from sans.perspectives.calculator.model_editor import EditorWindow
 from sans.guiframe.gui_manager import MDIFrame
+
+# TODO: remove globals from interface to bumps options!
+# Default bumps to use the levenberg-marquardt optimizer
+import bumps.fitters
+bumps.fitters.FIT_DEFAULT = 'lm'
 
 MAX_NBR_DATA = 4
@@ -78,9 +85,5 @@
         # Start with a good default
         self.elapsed = 0.022
-        # the type of optimizer selected, park or scipy
-        self.fitter = None
         self.fit_panel = None
-        #let fit ready
-        self.fitproblem_count = None
         #Flag to let the plug-in know that it is running stand alone
         self.standalone = True
@@ -88,5 +91,5 @@
         self.closed_page_dict = {}
         ## Fit engine
-        self._fit_engine = 'scipy'
+        self._fit_engine = 'bumps'
         self._gui_engine = None
         ## Relative error desired in the sum of squares (float); scipy only
@@ -111,4 +114,5 @@
         self.scipy_id = wx.NewId()
         self.park_id = wx.NewId()
+        self.bumps_id = wx.NewId()
         self.menu1 = None
         self.new_model_frame = None
@@ -198,6 +202,12 @@
         wx.EVT_MENU(owner, self.park_id, self._onset_engine_park)
         
-        self.menu1.FindItemById(self.scipy_id).Check(True)
-        self.menu1.FindItemById(self.park_id).Check(False)
+        bumps_help = "Bumps: fitting and uncertainty analysis. More in Help window...."
+        self.menu1.AppendCheckItem(self.bumps_id, "Bumps fit",
+                                   bumps_help)
+        wx.EVT_MENU(owner, self.bumps_id, self._onset_engine_bumps)
+        
+        self.menu1.FindItemById(self.scipy_id).Check(self._fit_engine=="scipy")
+        self.menu1.FindItemById(self.park_id).Check(self._fit_engine=="park")
+        self.menu1.FindItemById(self.bumps_id).Check(self._fit_engine=="bumps")
         self.menu1.AppendSeparator()
         self.id_tol = wx.NewId()
@@ -207,4 +217,15 @@
                                    ftol_help)
         wx.EVT_MENU(owner, self.id_tol, self.show_ftol_dialog)
+
+        self.id_bumps_options = wx.NewId()
+        bopts_help = "Bumps fitting options"
+        self.menu1.Append(self.id_bumps_options, 'Bumps &Options', bopts_help)
+        wx.EVT_MENU(owner, self.id_bumps_options, self.on_bumps_options)
+        self.bumps_options_menu = self.menu1.FindItemById(self.id_bumps_options)
+        self.bumps_options_menu.Enable(True)
+
+        self.id_result_panel = wx.NewId()
+        self.menu1.Append(self.id_result_panel, "Fit Results", "Show fit results panel")
+        wx.EVT_MENU(owner, self.id_result_panel, lambda ev: self.result_frame.Show())
         self.menu1.AppendSeparator()
         
@@ -511,4 +532,8 @@
         self.perspective = []
         self.perspective.append(self.fit_panel.window_name)
+
+        self.result_frame = MDIFrame(self.parent, None, ResultPanel.window_caption, (220, 200))
+        self.result_panel = ResultPanel(parent=self.result_frame, manager=self)
+        self.perspective.append(self.result_panel.window_name)
        
         #index number to create random model name
@@ -525,4 +550,5 @@
         #Send the fitting panel to guiframe
         self.mypanels.append(self.fit_panel)
+        self.mypanels.append(self.result_panel)
         return self.mypanels
     
@@ -818,4 +844,8 @@
                          StatusEvent(status=msg, info='warning'))
         dialog.Destroy()
+
+    def on_bumps_options(self, event=None):
+        from bumps.gui.fit_dialog import OpenFitOptions
+        OpenFitOptions()
 
     def stop_fit(self, uid):
@@ -951,62 +981,58 @@
         :param uid: id related to the panel currently calling this fit function.
         """
-        flag = True
-        ##  count the number of fitproblem schedule to fit
-        fitproblem_count = 0
-        for value in self.page_finder.values():
-            if value.get_scheduled() == 1:
-                fitproblem_count += 1
-        self._gui_engine = self._return_engine_type()
-        self.fitproblem_count = fitproblem_count
-        if self._fit_engine == "park":
-            engineType = "Simultaneous Fit"
+        if uid is None: raise RuntimeError("no page to fit") # Should never happen
+
+        # Remember the user selected fit engine before the fit.  Simultaneous
+        # fitting may change the selected engine, so it needs to be restored
+        # when the fit is complete.
+        self._gui_engine = self._fit_engine
+
+        sim_page_uid = getattr(self.sim_page, 'uid', None)
+        batch_page_uid = getattr(self.batch_page, 'uid', None)
+
+        if uid == sim_page_uid:
+            fit_type = 'simultaneous'
+        elif uid == batch_page_uid:
+            fit_type = 'combined_batch'
         else:
-            engineType = "Single Fit"
+            fit_type = 'single'
+
+        # if constrained fit, don't use scipy leastsq directly
+        if fit_type == 'simultaneous':
+            if self._fit_engine not in ("park","bumps"):
+                self._on_change_engine(engine='bumps')
+
+
         fitter_list = []
         sim_fitter = None
-        is_single_fit = True
-        batch_on = False
-        if self.sim_page is not None and self.sim_page.uid == uid:
+        if fit_type == 'simultaneous':
             #simulatanous fit only one engine need to be created
-            ## if simultaneous fit change automatically the engine to park
-            self._on_change_engine(engine='park')
             sim_fitter = Fit(self._fit_engine)
             sim_fitter.fitter_id = self.sim_page.uid
             fitter_list.append(sim_fitter)
-            is_single_fit = False
-            batch_on = self.sim_page.batch_on
-            
-        self.fitproblem_count = fitproblem_count
-        if self._fit_engine == "park":
-            engineType = "Simultaneous Fit"
-        else:
-            engineType = "Single Fit"
-        
+
         self.current_pg = None
         list_page_id = []
         fit_id = 0
-        batch_inputs = {}
-        batch_outputs = {}
-        for page_id, value in self.page_finder.iteritems():
+        for page_id, page_info in self.page_finder.iteritems():
             # For simulfit (uid give with None), do for-loop
             # if uid is specified (singlefit), do it only on the page.
-            if engineType == "Single Fit":
-                #combine more than 1 batch page on single mode
-                if self.batch_page is None or self.batch_page.uid != uid:
-                    if page_id != uid:
-                        continue
+            if page_id in (sim_page_uid, batch_page_uid): continue
+            if fit_type == "single" and page_id != uid: continue
+
             try:
-                if value.get_scheduled() == 1:
-                    value.nbr_residuals_computed = 0
-                    #Get list of parameters name to fit
-                    pars = []
-                    templist = []
+                if page_info.get_scheduled() == 1:
+                    page_info.nbr_residuals_computed = 0
                     page = self.fit_panel.get_page_by_id(page_id)
                     self.set_fit_weight(uid=page.uid,
                                      flag=page.get_weight_flag(),
                                      is2d=page._is_2D())
-                    templist = page.get_param_list()
-                    flag = page._update_paramv_on_fit()
-                    if not flag:
+                    if not page.param_toFit:
+                        msg = "No fitting parameters for %s"%page.window_caption
+                        wx.PostEvent(page.parent.parent,
+                                     StatusEvent(status=msg, info="error",
+                                                 type="stop"))
+                        return False
+                    if not page._update_paramv_on_fit():
                         msg = "Fitting range or parameter values are"
                         msg += " invalid in %s" % \
@@ -1015,44 +1041,32 @@
                                      StatusEvent(status=msg, info="error",
                                      type="stop"))
-                        return flag
-                    for element in templist:
-                        name = str(element[1])
-                        pars.append(name)
-                    fitproblem_list = value.values()
+                        return False
+
+                    pars = [str(element[1]) for element in page.param_toFit]
+                    fitproblem_list = page_info.values()
                     for fitproblem in  fitproblem_list:
                         if sim_fitter is None:
                             fitter = Fit(self._fit_engine)
                             fitter.fitter_id = page_id
-                            self._fit_helper(fitproblem=fitproblem,
-                                             pars=pars,
-                                             fitter=fitter,
-                                             fit_id=fit_id,
-                                             batch_inputs=batch_inputs,
-                                             batch_outputs=batch_outputs)
                             fitter_list.append(fitter)
                         else:
                             fitter = sim_fitter
-                            self._fit_helper(fitproblem=fitproblem,
+                        self._add_problem_to_fit(fitproblem=fitproblem,
                                              pars=pars,
                                              fitter=fitter,
-                                             fit_id=fit_id,
-                                             batch_inputs=batch_inputs,
-                                             batch_outputs=batch_outputs)
+                                             fit_id=fit_id)
                         fit_id += 1
                     list_page_id.append(page_id)
-                    current_page_id = page_id
-                    value.clear_model_param()
+                    page_info.clear_model_param()
             except KeyboardInterrupt:
-                flag = True
                 msg = "Fitting terminated"
                 wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
                                                       type="stop"))
-                return flag
+                return True
             except:
-                flag = False
-                msg = "%s error: %s" % (engineType, sys.exc_value)
+                msg = "Fitting error: %s" % str(sys.exc_value)
                 wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
                                                       type="stop"))
-                return flag
+                return False
         ## If a thread is already started, stop it
         #if self.calc_fit!= None and self.calc_fit.isrunning():
@@ -1066,21 +1080,10 @@
                                 improvement_delta=0.1)
         self._mac_sleep(0.2)
-        ## perform single fit
-        try:
-            page = self.fit_panel.get_page_by_id(uid)
-            batch_on = page.batch_on
-        except:
-            try:
-                #if the id cannot be found then  we deal with a self.sim_page
-                #or a self.batch_page
-                if self.sim_page is not None and uid == self.sim_page.uid:
-                    batch_on = self.sim_page.batch_on
-                if self.batch_page is not None and uid == self.batch_page.uid:
-                    batch_on = self.batch_page.batch_on
-            except:
-                batch_on = False
 
         # batch fit
-        if batch_on:
+        batch_inputs = {}
+        batch_outputs = {}
+        page = self.fit_panel.get_page_by_id(uid)
+        if page.batch_on:
             calc_fit = FitThread(handler=handler,
                                  fn=fitter_list,
@@ -1093,7 +1096,4 @@
                                  reset_flag=self.batch_reset_flag)
         else:
-            # single fit: not batch and not simul fit
-            if not is_single_fit:
-                current_page_id = self.sim_page.uid
             ## Perform more than 1 fit at the time
             calc_fit = FitThread(handler=handler,
@@ -1105,21 +1105,13 @@
                                     completefn=self._fit_completed,
                                     ftol=self.ftol)
-        self.fit_thread_list[current_page_id] = calc_fit
+        #self.fit_thread_list[current_page_id] = calc_fit
+        self.fit_thread_list[uid] = calc_fit
         calc_fit.queue()
+        calc_fit.ready(2.5)
         msg = "Fitting is in progress..."
         wx.PostEvent(self.parent, StatusEvent(status=msg, type="progress"))
         
-        self.ready_fit(calc_fit=calc_fit)
-        return flag
-    
-    def ready_fit(self, calc_fit):
-        """
-        Ready for another fit
-        """
-        if self.fitproblem_count != None and self.fitproblem_count > 1:
-            calc_fit.ready(2.5)
-        else:
-            time.sleep(0.4)
-            
+        return True
+
     def remove_plot(self, uid, fid=None, theory=False):
         """
@@ -1261,6 +1253,5 @@
                 self.page_finder[uid].schedule_tofit(value)
                 
-    def _fit_helper(self, fitproblem, pars, fitter, fit_id,
-                    batch_inputs, batch_outputs):
+    def _add_problem_to_fit(self, fitproblem, pars, fitter, fit_id):
         """
         Create and set fit engine with series of data and model
@@ -1571,4 +1562,5 @@
         wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
                                                       type="stop"))
+        wx.PostEvent(self.result_panel, PlotResultEvent(result=result))
         # reset fit_engine if changed by simul_fit
         if self._fit_engine != self._gui_engine:
@@ -1682,4 +1674,10 @@
         self._on_change_engine('scipy')
        
+    def _onset_engine_bumps(self, event):
+        """ 
+        set engine to bumps
+        """
+        self._on_change_engine('bumps')
+       
     def _on_slicer_event(self, event):
         """
@@ -1714,10 +1712,4 @@
                 break
     
-    def _return_engine_type(self):
-        """
-        return the current type of engine
-        """
-        return self._fit_engine
-     
     def _on_change_engine(self, engine='park'):
         """
@@ -1733,7 +1725,13 @@
             self.menu1.FindItemById(self.park_id).Check(True)
             self.menu1.FindItemById(self.scipy_id).Check(False)
+            self.menu1.FindItemById(self.bumps_id).Check(False)
+        elif engine == "scipy":
+            self.menu1.FindItemById(self.park_id).Check(False)
+            self.menu1.FindItemById(self.scipy_id).Check(True)
+            self.menu1.FindItemById(self.bumps_id).Check(False)
         else:
             self.menu1.FindItemById(self.park_id).Check(False)
-            self.menu1.FindItemById(self.scipy_id).Check(True)
+            self.menu1.FindItemById(self.scipy_id).Check(False)
+            self.menu1.FindItemById(self.bumps_id).Check(True)
         ## post a message to status bar
         msg = "Engine set to: %s" % self._fit_engine
Index: src/sans/perspectives/fitting/resultpanel.py
===================================================================
--- src/sans/perspectives/fitting/resultpanel.py	(revision ed4aef2412e82813a3c69fc3d050687b22a157ad)
+++ src/sans/perspectives/fitting/resultpanel.py	(revision ed4aef2412e82813a3c69fc3d050687b22a157ad)
@@ -0,0 +1,85 @@
+"""
+FitPanel class contains fields allowing to fit  models and  data
+
+:note: For Fit to be performed the user should check at least one parameter
+    on fit Panel window.
+   
+"""
+import wx
+import wx.lib.newevent
+from wx.aui import AuiNotebook as Notebook
+
+from sans.guiframe.panel_base import PanelBase
+from sans.guiframe.events import StatusEvent
+
+(PlotResultEvent, EVT_PLOT_RESULT) = wx.lib.newevent.NewEvent()
+
+
+class ResultPanel(Notebook, PanelBase):
+    """
+    FitPanel class contains fields allowing to fit  models and  data
+    
+    :note: For Fit to be performed the user should check at least one parameter
+        on fit Panel window.
+       
+    """
+    ## Internal name for the AUI manager
+    window_name = "Result panel"
+    ## Title to appear on top of the window
+    window_caption = "Result Panel"
+    CENTER_PANE = True
+    
+    def __init__(self, parent, manager=None, *args, **kwargs):
+        """
+        """
+        style = ((wx.aui.AUI_NB_WINDOWLIST_BUTTON
+                 |wx.aui.AUI_NB_DEFAULT_STYLE
+                 |wx.CLIP_CHILDREN)
+                 & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
+        Notebook.__init__(self, parent, -1, style = style)
+        PanelBase.__init__(self, parent)
+        self.frame = parent
+        self.Bind(EVT_PLOT_RESULT, self.on_plot_results)
+        self.frame.Bind(wx.EVT_CLOSE, self.on_close)
+        self._manager = None
+
+    def on_close(self, event):
+        if event.CanVeto():
+            self.frame.Hide()
+            event.Veto()
+        else:
+            event.Skip()
+
+    def on_plot_results(self, event):
+        self.frame.Show()
+        result = event.result[0][0]
+        if hasattr(result, 'convergence'):
+            from bumps.gui.convergence_view import ConvergenceView
+            best, pop = result.convergence[:,0], result.convergence[:,1:]
+            self.get_panel(ConvergenceView).update(best, pop)
+        if hasattr(result, 'uncertainty_state'):
+            from bumps.gui.uncertainty_view import UncertaintyView, CorrelationView, TraceView
+            from bumps.dream.stats import format_vars
+            self.get_panel(CorrelationView).update(result.uncertainty_state)
+            self.get_panel(UncertaintyView).update(result.uncertainty_state)
+            self.get_panel(TraceView).update(result.uncertainty_state)
+            # TODO: stats should be stored in result rather than computed in bumps UncertaintyView
+            msg = format_vars(self.get_panel(UncertaintyView).stats)
+            wx.PostEvent(self.frame.parent,
+                         StatusEvent(status=msg, info="info"))
+            print
+
+    def get_frame(self):
+        return self.frame
+
+    def add_panel(self, panel):
+        self.AddPage(panel, panel.title)
+
+    def get_panel(self, panel_class):
+        for idx in range(self.PageCount):
+            if self.GetPageText(idx) == panel_class.title:
+                return self.GetPage(idx)
+        else:
+            panel = panel_class(self)
+            self.add_panel(panel)
+            return panel
Index: src/sans/perspectives/fitting/simfitpage.py
===================================================================
--- src/sans/perspectives/fitting/simfitpage.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ src/sans/perspectives/fitting/simfitpage.py	(revision 4e9f22702695459c7a6c8721061aab9d9e4ef437)
@@ -138,5 +138,11 @@
                 self.Layout()
                 break
-        self._onAdd_constraint(None)
+
+        ## some model or parameters can be constrained
+        self._show_constraint()
+        self.sizer3.Layout()
+        self.Layout()
+        self.Refresh()
+        #self._onAdd_constraint(None)
              
     def onFit(self, event):
@@ -152,5 +158,5 @@
         ## making sure all parameters content a constraint
         ## validity of the constraint expression is own by fit engine
-        if self.parent._manager._fit_engine != "park" and flag:
+        if self.parent._manager._fit_engine not in ("park","bumps") and flag:
             msg = "The FitEnging will be set to 'Park' fit engine\n"
             msg += " for the simultaneous fit..."
@@ -378,5 +384,5 @@
         box_description = wx.StaticBox(self, -1,"Easy Setup ")
         boxsizer = wx.StaticBoxSizer(box_description, wx.HORIZONTAL)     
-        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL|wx.LEFT|wx.RIGHT|wx.EXPAND)
+        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL)
         self.model_cbox_left = wx.ComboBox(self, -1, style=wx.CB_READONLY)
         self.model_cbox_left.Clear()
Index: test/park_integration/test/batch_fit.py
===================================================================
--- test/park_integration/test/batch_fit.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ test/park_integration/test/batch_fit.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
@@ -1,6 +1,2 @@
-
-
-import math
-import numpy
 import copy
 import time
@@ -15,6 +11,4 @@
 
 
-
-    
 def classMapper(classInstance, classFunc, *args):
     """
@@ -28,6 +22,5 @@
 
 
-
-class BatchScipyFit:
+class BatchFit:
     """
     test fit module
@@ -69,5 +62,5 @@
             model.setParam('cyl_phi.npts', 3)
             model.setParam('cyl_theta.nsigmas', 10)
-            """ for 2 data cyl_theta = 60.0 [deg] cyl_phi= 60.0 [deg]"""
+            # for 2 data cyl_theta = 60.0 [deg] cyl_phi= 60.0 [deg]
             fitter.set_model(model, i, self.param_to_fit, 
                              self.list_of_constraints)
@@ -84,5 +77,5 @@
             self.list_of_mapper.append(classMapper)
                    
-    def reset_value(self):
+    def reset_value(self, engine='scipy'):
         """
         Initialize inputs for the map function
@@ -93,6 +86,5 @@
         self.list_of_constraints = []
         self.list_of_mapper = []
-        engine ="scipy"
-        
+
         path = "testdata_line3.txt"
         self._reset_helper(path=path, engine=engine, npts=NPTS)
@@ -113,11 +105,14 @@
         
       
-    def test_map_fit(self):
+    def test_map_fit(self, n=0):
         """
-        """ 
-        results =  map(classMapper,self.list_of_fitter, self.list_of_function)
-        print len(results)
-        for result in results:
-            print result.fitness, result.stderr, result.pvec
+        """
+        if n > 0:
+            self._test_process_map_fit(n=n)
+        else:
+            results =  map(classMapper,self.list_of_fitter, self.list_of_function)
+            print len(results)
+            for result in results:
+                print result.fitness, result.stderr, result.pvec
         
     def test_process_map_fit(self, n=1):
@@ -144,16 +139,17 @@
     """  
     def setUp(self):
-        self.test = BatchScipyFit(qmin=None, qmax=None)
+        self.test = BatchFit(qmin=None, qmax=None)
        
     
-    def __test_fit1(self):
+    def test_fit1(self):
         """test fit with python built in map function---- full range of each data"""
         self.test.test_map_fit()
         
-    def __test_fit2(self):
+    def test_fit2(self):
         """test fit with python built in map function---- common range for all data"""
         self.test.set_range(qmin=0.013, qmax=0.05)
         self.test.reset_value()
         self.test.test_map_fit()
+        raise Exception("fail")
         
     def test_fit3(self):
@@ -161,5 +157,5 @@
         self.test.set_range(qmin=None, qmax=None)
         self.test.reset_value()
-        self.test.test_process_map_fit(n=2)
+        self.test.test_map_fit(n=1)
         
     def test_fit4(self):
@@ -167,5 +163,5 @@
         self.test.set_range(qmin=-1, qmax=10)
         self.test.reset_value()
-        self.test.test_process_map_fit(n=1)
+        self.test.test_map_fit(n=3)
         
             
Index: st/park_integration/test/small_test.py
===================================================================
--- test/park_integration/test/small_test.py	(revision 5777106e8a4a0a62fe2ee0fbaf7c0aa19c0bb92b)
+++ 	(revision )
@@ -1,39 +1,0 @@
-"""
-    Unit tests for fitting module 
-"""
-import unittest
-import math
-from sans.fit.Fitting import Fit
-from DataLoader.loader import Loader
-
-class testFitModule(unittest.TestCase):
-    """ test fitting """
-    def test_park(self):
-        """ Simple cylinder model fit (scipy)  """
-        
-        out= Loader().load("cyl_400_20.txt")
-       
-        fitter = Fit('scipy')
-        # Receives the type of model for the fitting
-        from sans.models.CylinderModel import CylinderModel
-        model  = CylinderModel()
-        model.setParam('contrast', 1)
-       
-        pars1 =['length','radius','scale']
-        fitter.set_data(out,1)
-        model.setParam('scale', 1e-10)
-        fitter.set_model(model,1,pars1, constraints=())
-        fitter.select_problem_for_fit(Uid=1,value=1)
-        result1 = fitter.fit()
-        
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
-        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
-        
-        #print result1.pvec[0]-400.0, result1.pvec[0]
-        #print math.fabs(result1.pvec[0]-400.0)/3.0
-        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
-        self.assertTrue( math.fabs(result1.pvec[2]-9.0e-12)/3.0   < result1.stderr[2] )
-        self.assertTrue( result1.fitness < 1.0 )
-        
Index: st/park_integration/test/test_fit_cylinder.py
===================================================================
--- test/park_integration/test/test_fit_cylinder.py	(revision da5d8e8ddcd10ca55862386be6991a9817ba1897)
+++ 	(revision )
@@ -1,138 +1,0 @@
-"""
-    Unit tests for fitting module 
-    @author G.alina
-"""
-import unittest
-import math
-
-from sans.fit.AbstractFitEngine import Model
-from sans.fit.Fitting import Fit
-from sans.dataloader.loader import Loader
-
-class TestSingleFit(unittest.TestCase):
-    """ test single fitting """
-    def setUp(self):
-        """ initialize data"""
-        self.data = Loader().load("cyl_400_20.txt")
-        # Create model that fitting engine understands
-        from sans.models.CylinderModel import CylinderModel
-        self.model  = CylinderModel()
-        self.model.setParam("scale", 1.0)
-        self.model.setParam("radius",18)
-        self.model.setParam("length", 397)
-        self.model.setParam("sldCyl",3e-006 )
-        self.model.setParam("sldSolv",0.0 )
-        self.model.setParam("background", 0.0)
-        #select parameters to fit
-        self.pars1 =['length','radius','scale']
-        
-    def _fit(self, name="scipy"):
-        """ return fit result """
-        fitter = Fit(name)
-        fitter.set_data(self.data,1)
-        fitter.set_model(self.model,1,self.pars1)
-        fitter.select_problem_for_fit(id=1,value=1)
-        return  fitter.fit()
-       
-
-    def test_scipy(self):
-        """ Simple cylinder model fit (scipy)  """
-        
-        result1, = self._fit("scipy")
-        
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
-        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
-        
-        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
-        self.assertTrue( math.fabs(result1.pvec[2]-1.0)/3.0   < result1.stderr[2] )
-        self.assertTrue( result1.fitness < 1.0 )
-        
-        
-    def test_park(self):
-        """ Simple cylinder model fit (park)  """
-        #raise NotImplementedError()
-        result1, = self._fit("park")
-        
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
-        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
-       
-        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
-        self.assertTrue( math.fabs(result1.pvec[2]-1.0)/3.0   < result1.stderr[2] )
-        self.assertTrue( result1.fitness < 1.0 )
-        
-        
-        
-class TestSimultaneousFit(unittest.TestCase):
-    """ test simultaneous fitting """
-    def setUp(self):
-        """ initialize data"""
-        
-        self.data1=Loader().load("cyl_400_20.txt")
-        self.data2=Loader().load("cyl_400_40.txt")
-    
-        # Receives the type of model for the fitting
-        from sans.models.CylinderModel import CylinderModel
-        cyl1  = CylinderModel()
-        cyl1.name = "C1"
-        self.model1 = Model(cyl1)
-        self.model1.set(scale= 1.0)
-        self.model1.set(radius=18)
-        self.model1.set(length=396)
-        self.model1.set(sldCyl=3e-006, sldSolv=0.0)
-        self.model1.set(background=0.0)
-        
-        cyl2  = CylinderModel()
-        cyl2.name = "C2"
-        self.model2 = Model(cyl2)
-        self.model2.set(scale= 1.0)
-        self.model2.set(radius=37)
-        self.model2.set(length='C1.length')
-        self.model2.set(sldCyl=3e-006, sldSolv=0.0)
-        self.model2.set(background=0.0)
-       
-    def _fit(self, name="park"):
-        """ return fit result """
-        fitter = Fit(name)
-        fitter.set_data(self.data1,1)
-        fitter.set_model(self.model1, 1, ['length','radius','scale'])
-        
-        fitter.set_data(self.data2,2)
-        fitter.set_model(self.model2, 2, ['radius','scale'])
-        fitter.select_problem_for_fit(id=1,value=1)
-        fitter.select_problem_for_fit(id=2,value=1)
-        return fitter.fit()
-    
-    
-    def test_park2(self):
-        """ Simultaneous cylinder model fit (park)  """
-        raise NotImplementedError()
-        result1,= self._fit('park')
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>=0  )
-        self.assertTrue(len(result1.stderr)>= 0)
-      
-        for par in result1.parameters:
-            if par.name=='C1.length':
-                print par.name, par.value
-                self.assertTrue( math.fabs(par.value-400.0)/3.0 < par.stderr )
-            elif par.name=='C1.radius':
-                print par.name, par.value
-                self.assertTrue( math.fabs(par.value-20.0)/3.0 < par.stderr )
-            elif par.name=='C2.radius':
-                print par.name, par.value
-                self.assertTrue( math.fabs(par.value-40.0)/3.0 < par.stderr )
-            elif par.name=='C1.scale':
-                print par.name, par.value
-                self.assertTrue( math.fabs(par.value-1.0)/3.0 < par.stderr )
-            elif par.name=='C2.scale':
-                print par.name, par.value
-                self.assertTrue( math.fabs(par.value-1.0)/3.0 < par.stderr )
-            
-
-if __name__ == '__main__':
-    unittest.main()        
-       
Index: st/park_integration/test/test_fit_line.py
===================================================================
--- test/park_integration/test/test_fit_line.py	(revision da5d8e8ddcd10ca55862386be6991a9817ba1897)
+++ 	(revision )
@@ -1,218 +1,0 @@
-"""
-    Unit tests for fitting module 
-    @author Gervaise Alina
-"""
-import unittest
-
-from sans.fit.AbstractFitEngine import Model
-from sans.dataloader.loader import Loader
-from sans.fit.Fitting import Fit
-from sans.models.LineModel import LineModel
-from sans.models.Constant import Constant
-
-import math
-class testFitModule(unittest.TestCase):
-    """ test fitting """
-   
-    def test1(self):
-        """ Fit 1 data (testdata_line.txt)and 1 model(lineModel) """
-        #load data
-        data = Loader().load("testdata_line.txt")
-        data.name = data.filename
-        #Importing the Fit module
-        fitter = Fit('scipy')
-        # Receives the type of model for the fitting
-        model1  = LineModel()
-        model1.name = "M1"
-        model = Model(model1,data)
-        #fit with scipy test
-        
-        pars1= ['param1','param2']
-        fitter.set_data(data,1)
-        try:fitter.set_model(model,1,pars1)
-        except ValueError,exc:
-            #print "ValueError was correctly raised: "+str(msg)
-            assert str(exc).startswith('wrong parameter')
-        else: raise AssertionError("No error raised for scipy fitting with wrong parameters name to fit")
-        pars1= ['A','B']
-        fitter.set_model(model,1,pars1)
-        fitter.select_problem_for_fit(id=1,value=1)
-        result1, = fitter.fit()
-
-        self.assertTrue( math.fabs(result1.pvec[0]-4)/3 <= result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-2.5)/3 <= result1.stderr[1])
-        self.assertTrue( result1.fitness/len(data.x) < 2 )
-
-        #fit with park test
-        fitter = Fit('park')
-        fitter.set_data(data,1)
-        fitter.set_model(model,1,pars1)
-        fitter.select_problem_for_fit(id=1,value=1)
-        result2, = fitter.fit()
-        
-        self.assert_(result2)
-        self.assertTrue( math.fabs(result2.pvec[0]-4)/3 <= result2.stderr[0] ) 
-        self.assertTrue( math.fabs(result2.pvec[1]-2.5)/3 <= result2.stderr[1] )
-        self.assertTrue( result2.fitness/len(data.x) < 2)
-        # compare fit result result for scipy and park
-        self.assertAlmostEquals( result1.pvec[0], result2.pvec[0] )
-        self.assertAlmostEquals( result1.pvec[1],result2.pvec[1] )
-        self.assertAlmostEquals( result1.stderr[0],result2.stderr[0] )
-        self.assertAlmostEquals( result1.stderr[1],result2.stderr[1] )
-        self.assertAlmostEquals( result1.fitness,
-                                 result2.fitness/len(data.x),1 )
-        
-        
-    def test2(self):
-        """ fit 2 data and 2 model with no constrainst"""
-        #load data
-        l = Loader()
-        data1=l.load("testdata_line.txt")
-        data1.name = data1.filename
-      
-        data2=l.load("testdata_line1.txt")
-        data2.name = data2.filename
-     
-        #Importing the Fit module
-        fitter = Fit('scipy')
-        # Receives the type of model for the fitting
-        model11  = LineModel()
-        model11.name= "M1"
-        model22  = LineModel()
-        model11.name= "M2"
-      
-        model1 = Model(model11,data1)
-        model2 = Model(model22,data2)
-        #fit with scipy test
-        pars1= ['A','B']
-        fitter.set_data(data1,1)
-        fitter.set_model(model1,1,pars1)
-        fitter.select_problem_for_fit(id=1,value=0)
-        fitter.set_data(data2,2)
-        fitter.set_model(model2,2,pars1)
-        fitter.select_problem_for_fit(id=2,value=0)
-        
-        try: result1, = fitter.fit()
-        except RuntimeError,msg:
-           assert str(msg)=="No Assembly scheduled for Scipy fitting."
-        else: raise AssertionError,"No error raised for scipy fitting with no model"
-        fitter.select_problem_for_fit(id=1,value=1)
-        fitter.select_problem_for_fit(id=2,value=1)
-        try: result1, = fitter.fit()
-        except RuntimeError,msg:
-           assert str(msg)=="Scipy can't fit more than a single fit problem at a time."
-        else: raise AssertionError,"No error raised for scipy fitting with more than 2 models"
-        
-        #fit with park test
-        fitter = Fit('park')
-        fitter.set_data(data1,1)
-        fitter.set_model(model1,1,pars1)
-        fitter.set_data(data2,2)
-        fitter.set_model(model2,2,pars1)
-        fitter.select_problem_for_fit(id=1,value=1)
-        fitter.select_problem_for_fit(id=2,value=1)
-        R1,R2 = fitter.fit()
-        
-        self.assertTrue( math.fabs(R1.pvec[0]-4)/3 <= R1.stderr[0] )
-        self.assertTrue( math.fabs(R1.pvec[1]-2.5)/3 <= R1.stderr[1] )
-        self.assertTrue( R1.fitness/(len(data1.x)+len(data2.x)) < 2)
-        
-        
-    def test3(self):
-        """ fit 2 data and 2 model with 1 constrainst"""
-        #load data
-        l = Loader()
-        data1= l.load("testdata_line.txt")
-        data1.name = data1.filename
-        data2= l.load("testdata_cst.txt")
-        data2.name = data2.filename
-       
-        # Receives the type of model for the fitting
-        model11  = LineModel()
-        model11.name= "line"
-        model11.setParam("A", 1.0)
-        model11.setParam("B",1.0)
-        
-        model22  = Constant()
-        model22.name= "cst"
-        model22.setParam("value", 1.0)
-        
-        model1 = Model(model11,data1)
-        model2 = Model(model22,data2)
-        model1.set(A=4)
-        model1.set(B=3)
-        # Constraint the constant value to be equal to parameter B (the real value is 2.5)
-        model2.set(value='line.B')
-        #fit with scipy test
-        pars1= ['A','B']
-        pars2= ['value']
-        
-        #Importing the Fit module
-        fitter = Fit('park')
-        fitter.set_data(data1,1)
-        fitter.set_model(model1,1,pars1)
-        fitter.set_data(data2,2,smearer=None)
-        fitter.set_model(model2,2,pars2)
-        fitter.select_problem_for_fit(id=1,value=1)
-        fitter.select_problem_for_fit(id=2,value=1)
-        
-        R1,R2 = fitter.fit()
-        self.assertTrue( math.fabs(R1.pvec[0]-4.0)/3. <= R1.stderr[0])
-        self.assertTrue( math.fabs(R1.pvec[1]-2.5)/3. <= R1.stderr[1])
-        self.assertTrue( R1.fitness/(len(data1.x)+len(data2.x)) < 2)
-        
-        
-    def test4(self):
-        """ fit 2 data concatenates with limited range of x and  one model """
-            #load data
-        l = Loader()
-        data1 = l.load("testdata_line.txt")
-        data1.name = data1.filename
-        data2 = l.load("testdata_line1.txt")
-        data2.name = data2.filename
-
-        # Receives the type of model for the fitting
-        model1  = LineModel()
-        model1.name= "M1"
-        model1.setParam("A", 1.0)
-        model1.setParam("B",1.0)
-        model = Model(model1,data1)
-      
-        #fit with scipy test
-        pars1= ['A','B']
-        #Importing the Fit module
-        fitter = Fit('scipy')
-        fitter.set_data(data1,1,qmin=0, qmax=7)
-        fitter.set_model(model,1,pars1)
-        fitter.set_data(data2,1,qmin=1,qmax=10)
-        fitter.select_problem_for_fit(id=1,value=1)
-        
-        result1, = fitter.fit()
-        self.assert_(result1)
-
-        self.assertTrue( math.fabs(result1.pvec[0]-4)/3 <= result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-2.5)/3 <= result1.stderr[1])
-        self.assertTrue( result1.fitness/len(data1.x) < 2 )
-        
-        #fit with park test
-        fitter = Fit('park')
-        fitter.set_data(data1,1,qmin=0, qmax=7)
-        fitter.set_model(model,1,pars1)
-        fitter.set_data(data2,1,qmin=1,qmax=10)
-        fitter.select_problem_for_fit(id=1,value=1)
-        result2, = fitter.fit()
-        
-        self.assert_(result2)
-        self.assertTrue( math.fabs(result2.pvec[0]-4)/3 <= result2.stderr[0] )
-        self.assertTrue( math.fabs(result2.pvec[1]-2.5)/3 <= result2.stderr[1] )
-        self.assertTrue( result2.fitness/len(data1.x) < 2)
-        # compare fit result result for scipy and park
-        self.assertAlmostEquals( result1.pvec[0], result2.pvec[0] )
-        self.assertAlmostEquals( result1.pvec[1],result2.pvec[1] )
-        self.assertAlmostEquals( result1.stderr[0],result2.stderr[0] )
-        self.assertAlmostEquals( result1.stderr[1],result2.stderr[1] )
-        self.assertTrue( result2.fitness/(len(data2.x)+len(data1.x)) < 2 )
-        
-        
-    
-    
Index: st/park_integration/test/test_fit_smeared.py
===================================================================
--- test/park_integration/test/test_fit_smeared.py	(revision 6c007022258cff8efb5208e90301244c22e30170)
+++ 	(revision )
@@ -1,171 +1,0 @@
-"""
-    Unit tests for fitting module 
-    @author M. Doucet
-"""
-import unittest
-import math
-import numpy
-from sans.fit.AbstractFitEngine import Model
-from sans.fit.Fitting import Fit
-from sans.dataloader.loader import Loader
-from sans.models.qsmearing import smear_selection
-from sans.models.CylinderModel import CylinderModel
-from sans.models.SphereModel import SphereModel
-
-class testFitModule(unittest.TestCase):
-    """ test fitting """
-    
-    def test_scipy(self):
-        """ Simple cylinder model fit (scipy)  """
-        
-        out=Loader().load("cyl_400_20.txt")
-        # This data file has not error, add them
-        out.dy = out.y
-        
-        fitter = Fit('scipy')
-        fitter.set_data(out,1)
-        
-        # Receives the type of model for the fitting
-        model1  = CylinderModel()
-        model1.setParam('sldCyl', 3.0e-6)
-        model1.setParam('sldSolv', 0.0)
-        model = Model(model1)
-        model.set(scale=1e-10)
-        pars1 =['length','radius','scale']
-        fitter.set_model(model,1,pars1)
-        
-        # What the hell is this line for?
-        fitter.select_problem_for_fit(id=1,value=1)
-        result1, = fitter.fit()
-        
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
-        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
-        
-        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
-        self.assertTrue( math.fabs(result1.pvec[2]-9.0e-12)/3.0   < result1.stderr[2] )
-        self.assertTrue( result1.fitness < 1.0 )
-        
-    def test_scipy_dispersion(self):
-        """
-            Cylinder fit with dispersion
-        """
-        # Load data
-        # This data is for a cylinder with 
-        #   length=400, radius=20, radius disp=5, scale=1e-10
-        out=Loader().load("cyl_400_20_disp5r.txt")
-        out.dy = numpy.zeros(len(out.y))
-        for i in range(len(out.y)):
-            out.dy[i] = math.sqrt(out.y[i])
-        
-        # Set up the fit
-        fitter = Fit('scipy')
-        # Receives the type of model for the fitting
-        model1  = CylinderModel()
-        model1.setParam('sldCyl', 3.0e-6)
-        model1.setParam('sldSolv', 0.0)
-
-        # Dispersion parameters
-        model1.dispersion['radius']['width'] = 0.001
-        model1.dispersion['radius']['npts'] = 50        
-        
-        model = Model(model1)
-        
-        pars1 =['length','radius','scale','radius.width']
-        fitter.set_data(out,1)
-        model.set(scale=1e-10)
-        fitter.set_model(model,1,pars1)
-        fitter.select_problem_for_fit(id=1,value=1)
-        result1, = fitter.fit()
-        
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
-        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
-        
-        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
-        self.assertTrue( math.fabs(result1.pvec[2]-1.0e-10)/3.0   < result1.stderr[2] )
-        self.assertTrue( math.fabs(result1.pvec[3]-5.0)/3.0   < result1.stderr[3] )
-        self.assertTrue( result1.fitness < 1.0 )
-        
-        
-class smear_testdata(unittest.TestCase):
-    """
-        Test fitting with the smearing operations
-        The output of the fits should be compated to fits
-        done with IGOR for the same models and data sets.
-    """
-    def setUp(self):
-        print "TEST DONE WITHOUT PROPER OUTPUT CHECK:"
-        print "   ---> TEST NEEDS TO BE COMPLETED"
-        data = Loader().load("latex_smeared.xml")
-        self.data_res = data[0]
-        self.data_slit = data[1]
-        
-        self.sphere = SphereModel()
-        self.sphere.setParam('radius', 5000.0)
-        self.sphere.setParam('scale', 1.0e-13)
-        self.sphere.setParam('radius.npts', 30)
-        self.sphere.setParam('radius.width',500)
-        
-    def test_reso(self):
-
-        # Let the data module find out what smearing the
-        # data needs
-        smear = smear_selection(self.data_res)
-        self.assertEqual(smear.__class__.__name__, 'QSmearer')
-
-        # Fit
-        fitter = Fit('scipy')
-        
-        # Data: right now this is the only way to set the smearer object
-        # We should improve that and have a way to get access to the
-        # data for a given fit.
-        fitter.set_data(self.data_res,1)
-        fitter._engine.fit_arrange_dict[1].data_list[0].smearer = smear
-        print "smear ",smear
-        # Model: maybe there's a better way to do this.
-        # Ideally we should have to create a new model from our sans model.
-        fitter.set_model(Model(self.sphere),1, ['radius','scale'])
-        
-        # Why do we have to do this...?
-        fitter.select_problem_for_fit(id=1,value=1)
-        
-        # Perform the fit (might take a while)
-        result1, = fitter.fit()
-        
-        # Replace this with proper test once we know what the
-        # result should be 
-        print result1.pvec
-        print result1.stderr
-        
-    def test_slit(self):
-        smear = smear_selection(self.data_slit)
-        self.assertEqual(smear.__class__.__name__, 'SlitSmearer')
-
-        # Fit
-        fitter = Fit('scipy')
-        
-        # Data: right now this is the only way to set the smearer object
-        # We should improve that and have a way to get access to the
-        # data for a given fit.
-        fitter.set_data(self.data_slit,1)
-        fitter._engine.fit_arrange_dict[1].data_list[0].smearer = smear
-        fitter._engine.fit_arrange_dict[1].data_list[0].qmax = 0.003
-        
-        # Model
-        fitter.set_model(Model(self.sphere),1, ['radius','scale'])
-        fitter.select_problem_for_fit(id=1,value=1)
-        
-        result1, = fitter.fit()
-        
-        # Replace this with proper test once we know what the
-        # result should be 
-        print result1.pvec
-        print result1.stderr
-        
-       
-       
-if __name__ == '__main__':
-    unittest.main()
Index: st/park_integration/test/test_park_scipy.py
===================================================================
--- test/park_integration/test/test_park_scipy.py	(revision 6c007022258cff8efb5208e90301244c22e30170)
+++ 	(revision )
@@ -1,59 +1,0 @@
-"""
-    Unit tests for fitting module 
-    @author: G. Alina
-"""
-import unittest
-import math
-
-from sans.guiframe.dataFitting import Data1D 
-from sans.fit.AbstractFitEngine import Model,FitData1D
-from sans.fit.Fitting import Fit
-from sans.dataloader.loader import Loader
-from sans.models.MultiplicationModel import MultiplicationModel
-from sans.models.CylinderModel import CylinderModel
-from sans.models.SquareWellStructure import SquareWellStructure
-
-class testFitModule(unittest.TestCase):
-    """ test fitting """
-   
-        
-    def test_scipy(self):
-        """ Simple cylinder model fit (scipy)  """
-        
-        out=Loader().load("cyl_400_20.txt")
-        data = Data1D(x=out.x, y=out.y, dx=out.dx, dy=out.dy)
-        # Receives the type of model for the fitting
-        model1  =  MultiplicationModel(CylinderModel(),SquareWellStructure())
-        model1.setParam('background', 0.0)
-        model1.setParam('sldCyl', 3e-006)
-        model1.setParam('sldSolv', 0.0)
-        model1.setParam('length', 420)
-        model1.setParam('radius', 40)
-        model1.setParam('scale_factor', 2)
-        model1.setParam('volfraction', 0.04)
-        model1.setParam('welldepth', 1.5)
-        model1.setParam('wellwidth', 1.2)
-      
-        model = Model(model1)
-    
-        pars1 =['length','radius','scale_factor']
-        fitter = Fit('scipy')
-        fitter.set_data(data,1)
-        fitter.set_model(model,1,pars1)
-        fitter.select_problem_for_fit(id=1,value=1)
-        result1, = fitter.fit()
-
-        self.assert_(result1)
-        self.assertTrue(len(result1.pvec)>=0 )
-        self.assertTrue(len(result1.stderr)>= 0)
-
-        print "results",list(zip(result1.pvec, result1.stderr))
-        self.assertTrue( math.fabs(result1.pvec[0]-605)/3.0 <= result1.stderr[0] )
-        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  <= result1.stderr[1] )
-        self.assertTrue( math.fabs(result1.pvec[2]-1)/3.0 <= result1.stderr[2] )
-        
-        self.assertTrue( result1.fitness/len(data.x) < 1.0 )
-        
-       
-if __name__ == '__main__':
-    unittest.main()  
Index: test/park_integration/test/utest_fit_cylinder.py
===================================================================
--- test/park_integration/test/utest_fit_cylinder.py	(revision eff93b8d577de85b34ffd99e484da07484c35580)
+++ test/park_integration/test/utest_fit_cylinder.py	(revision eff93b8d577de85b34ffd99e484da07484c35580)
@@ -0,0 +1,137 @@
+"""
+    Unit tests for fitting module 
+    @author G.alina
+"""
+import unittest
+import math
+
+from sans.fit.AbstractFitEngine import Model
+from sans.fit.Fitting import Fit
+from sans.dataloader.loader import Loader
+
+#@unittest.skip("")
+class TestSingleFit(unittest.TestCase):
+    """ test single fitting """
+    def setUp(self):
+        """ initialize data"""
+        self.data = Loader().load("cyl_400_20.txt")
+        # Create model that fitting engine understands
+        from sans.models.CylinderModel import CylinderModel
+        self.model  = CylinderModel()
+        self.model.setParam("scale", 1.0)
+        self.model.setParam("radius",18)
+        self.model.setParam("length", 397)
+        self.model.setParam("sldCyl",3e-006 )
+        self.model.setParam("sldSolv",0.0 )
+        self.model.setParam("background", 0.0)
+        #select parameters to fit
+        self.pars1 =['length','radius','scale']
+        
+    def _fit(self, name="scipy"):
+        """ return fit result """
+        fitter = Fit(name)
+        fitter.set_data(self.data,1)
+        fitter.set_model(self.model,1,self.pars1)
+        fitter.select_problem_for_fit(id=1,value=1)
+        result1, = fitter.fit()
+
+        self.assert_(result1)
+        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
+        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
+
+        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
+        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
+        self.assertTrue( math.fabs(result1.pvec[2]-1.0)/3.0   < result1.stderr[2] )
+        self.assertTrue( result1.fitness < 1.0 )
+
+
+    def test_scipy(self):
+        """ Simple cylinder model fit (scipy)  """
+        self._fit("scipy")
+
+
+    def test_park(self):
+        """ Simple cylinder model fit (park)  """
+        self._fit("park")
+
+    def test_bumps(self):
+        """ Simple cylinder model fit (park)  """
+        self._fit("bumps")
+
+
+        
+class TestSimultaneousFit(unittest.TestCase):
+    """ test simultaneous fitting """
+    def setUp(self):
+        """ initialize data"""
+        
+        self.data1=Loader().load("cyl_400_20.txt")
+        self.data2=Loader().load("cyl_400_40.txt")
+    
+        # Receives the type of model for the fitting
+        from sans.models.CylinderModel import CylinderModel
+        cyl1  = CylinderModel()
+        cyl1.name = "C1"
+        self.model1 = Model(cyl1)
+        self.model1.set(scale= 1.0)
+        self.model1.set(radius=18)
+        self.model1.set(length=200)
+        self.model1.set(sldCyl=3e-006, sldSolv=0.0)
+        self.model1.set(background=0.0)
+
+        cyl2  = CylinderModel()
+        cyl2.name = "C2"
+        self.model2 = Model(cyl2)
+        self.model2.set(scale= 1.0)
+        self.model2.set(radius=37)
+        self.model2.set(length=300)
+        self.model2.set(sldCyl=3e-006, sldSolv=0.0)
+        self.model2.set(background=0.0)
+
+
+    def test_constrained_bumps(self):
+        """ Simultaneous cylinder model fit (park)  """
+        self._run_fit(Fit('bumps'))
+
+    #@unittest.skip("")
+    def test_constrained_park(self):
+        """ Simultaneous cylinder model fit (park)  """
+        self._run_fit(Fit('park'))
+
+    def _run_fit(self, fitter):
+        result1, result2 = self._fit(fitter)
+        self.assert_(result1)
+        self.assertTrue(len(result1.pvec)>0)
+        self.assertTrue(len(result1.stderr)>0)
+
+        for n, v, dv in zip(result1.param_list, result1.pvec, result1.stderr):
+            print "%s M1.%s = %s +/- %s"%(fitter._engine.__class__.__name__,n,v,dv)
+            if n == "length":
+                self.assertTrue( math.fabs(v-400.0)/3.0 < dv )
+            elif n=='radius':
+                self.assertTrue( math.fabs(v-20.0)/3.0 < dv )
+            elif n=='scale':
+                self.assertTrue( math.fabs(v-1.0)/3.0 < dv )
+        for n, v, dv in zip(result2.param_list, result2.pvec, result2.stderr):
+            print "%s M2.%s = %s +/- %s"%(fitter._engine.__class__.__name__,n,v,dv)
+            if n=='radius':
+                self.assertTrue( math.fabs(v-40.0)/3.0 < dv )
+            elif n=='scale':
+                self.assertTrue( math.fabs(v-1.0)/3.0 < dv )
+
+    def _fit(self, fitter):
+        """ return fit result """
+        fitter.set_data(self.data1,1)
+        fitter.set_model(self.model1, 1, ['length','radius','scale'])
+
+        fitter.set_data(self.data2,2)
+        fitter.set_model(self.model2, 2, ['length','radius','scale'],
+                         constraints=[("length","C1.length")])
+        fitter.select_problem_for_fit(id=1,value=1)
+        fitter.select_problem_for_fit(id=2,value=1)
+        return fitter.fit()
+
+
+if __name__ == '__main__':
+    unittest.main()        
+       
Index: test/park_integration/test/utest_fit_line.py
===================================================================
--- test/park_integration/test/utest_fit_line.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
+++ test/park_integration/test/utest_fit_line.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
@@ -0,0 +1,257 @@
+"""
+    Unit tests for fitting module 
+    @author Gervaise Alina
+"""
+import unittest
+import math
+
+from sans.fit.AbstractFitEngine import Model, FitHandler
+from sans.dataloader.loader import Loader
+from sans.fit.Fitting import Fit
+from sans.models.LineModel import LineModel
+from sans.models.Constant import Constant
+
+class testFitModule(unittest.TestCase):
+    """ test fitting """
+
+    def test_bad_pars(self):
+        fitter = Fit('bumps')
+
+        data = Loader().load("testdata_line.txt")
+        data.name = data.filename
+        fitter.set_data(data,1)
+
+        model1  = LineModel()
+        model1.name = "M1"
+        model = Model(model1, data)
+        pars1= ['param1','param2']
+        try:
+            fitter.set_model(model,1,pars1)
+        except ValueError,exc:
+            #print "ValueError was correctly raised: "+str(msg)
+            assert str(exc).startswith('parameter param1')
+        else:
+            raise AssertionError("No error raised for scipy fitting with wrong parameters name to fit")
+
+    def fit_single(self, fitter_name, isdream=False):
+        fitter = Fit(fitter_name)
+
+        data = Loader().load("testdata_line.txt")
+        data.name = data.filename
+        fitter.set_data(data,1)
+
+        # Receives the type of model for the fitting
+        model1  = LineModel()
+        model1.name = "M1"
+        model = Model(model1,data)
+        #fit with scipy test
+
+        pars1= ['A','B']
+        fitter.set_model(model,1,pars1)
+        fitter.select_problem_for_fit(id=1,value=1)
+        result1, = fitter.fit(handler=FitHandler())
+
+        # The target values were generated from the following statements
+        p,s,fx = result1.pvec, result1.stderr, result1.fitness
+        #print "p0,p1,s0,s1,fx = %g, %g, %g, %g, %g"%(p[0],p[1],s[0],s[1],fx)
+        p0,p1,s0,s1,fx_ = 3.68353, 2.61004, 0.336186, 0.105244, 1.20189
+
+        if isdream:
+            # Dream is not a minimizer: just check that the fit is within
+            # uncertainty
+            self.assertTrue( abs(p[0]-p0) <= s0 )
+            self.assertTrue( abs(p[1]-p1) <= s1 )
+        else:
+            self.assertTrue( abs(p[0]-p0) <= 1e-5 )
+            self.assertTrue( abs(p[1]-p1) <= 1e-5 )
+            self.assertTrue( abs(fx-fx_) <= 1e-5 )
+
+    def fit_bumps(self, alg, **opts):
+        #Importing the Fit module
+        from bumps import fitters
+        fitters.FIT_DEFAULT = alg
+        fitters.FIT_OPTIONS[alg].options.update(opts)
+        fitters.FIT_OPTIONS[alg].options.update(monitors=[])
+        #print "fitting",alg,opts
+        #kprint "options",fitters.FIT_OPTIONS[alg].__dict__
+        self.fit_single('bumps', isdream=(alg=='dream'))
+
+    def test_bumps_de(self):
+        self.fit_bumps('de')
+
+    def test_bumps_dream(self):
+        self.fit_bumps('dream', burn=500, steps=100)
+
+    def test_bumps_amoeba(self):
+        self.fit_bumps('amoeba')
+
+    def test_bumps_newton(self):
+        self.fit_bumps('newton')
+
+    def test_bumps_lm(self):
+        self.fit_bumps('lm')
+
+    def test_scipy(self):
+        #print "fitting scipy"
+        self.fit_single('scipy')
+
+    def test_park(self):
+        #print "fitting park"
+        self.fit_single('park')
+
+        
+    def test2(self):
+        """ fit 2 data and 2 model with no constrainst"""
+        #load data
+        l = Loader()
+        data1=l.load("testdata_line.txt")
+        data1.name = data1.filename
+      
+        data2=l.load("testdata_line1.txt")
+        data2.name = data2.filename
+     
+        #Importing the Fit module
+        fitter = Fit('scipy')
+        # Receives the type of model for the fitting
+        model11  = LineModel()
+        model11.name= "M1"
+        model22  = LineModel()
+        model11.name= "M2"
+      
+        model1 = Model(model11,data1)
+        model2 = Model(model22,data2)
+        #fit with scipy test
+        pars1= ['A','B']
+        fitter.set_data(data1,1)
+        fitter.set_model(model1,1,pars1)
+        fitter.select_problem_for_fit(id=1,value=0)
+        fitter.set_data(data2,2)
+        fitter.set_model(model2,2,pars1)
+        fitter.select_problem_for_fit(id=2,value=0)
+        
+        try: result1, = fitter.fit(handler=FitHandler())
+        except RuntimeError,msg:
+           assert str(msg)=="No Assembly scheduled for Scipy fitting."
+        else: raise AssertionError,"No error raised for scipy fitting with no model"
+        fitter.select_problem_for_fit(id=1,value=1)
+        fitter.select_problem_for_fit(id=2,value=1)
+        try: result1, = fitter.fit(handler=FitHandler())
+        except RuntimeError,msg:
+           assert str(msg)=="Scipy can't fit more than a single fit problem at a time."
+        else: raise AssertionError,"No error raised for scipy fitting with more than 2 models"
+
+        #fit with park test
+        fitter = Fit('park')
+        fitter.set_data(data1,1)
+        fitter.set_model(model1,1,pars1)
+        fitter.set_data(data2,2)
+        fitter.set_model(model2,2,pars1)
+        fitter.select_problem_for_fit(id=1,value=1)
+        fitter.select_problem_for_fit(id=2,value=1)
+        R1,R2 = fitter.fit(handler=FitHandler())
+        
+        self.assertTrue( math.fabs(R1.pvec[0]-4)/3 <= R1.stderr[0] )
+        self.assertTrue( math.fabs(R1.pvec[1]-2.5)/3 <= R1.stderr[1] )
+        self.assertTrue( R1.fitness/(len(data1.x)+len(data2.x)) < 2)
+        
+        
+    def test3(self):
+        """ fit 2 data and 2 model with 1 constrainst"""
+        #load data
+        l = Loader()
+        data1= l.load("testdata_line.txt")
+        data1.name = data1.filename
+        data2= l.load("testdata_cst.txt")
+        data2.name = data2.filename
+       
+        # Receives the type of model for the fitting
+        model11  = LineModel()
+        model11.name= "line"
+        model11.setParam("A", 1.0)
+        model11.setParam("B",1.0)
+        
+        model22  = Constant()
+        model22.name= "cst"
+        model22.setParam("value", 1.0)
+        
+        model1 = Model(model11,data1)
+        model2 = Model(model22,data2)
+        model1.set(A=4)
+        model1.set(B=3)
+        # Constraint the constant value to be equal to parameter B (the real value is 2.5)
+        model2.set(value='line.B')
+        #fit with scipy test
+        pars1= ['A','B']
+        pars2= ['value']
+        
+        #Importing the Fit module
+        fitter = Fit('park')
+        fitter.set_data(data1,1)
+        fitter.set_model(model1,1,pars1)
+        fitter.set_data(data2,2,smearer=None)
+        fitter.set_model(model2,2,pars2)
+        fitter.select_problem_for_fit(id=1,value=1)
+        fitter.select_problem_for_fit(id=2,value=1)
+        
+        R1,R2 = fitter.fit(handler=FitHandler())
+        self.assertTrue( math.fabs(R1.pvec[0]-4.0)/3. <= R1.stderr[0])
+        self.assertTrue( math.fabs(R1.pvec[1]-2.5)/3. <= R1.stderr[1])
+        self.assertTrue( R1.fitness/(len(data1.x)+len(data2.x)) < 2)
+        
+        
+    def test4(self):
+        """ fit 2 data concatenates with limited range of x and  one model """
+            #load data
+        l = Loader()
+        data1 = l.load("testdata_line.txt")
+        data1.name = data1.filename
+        data2 = l.load("testdata_line1.txt")
+        data2.name = data2.filename
+
+        # Receives the type of model for the fitting
+        model1  = LineModel()
+        model1.name= "M1"
+        model1.setParam("A", 1.0)
+        model1.setParam("B",1.0)
+        model = Model(model1,data1)
+      
+        #fit with scipy test
+        pars1= ['A','B']
+        #Importing the Fit module
+        fitter = Fit('scipy')
+        fitter.set_data(data1,1,qmin=0, qmax=7)
+        fitter.set_model(model,1,pars1)
+        fitter.set_data(data2,1,qmin=1,qmax=10)
+        fitter.select_problem_for_fit(id=1,value=1)
+        
+        result1, = fitter.fit(handler=FitHandler())
+        #print(result1)
+        self.assert_(result1)
+
+        self.assertTrue( math.fabs(result1.pvec[0]-4)/3 <= result1.stderr[0] )
+        self.assertTrue( math.fabs(result1.pvec[1]-2.5)/3 <= result1.stderr[1])
+        self.assertTrue( result1.fitness/len(data1.x) < 2 )
+
+        #fit with park test
+        fitter = Fit('park')
+        fitter.set_data(data1,1,qmin=0, qmax=7)
+        fitter.set_model(model,1,pars1)
+        fitter.set_data(data2,1,qmin=1,qmax=10)
+        fitter.select_problem_for_fit(id=1,value=1)
+        result2, = fitter.fit(handler=FitHandler())
+        
+        self.assert_(result2)
+        self.assertTrue( math.fabs(result2.pvec[0]-4)/3 <= result2.stderr[0] )
+        self.assertTrue( math.fabs(result2.pvec[1]-2.5)/3 <= result2.stderr[1] )
+        self.assertTrue( result2.fitness/len(data1.x) < 2)
+        # compare fit result result for scipy and park
+        self.assertAlmostEquals( result1.pvec[0], result2.pvec[0] )
+        self.assertAlmostEquals( result1.pvec[1],result2.pvec[1] )
+        self.assertAlmostEquals( result1.stderr[0],result2.stderr[0] )
+        self.assertAlmostEquals( result1.stderr[1],result2.stderr[1] )
+        self.assertTrue( result2.fitness/(len(data2.x)+len(data1.x)) < 2 )
+
+
+if __name__ == "__main__":
+    unittest.main()
+    
Index: test/park_integration/test/utest_fit_smeared.py
===================================================================
--- test/park_integration/test/utest_fit_smeared.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
+++ test/park_integration/test/utest_fit_smeared.py	(revision e3efa6b33f61b244c04b2476cabdadf01a183b76)
@@ -0,0 +1,204 @@
+"""
+    Unit tests for fitting module 
+    @author M. Doucet
+"""
+import unittest
+import math
+
+import numpy
+from sans.fit.AbstractFitEngine import Model
+from sans.fit.Fitting import Fit
+from sans.dataloader.loader import Loader
+from sans.models.qsmearing import smear_selection
+from sans.models.CylinderModel import CylinderModel
+from sans.models.SphereModel import SphereModel
+
+class testFitModule(unittest.TestCase):
+    """ test fitting """
+    
+    def test_scipy(self):
+        """ Simple cylinder model fit (scipy)  """
+        
+        out=Loader().load("cyl_400_20.txt")
+        # This data file has not error, add them
+        #out.dy = out.y
+        
+        fitter = Fit('scipy')
+        fitter.set_data(out,1)
+        
+        # Receives the type of model for the fitting
+        model1  = CylinderModel()
+        model1.setParam("scale", 1.0)
+        model1.setParam("radius",18)
+        model1.setParam("length", 397)
+        model1.setParam("sldCyl",3e-006 )
+        model1.setParam("sldSolv",0.0 )
+        model1.setParam("background", 0.0)
+        model = Model(model1)
+        pars1 =['length','radius','scale']
+        fitter.set_model(model,1,pars1)
+        
+        # What the hell is this line for?
+        fitter.select_problem_for_fit(id=1,value=1)
+        result1, = fitter.fit()
+        #print "result1",result1
+
+        self.assert_(result1)
+        self.assertTrue(len(result1.pvec) > 0)
+        self.assertTrue(len(result1.stderr) > 0)
+        
+        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
+        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
+        self.assertTrue( math.fabs(result1.pvec[2]-1)/3.0   < result1.stderr[2] )
+        self.assertTrue( result1.fitness < 1.0 )
+
+    def test_park_dispersion(self):
+        """
+            Cylinder fit with dispersion
+        """
+        self._dispersion(fitter = Fit('park'))
+
+    def test_bumps_dispersion(self):
+        """
+            Cylinder fit with dispersion
+        """
+        alg = 'lm'
+        from bumps import fitters
+        fitters.FIT_DEFAULT = alg
+        #fitters.FIT_OPTIONS[alg].options.update(opts)
+        fitters.FIT_OPTIONS[alg].options.update(monitors=[])
+        self._dispersion(fitter = Fit('bumps'))
+
+    def test_scipy_dispersion(self):
+        """
+            Cylinder fit with dispersion
+        """
+        self._dispersion(fitter = Fit('scipy'))
+
+    def _dispersion(self, fitter):
+        # Load data
+        # This data is for a cylinder with 
+        #   length=400, radius=20, radius disp=5, scale=1e-10
+        out=Loader().load("cyl_400_20_disp5r.txt")
+        out.dy = numpy.zeros(len(out.y))
+        for i in range(len(out.y)):
+            out.dy[i] = math.sqrt(out.y[i])
+        
+        # Receives the type of model for the fitting
+        model1  = CylinderModel()
+        model1.setParam("scale", 10.0)
+        model1.setParam("radius",18)
+        model1.setParam("length", 397)
+        model1.setParam("sldCyl",3e-006 )
+        model1.setParam("sldSolv",0.0 )
+        model1.setParam("background", 0.0)
+
+        # Dispersion parameters
+        model1.dispersion['radius']['width'] = 0.25
+        model1.dispersion['radius']['npts'] = 50
+
+        model = Model(model1)
+
+        pars1 =['length','radius','scale','radius.width']
+        fitter.set_data(out,1)
+        fitter.set_model(model,1,pars1)
+        fitter.select_problem_for_fit(id=1,value=1)
+        #import time; T0 = time.time()
+        result1, = fitter.fit()
+        #print "time",time.time()-T0,fitter._engine.__class__.__name__
+        
+        self.assert_(result1)
+        self.assertTrue(len(result1.pvec)>0)
+        self.assertTrue(len(result1.stderr)>0)
+
+        #print [z for z in zip(result1.param_list,result1.pvec,result1.stderr)]
+        self.assertTrue( math.fabs(result1.pvec[0]-399.8)/3.0 < result1.stderr[0] )
+        self.assertTrue( math.fabs(result1.pvec[1]-17.5)/3.0  < result1.stderr[1] )
+        self.assertTrue( math.fabs(result1.pvec[2]-11.1)/3.0   < result1.stderr[2] )
+        self.assertTrue( math.fabs(result1.pvec[3]-0.276)/3.0   < result1.stderr[3] )
+        self.assertTrue( result1.fitness < 1.0 )
+        
+        
+class smear_testdata(unittest.TestCase):
+    """
+        Test fitting with the smearing operations
+        The output of the fits should be compated to fits
+        done with IGOR for the same models and data sets.
+    """
+    def setUp(self):
+        data = Loader().load("latex_smeared.xml")
+        self.data_res = data[0]
+        self.data_slit = data[1]
+        
+        self.sphere = SphereModel()
+        self.sphere.setParam('background', 0)
+        self.sphere.setParam('radius', 5000.0)
+        self.sphere.setParam('scale', 0.4)
+        self.sphere.setParam('sldSolv',0)
+        self.sphere.setParam('sldSph',1e-6)
+        #self.sphere.setParam('radius.npts', 30)
+        #self.sphere.setParam('radius.width',50)
+
+    def test_reso(self):
+
+        # Let the data module find out what smearing the
+        # data needs
+        smear = smear_selection(self.data_res)
+        self.assertEqual(smear.__class__.__name__, 'QSmearer')
+
+        # Fit
+        fitter = Fit('scipy')
+        
+        # Data: right now this is the only way to set the smearer object
+        # We should improve that and have a way to get access to the
+        # data for a given fit.
+        fitter.set_data(self.data_res,1)
+        fitter._engine.fit_arrange_dict[1].data_list[0].smearer = smear
+
+        # Model: maybe there's a better way to do this.
+        # Ideally we should have to create a new model from our sans model.
+        fitter.set_model(Model(self.sphere),1, ['radius','scale', 'background'])
+        
+        # Why do we have to do this...?
+        fitter.select_problem_for_fit(id=1,value=1)
+
+        # Perform the fit (might take a while)
+        result1, = fitter.fit()
+        
+        #print "v",result1.pvec
+        #print "dv",result1.stderr
+        #print "chisq(v)",result1.fitness
+
+        self.assertTrue( math.fabs(result1.pvec[0]-5000) < 20 )
+        self.assertTrue( math.fabs(result1.pvec[1]-0.48) < 0.02 )
+        self.assertTrue( math.fabs(result1.pvec[2]-0.060)  < 0.002 )
+
+
+    def test_slit(self):
+        smear = smear_selection(self.data_slit)
+        self.assertEqual(smear.__class__.__name__, 'SlitSmearer')
+
+        fitter = Fit('scipy')
+        
+        # Data: right now this is the only way to set the smearer object
+        # We should improve that and have a way to get access to the
+        # data for a given fit.
+        fitter.set_data(self.data_slit,1)
+        fitter._engine.fit_arrange_dict[1].data_list[0].smearer = smear
+        fitter._engine.fit_arrange_dict[1].data_list[0].qmax = 0.003
+        
+        # Model
+        fitter.set_model(Model(self.sphere),1, ['radius','scale'])
+        fitter.select_problem_for_fit(id=1,value=1)
+        
+        result1, = fitter.fit()
+        
+        #print "v",result1.pvec
+        #print "dv",result1.stderr
+        #print "chisq(v)",result1.fitness
+        
+        self.assertTrue( math.fabs(result1.pvec[0]-2340) < 20 )
+        self.assertTrue( math.fabs(result1.pvec[1]-0.010) < 0.002 )
+
+if __name__ == '__main__':
+    unittest.main()
Index: test/park_integration/test/utest_park_scipy.py
===================================================================
--- test/park_integration/test/utest_park_scipy.py	(revision e544c84d2610bcd83dba5154fafcc4691034075a)
+++ test/park_integration/test/utest_park_scipy.py	(revision e544c84d2610bcd83dba5154fafcc4691034075a)
@@ -0,0 +1,59 @@
+"""
+    Unit tests for fitting module 
+    @author: G. Alina
+"""
+import unittest
+import math
+
+from sans.guiframe.dataFitting import Data1D 
+from sans.fit.AbstractFitEngine import Model,FitData1D
+from sans.fit.Fitting import Fit
+from sans.dataloader.loader import Loader
+from sans.models.MultiplicationModel import MultiplicationModel
+from sans.models.CylinderModel import CylinderModel
+from sans.models.SquareWellStructure import SquareWellStructure
+
+class testFitModule(unittest.TestCase):
+    """ test fitting """
+   
+        
+    def test_scipy(self):
+        """ Simple cylinder model fit (scipy)  """
+        
+        out=Loader().load("cyl_400_20.txt")
+        data = Data1D(x=out.x, y=out.y, dx=out.dx, dy=out.dy)
+        # Receives the type of model for the fitting
+        model1  =  MultiplicationModel(CylinderModel(),SquareWellStructure())
+        model1.setParam('background', 0.0)
+        model1.setParam('sldCyl', 3e-006)
+        model1.setParam('sldSolv', 0.0)
+        model1.setParam('length', 420)
+        model1.setParam('radius', 40)
+        model1.setParam('scale_factor', 2)
+        model1.setParam('volfraction', 0.04)
+        model1.setParam('welldepth', 1.5)
+        model1.setParam('wellwidth', 1.2)
+      
+        model = Model(model1)
+    
+        pars1 =['length','radius','scale_factor']
+        fitter = Fit('scipy')
+        fitter.set_data(data,1)
+        fitter.set_model(model,1,pars1)
+        fitter.select_problem_for_fit(id=1,value=1)
+        result1, = fitter.fit()
+
+        self.assert_(result1)
+        self.assertTrue(len(result1.pvec)>=0 )
+        self.assertTrue(len(result1.stderr)>= 0)
+
+        #print "results",list(zip(result1.pvec, result1.stderr))
+        self.assertTrue( math.fabs(result1.pvec[0]-612)/3.0 <= result1.stderr[0] )
+        self.assertTrue( math.fabs(result1.pvec[1]-20.3)/3.0  <= result1.stderr[1] )
+        self.assertTrue( math.fabs(result1.pvec[2]-25)/3.0 <= result1.stderr[2] )
+        
+        self.assertTrue( result1.fitness/len(data.x) < 1.0 )
+        
+       
+if __name__ == '__main__':
+    unittest.main()  
Index: test/park_integration/test/utest_small_test.py
===================================================================
--- test/park_integration/test/utest_small_test.py	(revision 76f132a28f8a87fc91ae4fe9b234ceda800fa202)
+++ test/park_integration/test/utest_small_test.py	(revision 76f132a28f8a87fc91ae4fe9b234ceda800fa202)
@@ -0,0 +1,42 @@
+"""
+    Unit tests for fitting module 
+"""
+import unittest
+import math
+from sans.fit.Fitting import Fit
+from sans.dataloader.loader import Loader
+
+class testFitModule(unittest.TestCase):
+    """ test fitting """
+    def test_park(self):
+        """ Simple cylinder model fit (scipy)  """
+        
+        out= Loader().load("cyl_400_20.txt")
+       
+        fitter = Fit('scipy')
+        # Receives the type of model for the fitting
+        from sans.models.CylinderModel import CylinderModel
+        model  = CylinderModel()
+        model.setParam('sldCyl', 1)
+        model.setParam('sldSolv', 0)
+
+        pars1 =['length','radius','scale']
+        fitter.set_data(out,1)
+        model.setParam('scale', 1e-10)
+        fitter.set_model(model,1,pars1, constraints=())
+        fitter.select_problem_for_fit(id=1,value=1)
+        result1, = fitter.fit()
+        #print result1
+        #print result1.__dict__
+
+        self.assert_(result1)
+        self.assertTrue(len(result1.pvec)>0 or len(result1.pvec)==0 )
+        self.assertTrue(len(result1.stderr)> 0 or len(result1.stderr)==0)
+        
+        #print result1.pvec[0]-400.0, result1.pvec[0]
+        #print math.fabs(result1.pvec[0]-400.0)/3.0
+        self.assertTrue( math.fabs(result1.pvec[0]-400.0)/3.0 < result1.stderr[0] )
+        self.assertTrue( math.fabs(result1.pvec[1]-20.0)/3.0  < result1.stderr[1] )
+        self.assertTrue( math.fabs(result1.pvec[2]-9.0e-12)/3.0   < result1.stderr[2] )
+        self.assertTrue( result1.fitness < 1.0 )
+        
Index: test/run_one.py
===================================================================
--- test/run_one.py	(revision 95fb3e8659be4e20c87d88465e68b8077488a368)
+++ test/run_one.py	(revision 76f132a28f8a87fc91ae4fe9b234ceda800fa202)
@@ -1,3 +1,4 @@
 #!/usr/bin/env python
+
 import os
 import sys
@@ -8,10 +9,9 @@
 
 run_py = joinpath(dirname(dirname(abspath(__file__))), 'run.py')
-#print run_py
 run = imp.load_source('sasview_run', run_py)
 run.prepare()
 #print "\n".join(sys.path)
-test_path,test_file = splitpath(sys.argv[1])
-print "test file",sys.argv[1]
+test_path,test_file = splitpath(abspath(sys.argv[1]))
+print "=== testing:",sys.argv[1]
 #print test_path, test_file
 sys.argv = [sys.argv[0]]
@@ -20,3 +20,2 @@
 test = imp.load_source('tests',test_file)
 unittest.main(test, testRunner=xmlrunner.XMLTestRunner(output='logs'))
-
