Index: src/sans/fit/BumpsFitting.py
===================================================================
--- src/sans/fit/BumpsFitting.py	(revision 90f49a886b0e7b34ccf9b13c5bbd18c135e9a268)
+++ src/sans/fit/BumpsFitting.py	(revision 042f0652a0552c6add090233c50477ed4d1361c1)
@@ -2,5 +2,5 @@
 BumpsFitting module runs the bumps optimizer.
 """
-import sys
+import time
 
 import numpy
@@ -25,12 +25,10 @@
         self.data = data
         self.param_list = param_list
-        self.msg_q = msg_q
-        self.curr_thread = curr_thread
-        self.handler = handler
-        self.fitresult = fitresult
-        self.res = []
-        self.func_name = "Functor"
+        self.res = None
         self.theory = None
-        self.name = "Fill in proper name!"
+
+    @property
+    def name(self):
+        return self.model.name
 
     @property
@@ -119,16 +117,58 @@
         #print "params", params
         self.res, self.theory = self.data.residuals(self.model.evalDistribution)
-
-        # TODO: this belongs in monitor not residuals calculation
-        if False: # self.fitresult is not None:
+        return self.res
+
+BOUNDS_PENALTY = 1e6 # cost for going out of bounds on unbounded fitters
+class MonitoredSasProblem(SasProblem):
+    """
+    SAS problem definition for optimizers which do not have monitoring or bounds.
+    """
+    def __init__(self, param_list, model=None, data=None, fitresult=None,
+                 handler=None, curr_thread=None, msg_q=None, update_rate=1):
+        """
+        :param Model: the model wrapper fro sans -model
+        :param Data: the data wrapper for sans data
+        """
+        SasProblem.__init__(self, param_list, model, data)
+        self.msg_q = msg_q
+        self.curr_thread = curr_thread
+        self.handler = handler
+        self.fitresult = fitresult
+        #self.last_update = time.time()
+        #self.func_name = "Functor"
+        #self.name = "Fill in proper name!"
+
+    def residuals(self, p):
+        """
+        Cost function for scipy.optimize.leastsq, which does not have a monitor
+        built into the algorithm, and instead relies on a monitor built into
+        the cost function.
+        """
+        # Note: technically, unbounded fitters and unmonitored fitters are
+        self.setp(x)
+
+        # Compute penalty for being out of bounds which increases the farther
+        # you get out of bounds.  This allows derivative following algorithms
+        # to point back toward the feasible region.
+        penalty = self.bounds_penalty()
+        if penalty > 0:
+            self.theory = numpy.ones(self.data.num_points)
+            self.res = self.theory*(penalty/self.data.num_points) + BOUNDS_PENALTY
+            return self.res
+
+        # If no penalty, then we are not out of bounds and we can use the
+        # normal residual calculation
+        SasProblem.residuals(self, p)
+
+        # send update to the application
+        if True:
             #self.fitresult.set_model(model=self.model)
+            # copy residuals into fit results
             self.fitresult.residuals = self.res+0
             self.fitresult.iterations += 1
             self.fitresult.theory = self.theory+0
 
-            #fitness = self.chisq(params=params)
-            fitness = self.chisq()
-            self.fitresult.p = params
-            self.fitresult.set_fitness(fitness=fitness)
+            self.fitresult.p = numpy.array(p) # force copy, and coversion to array
+            self.fitresult.set_fitness(fitness=self.chisq())
             if self.msg_q is not None:
                 self.msg_q.put(self.fitresult)
@@ -149,45 +189,10 @@
 
         return self.res
-    __call__ = residuals
-
-    def _DEAD_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
-        for p in self.param_list:
-            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
+
+    def bounds_penalty(self):
+        from numpy import sum, where
+        p, bounds = self.getp(), self.bounds()
+        return (sum(where(p<bounds[:,0], bounds[:,0]-p, 0)**2)
+              + sum(where(p>bounds[:,1], bounds[:,1]-p, 0)**2) )
 
 class BumpsFit(FitEngine):
@@ -223,7 +228,5 @@
                 ind = fitproblem[0].pars.index(name)
                 model.setParam(name, fitproblem[0].vals[ind])
-        listdata = fitproblem[0].get_data()
-        # Concatenate dList set (contains one or more data)before fitting
-        data = listdata
+        data = fitproblem[0].get_data()
 
         self.curr_thread = curr_thread
@@ -235,22 +238,27 @@
         if handler is not None:
             handler.set_result(result=result)
-        problem = SasProblem(param_list=self.param_list,
-                              model=model.model,
-                              data=data,
-                              handler=handler,
-                              fitresult=result,
-                              curr_thread=curr_thread,
-                              msg_q=msg_q)
-        try:
-            run_bumps(problem, result, ftol)
-            #run_scipy(problem, result, ftol)
-        except:
-            if hasattr(sys, 'last_type') and sys.last_type == KeyboardInterrupt:
-                if handler is not None:
-                    msg = "Fitting: Terminated!!!"
-                    handler.stop(msg)
-                    raise KeyboardInterrupt, msg
-            else:
-                raise
+
+        if True: # bumps
+            def abort_test():
+                try: curr_thread.isquit()
+                except KeyboardInterrupt:
+                    if handler is not None:
+                        handler.stop("Fitting: Terminated!!!")
+                    return True
+                return False
+
+            problem = SasProblem(param_list=self.param_list,
+                                 model=model.model,
+                                 data=data)
+            run_bumps(problem, result, ftol, abort_test)
+        else:
+            problem = SasProblem(param_list=self.param_list,
+                                 model=model.model,
+                                 data=data,
+                                 handler=handler,
+                                 fitresult=result,
+                                 curr_thread=curr_thread,
+                                 msg_q=msg_q)
+            run_levenburg_marquardt(problem, result, ftol)
 
         if handler is not None:
@@ -264,5 +272,5 @@
         return [result]
 
-def run_bumps(problem, result, ftol):
+def run_bumps(problem, result, ftol, abort_test):
     fitopts = fitters.FIT_OPTIONS[fitters.FIT_DEFAULT]
     fitclass = fitopts.fitclass
@@ -270,5 +278,5 @@
     options['ftol'] = ftol
     fitdriver = fitters.FitDriver(fitclass, problem=problem,
-                                  abort_test=lambda: False, **options)
+                                  abort_test=abort_test, **options)
     mapper = SerialMapper 
     fitdriver.mapper = mapper.start_mapper(problem, None)
@@ -289,5 +297,5 @@
     result.theory = problem.theory
 
-def run_scipy(model, result, ftol):
+def run_levenburg_marquardt(model, result, ftol):
     # This import must be here; otherwise it will be confused when more
     # than one thread exist.
Index: src/sans/fit/ScipyFitting.py
===================================================================
--- src/sans/fit/ScipyFitting.py	(revision 95d58d3a800344be2703a5e297ab0e7b153c6309)
+++ src/sans/fit/ScipyFitting.py	(revision 042f0652a0552c6add090233c50477ed4d1361c1)
@@ -287,5 +287,5 @@
     : param range: min or max value of the bounds
     """
-    return 0.1 (limit if limit != 0.0 else 1.0)
+    return 0.1 * (limit if limit != 0.0 else 1.0)
 
     
