Index: sansview/perspectives/fitting/calcthread.py
===================================================================
--- sansview/perspectives/fitting/calcthread.py	(revision 20be9463a765b4503ffa26778e9bec366206be3f)
+++ sansview/perspectives/fitting/calcthread.py	(revision 20be9463a765b4503ffa26778e9bec366206be3f)
@@ -0,0 +1,297 @@
+# This program is public domain
+
+## \file
+#  \brief Abstract class for defining calculation threads.
+#
+
+import thread, traceback
+
+import sys
+if sys.platform.count("darwin")>0:
+    import mactime as time
+else:
+    import time
+
+class CalcThread:
+    """Threaded calculation class.  Inherit from here and specialize
+    the compute() method to perform the appropriate operations for the
+    class.
+
+    If you specialize the __init__ method be sure to call
+    CalcThread.__init__, passing it the keyword arguments for
+    yieldtime, worktime, update and complete.
+    
+    When defining the compute() method you need to include code which
+    allows the GUI to run.  They are as follows:
+        self.isquit()          call frequently to check for interrupts
+        self.update(kw=...)    call when the GUI could be updated
+        self.complete(kw=...)  call before exiting compute()
+    The update() and complete() calls accept field=value keyword
+    arguments which are passed to the called function.  complete()
+    should be called before exiting the GUI function.  A KeyboardInterrupt
+    event is triggered if the GUI signals that the computation should
+    be halted.
+
+    The following documentation should be included in the description
+    of the derived class.
+
+    The user of this class will call the following:
+
+        thread = Work(...,kw=...)  prepare the work thread.
+        thread.queue(...,kw=...)   queue a work unit
+        thread.requeue(...,kw=...) replace work unit on the end of queue
+        thread.reset(...,kw=...)   reset the queue to the given work unit
+        thread.stop()              clear the queue and halt
+        thread.interrupt()         halt the current work unit but continue
+        thread.ready(delay=0.)     request an update signal after delay
+        thread.isrunning()         returns true if compute() is running
+
+    Use queue() when all work must be done.  Use requeue() when intermediate
+    work items don't need to be done (e.g., in response to a mouse move
+    event).  Use reset() when the current item doesn't need to be completed
+    before the new event (e.g., in response to a mouse release event).  Use
+    stop() to halt the current and pending computations (e.g., in response to
+    a stop button).
+    
+    The methods queue(), requeue() and reset() are proxies for the compute()
+    method in the subclass.  Look there for a description of the arguments.
+    The compute() method can be called directly to run the computation in
+    the main thread, but it should not be called if isrunning() returns true.
+
+    The constructor accepts additional keywords yieldtime=0.01 and
+    worktime=0.01 which determine the cooperative multitasking
+    behaviour.  Yield time is the duration of the sleep period
+    required to give other processes a chance to run.  Work time
+    is the duration between sleep periods.
+
+    Notifying the GUI thread of work in progress and work complete
+    is done with updatefn=updatefn and completefn=completefn arguments
+    to the constructor.  Details of the parameters to the functions
+    depend on the particular calculation class, but they will all
+    be passed as keyword arguments.  Details of how the functions
+    should be implemented vary from framework to framework.
+
+    For wx, something like the following is needed:
+
+        import wx, wx.lib.newevent
+        (CalcCompleteEvent, EVT_CALC_COMPLETE) = wx.lib.newevent.NewEvent()
+
+        # methods in the main window class of your application
+        def __init__():
+            ...
+            # Prepare the calculation in the GUI thread.
+            self.work = Work(completefn=self.CalcComplete)
+            self.Bind(EVT_CALC_COMPLETE, self.OnCalcComplete)
+            ...
+            # Bind work queue to a menu event.
+            self.Bind(wx.EVT_MENU, self.OnCalcStart, id=idCALCSTART)
+            ...
+
+        def OnCalcStart(self,event):
+            # Start the work thread from the GUI thread.
+            self.work.queue(...work unit parameters...)
+
+        def CalcComplete(self,**kwargs):
+            # Generate CalcComplete event in the calculation thread.
+            # kwargs contains field1, field2, etc. as defined by
+            # the Work thread class.
+            event = CalcCompleteEvent(**kwargs)
+            wx.PostEvent(self, event)
+
+        def OnCalcComplete(self,event):
+            # Process CalcComplete event in GUI thread.
+            # Use values from event.field1, event.field2 etc. as
+            # defined by the Work thread class to show the results.
+            ...
+    """
+
+    def __init__(self,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        """Prepare the calculator"""
+        self.yieldtime     = yieldtime
+        self.worktime      = worktime
+        self.completefn    = completefn
+        self.updatefn      = updatefn
+        self._interrupting = False
+        self._running      = False
+        self._queue        = []
+        self._lock         = thread.allocate_lock()
+        self._delay        = 1e6
+
+    def queue(self,*args,**kwargs):
+        """Add a work unit to the end of the queue.  See the compute()
+        method for details of the arguments to the work unit."""
+        self._lock.acquire()
+        self._queue.append((args,kwargs))
+        # Cannot do start_new_thread call within the lock
+        self._lock.release()
+        if not self._running:
+            # print "Starting thread"
+            self._time_for_update = time.clock()+1e6
+            thread.start_new_thread(self._run,())
+
+    def requeue(self,*args,**kwargs):
+        """Replace the work unit on the end of the queue.  See the compute()
+        method for details of the arguments to the work unit."""
+        self._lock.acquire()
+        self._queue = self._queue[:-1]
+        self._lock.release()
+        self.queue(*args,**kwargs)
+
+    def reset(self,*args,**kwargs):
+        """Clear the queue and start a new work unit.  See the compute()
+        method for details of the arguments to the work unit."""
+        self.stop()
+        self.queue(*args,**kwargs)
+
+    def stop(self):
+        """Clear the queue and stop the thread.  New items may be
+        queued after stop.  To stop just the current work item, and
+        continue the rest of the queue call the interrupt method"""
+        self._lock.acquire()
+        self._interrupting = True
+        self._queue = []
+        self._lock.release()
+
+    def interrupt(self):
+        """Stop the current work item.  To clear the work queue as
+        well call the stop() method."""
+        self._lock.acquire()
+        self._interrupting = True
+        self._lock.release()
+
+    def isrunning(self): return self._running
+
+    def ready(self, delay=0.):
+        """Ready for another update after delay=t seconds.  Call
+        this for threads which can show intermediate results from
+        long calculations."""
+        self._delay = delay
+        self._lock.acquire()
+        self._time_for_update = time.clock() + delay
+        # print "setting _time_for_update to ",self._time_for_update
+        self._lock.release()
+
+    def isquit(self):
+        """Check for interrupts.  Should be called frequently to
+        provide user responsiveness.  Also yields to other running
+        threads, which is required for good performance on OS X."""
+
+        # Only called from within the running thread so no need to lock
+        if self._running and self.yieldtime>0 and time.clock()>self._time_for_nap:
+            # print "sharing"
+            time.sleep(self.yieldtime)
+            self._time_for_nap = time.clock() + self.worktime
+        if self._interrupting: raise KeyboardInterrupt
+
+    def update(self,**kwargs):
+       
+        """Update GUI with the lastest results from the current work unit."""
+      
+        if self.updatefn != None and time.clock() > self._time_for_update:
+            self._lock.acquire()
+            self._time_for_update = time.clock() + self._delay
+            self._lock.release()
+            
+            #self._time_for_update += 1e6  # No more updates
+            
+            self.updatefn(**kwargs)
+            time.sleep(self.yieldtime)
+            if self._interrupting: raise KeyboardInterrupt
+        else:
+            self.isquit()
+        return
+
+    def complete(self,**kwargs):
+        """Update the GUI with the completed results from a work unit."""
+        if self.completefn != None:
+            self.completefn(**kwargs)
+            time.sleep(self.yieldtime)
+        return
+
+    def compute(self,*args,**kwargs):
+        """Perform a work unit.  The subclass will provide details of
+        the arguments."""
+        raise NotImplemented, "Calculation thread needs compute method"
+
+    def _run(self):
+        """Internal function to manage the thread."""
+        # The code for condition wait in the threading package is
+        # implemented using polling.  I'll accept for now that the
+        # authors of this code are clever enough that polling is
+        # difficult to avoid.  Rather than polling, I will exit the
+        # thread when the queue is empty and start a new thread when
+        # there is more work to be done.
+        while 1:
+            self._lock.acquire()
+            # print "lock aquired"
+            self._time_for_nap = time.clock()+self.worktime
+            self._running = True
+            if self._queue == []: break
+            self._interrupting = False
+            args,kwargs = self._queue[0]
+            self._queue = self._queue[1:]
+            self._lock.release()
+            # print "lock released"
+            try:
+                self.compute(*args,**kwargs)
+            except KeyboardInterrupt:
+                pass
+            except:
+                traceback.print_exc()
+                #print 'CalcThread exception',
+        self._running = False
+
+# ======================================================================
+# Demonstration of calcthread in action
+class CalcDemo(CalcThread):
+    """Example of a calculation thread."""
+    def compute(self,n):
+        total = 0.
+        for i in range(n):
+            #self.update(i=i)
+            for j in range(n):
+                self.isquit()
+                total += j
+        self.complete(total=total)
+
+class CalcCommandline:
+    def __init__(self, n=20000):
+        print thread.get_ident()
+        self.starttime = time.clock()
+        self.done = False
+        self.work = CalcDemo(completefn=self.complete,
+                             updatefn=self.update, yieldtime=0.001)
+        #self.work2 = CalcDemo(completefn=self.complete,
+        #                     updatefn=self.update)
+        #self.work3 = CalcDemo(completefn=self.complete,
+        #                     updatefn=self.update)
+        self.work.queue(n)
+        #self.work2.queue(n)
+        #self.work3.queue(n)
+        print "Expect updates from Main every second and from thread every 2.5 seconds"
+        print ""
+        self.work.ready(.5)
+        while not self.done:
+            time.sleep(1)
+            print "Main thread %d at %.2f"%(thread.get_ident(),time.clock()-self.starttime)
+
+    def update(self,i=0):
+        print "Update i=%d from thread %d at %.2f"%(i,thread.get_ident(),time.clock()-self.starttime)
+        self.work.ready(2.5)
+
+    def complete(self,total=0.0):
+        print "Complete total=%g from thread %d at %.2f"%(total,thread.get_ident(),time.clock()-self.starttime)
+        self.done = True
+
+if __name__ == "__main__":
+    CalcCommandline()
+
+# version
+__id__ = "$Id: calcthread.py 249 2007-06-15 17:03:01Z ziwen $"
+
+# End of file
Index: sansview/perspectives/fitting/fitting.py
===================================================================
--- sansview/perspectives/fitting/fitting.py	(revision 86c1832466ddab5c573aec133a29d224902b0e03)
+++ sansview/perspectives/fitting/fitting.py	(revision 20be9463a765b4503ffa26778e9bec366206be3f)
@@ -643,5 +643,28 @@
                 except:
                     raise
-    def _draw_model2D(self,model,name,description=None, enable2D=False,qmin=None,qmax=None, qstep=None):
+    def update(self, output):
+        print "Got an update"
+    
+    def complete(self, output, elapsed, model, qmin, qmax):
+        #printEVT("Calc complete in %g sec" % elapsed) 
+        wx.PostEvent(self.parent, StatusEvent(status="Calc \
+        complete in %g sec" % elapsed))
+                           
+        print "complete",output, model,qmin, qmax
+        data = output
+        theory= Data2D(data)
+        theory.name= model.name
+        theory.group_id ="Model"
+        theory.id ="Model"
+        theory.xmin= qmin
+        theory.xmax= qmax
+        theory.ymin= qmin
+        theory.ymax= qmax
+        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
+                         title="Analytical model 2D %s" %str(model.name)))
+         
+        
+         
+    def _draw_model2D(self,model,description=None, enable2D=False,qmin=None,qmax=None, qstep=None):
         if qmin==None:
             qmin= -0.05
@@ -655,27 +678,46 @@
         #print x
         data=numpy.zeros([len(x),len(y)])
+        self.model= model
         if enable2D:
-            #print "drawing model 2D params",qmin, qmax,model.getParamList()
-            for i_x in range(int(len(x))):
-                for i_y in range(len(y)):
+            from model_thread import Calc2D
+            self.calc_thread = Calc2D(parent =self.parent,x=x, y=y,model= self.model, qmin=qmin,qmax=qmax,
+                            completefn=self.complete,
+                            updatefn=self.update)
+            self.calc_thread.queue()
+            self.calc_thread.ready(2.5)
+           
+                
+                
+    def H_draw_model2D(self,model,description=None, enable2D=False,qmin=None,qmax=None, qstep=None):
+        if qmin==None:
+            qmin= -0.05
+        if qmax==None:
+            qmax= 0.05
+        if qstep ==None:
+            qstep =0.001
+        x = numpy.arange(qmin,qmax, qstep)
+        y = numpy.arange(qmin,qmax,qstep)
+        lx = len(self.x)
+        if enable2D:
+            data=numpy.zeros([len(x),len(y)])
+            for i in range(len(x)):
+                for j in range(len(x)):
                     try:
-                        value = model.runXY([x[i_x],y[i_y]])
-                        data[i_y][i_x] = value
+                        data[i][j]=model.runXY([j,i])
                     except:
                          wx.PostEvent(self.parent, StatusEvent(status="\
-                        Error computing %s at [%g,%g] :%s" %(model.name,x[i_x],y[i_y], sys.exc_value)))
-            #print "data2 draw" ,data          
-            theory= Data2D(data)
-            theory.name= name
-            theory.group_id ="Model"
-            theory.id ="Model"
-            theory.xmin= qmin
-            theory.xmax= qmax
-            theory.ymin= qmin
-            theory.ymax= qmax
-            wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
-                             title="Analytical model 2D %s" %str(name)))
-             
-  
+                        Model 2D cannot be plot %g %s %s" %(data[i][j],model.name, sys.exc_value)))
+           
+    
+    def on_draw_model2D(self, event):
+        """
+             plot view model 2D
+        """
+        
+        if self.enable_model2D== True:
+            self.enable_model2D=False
+        else:
+            self.enable_model2D=True
+        print "self.enable_model2D",self.enable_model2D
 if __name__ == "__main__":
     i = Plugin()
Index: sansview/perspectives/fitting/model_thread.py
===================================================================
--- sansview/perspectives/fitting/model_thread.py	(revision 20be9463a765b4503ffa26778e9bec366206be3f)
+++ sansview/perspectives/fitting/model_thread.py	(revision 20be9463a765b4503ffa26778e9bec366206be3f)
@@ -0,0 +1,450 @@
+import time
+from calcthread import CalcThread
+from sans.guicomm.events import NewPlotEvent, StatusEvent  
+import sys
+import wx
+class Calc2D_all(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 2-fold symmetry of the model
+        where points are computed for one half of the detector
+        and I(qx, qy) = I(-qx, -qy) is assumed.
+    """
+    
+    def __init__(self, x, y, model,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        
+        self.x = x
+        self.y = y
+        self.model = model
+        self.starttime = 0
+        
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            #printEVT("Calc %s interrupted" % self.model.name)
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+            raise KeyboardInterrupt
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+            
+        self.starttime = time.time()
+        lx = len(self.x)
+        
+        #for i_x in range(int(len(self.x)/2)):
+        for i_x in range(len(self.x)):
+            if i_x%2==1:
+                continue
+            
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+                
+            for i_y in range(len(self.y)):
+                value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                output[i_y][i_x] = value
+                #output[lx-i_y-1][lx-i_x-1] = value
+                
+        if lx%2==1:
+            i_x = int(len(self.x)/2)
+            for i_y in range(len(self.y)):
+                value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                output[i_y][i_x] = value
+                
+        #for i_x in range(int(len(self.x)/2)):
+        for i_x in range(len(self.x)):
+            if not i_x%2==1:
+                continue
+
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+            
+            for i_y in range(len(self.y)):
+                value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                output[i_y][i_x] = value
+                #output[lx-i_y-1][lx-i_x-1] = value
+            
+        elapsed = time.time()-self.starttime
+        self.complete(output=output, elapsed=elapsed)
+
+
+class Calc2D(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 2-fold symmetry of the model
+        where points are computed for one half of the detector
+        and I(qx, qy) = I(-qx, -qy) is assumed.
+    """
+    
+    def __init__(self,parent, x, y, model,qmin, qmax,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.parent =parent
+        self.qmin= qmin
+        self.qmax=qmax
+        self.x = x
+        self.y = y
+        self.model = model
+        self.starttime = 0
+        
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            #printEVT("Calc %s interrupted" % self.model.name)
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+           
+            raise KeyboardInterrupt
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+        if self.qmin *self.qmax >=0:
+            print "same signe plotting"
+            if self.qmax==0:
+                center_x= self.qmin/2
+                center_y= self.qmin /2
+            else:
+                center_x= (self.qmax -self.qmin)/2
+                center_y= (self.qmax -self.qmin)/2
+        else:
+            center_x=0
+            center_y=0
+        print "center_x , center_y",center_x , center_y
+        print "x ",len(x)
+        print "y", y
+        print "int(len(self.x)/2)",int(len(self.x)/2)
+        self.starttime = time.time()
+        lx = len(self.x)
+       
+        for i_x in range(int(len(self.x)/2)+1):
+           
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+            
+            for i_y in range(int(len(self.y)/2)+1):
+                try:
+                    value1 = self.model.runXY([self.x[i_x]-center_x, self.y[i_y]-center_y])
+                    value2 = self.model.runXY([self.x[i_x]-center_x, self.y[lx-i_y-1]-center_y])
+                    output[i_y][i_x] = value1 +value2
+                    output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                    output[lx-i_y-1][i_x] = value1 + value2
+                    output[i_y][lx-i_x-1] = value1 + value2
+          
+
+                except:
+                     wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Error computing %s at [%g,%g]" %(self.model.name, self.x[i_x],self.y[i_y])))
+           
+        elapsed = time.time()-self.starttime
+        self.complete(
+                      output=output, elapsed=elapsed,model= self.model,
+                      qmin= self.qmin,
+                      qmax=self.qmax)
+
+class Calc2D_old(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 2-fold symmetry of the model
+        where points are computed for one half of the detector
+        and I(qx, qy) = I(-qx, -qy) is assumed.
+    """
+    
+    def __init__(self, x, y, model,qmin, qmax,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.qmin= qmin
+        self.qmax=qmax
+        self.x = x
+        self.y = y
+        self.model = model
+        self.starttime = 0
+        
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            #printEVT("Calc %s interrupted" % self.model.name)
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+           
+            raise KeyboardInterrupt
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+            
+        self.starttime = time.time()
+        lx = len(self.x)
+        
+        for i_x in range(int(len(self.x)/2)):
+            if i_x%2==1:
+                continue
+            
+            # Check whether we need to bail out (before updating!)
+            self.isquit()
+            self.update(output=output)
+                
+            for i_y in range(len(self.y)):
+                try:
+                    value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                    #output[i_x][i_y] = value
+                    #output[lx-i_x-1][lx-i_y-1] = value
+                    output[i_y][i_x] = value
+                    output[lx-i_y-1][lx-i_x-1] = value
+                except:
+                    wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Error computing %s at [%g,%g]" %(self.model.name, self.x[i_x],self.y[i_y])))
+           
+        if lx%2==1:
+            i_x = int(len(self.x)/2)
+            for i_y in range(len(self.y)):
+                try:
+                    value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                    #output[i_x][i_y] = value
+                    output[i_y][i_x] = value
+                except:
+                    
+                    wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Error computing %s at [%g,%g]" %(self.model.name, self.x[i_x],self.y[i_y])))
+           
+        for i_x in range(int(len(self.x)/2)):
+            if not i_x%2==1:
+                continue
+
+            # Check whether we need to bail out
+            self.isquit()
+            self.update(output=output)
+            
+            for i_y in range(len(self.y)):
+                try:
+                    value = self.model.runXY([self.x[i_x], self.y[i_y]])
+                    #output[i_x][i_y] = value
+                    #output[lx-i_x-1][lx-i_y-1] = value
+                    output[i_y][i_x] = value
+                    output[lx-i_y-1][lx-i_x-1] = value
+                except:
+                    
+                    wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Error computing %s at [%g,%g]" %(self.model.name, self.x[i_x],self.y[i_y])))
+           
+        elapsed = time.time()-self.starttime
+        self.complete(
+                      output=output, elapsed=elapsed,model= self.model,
+                      qmin= self.qmin,
+                      qmax=self.qmax)
+
+
+class Calc2D_4fold(CalcThread):
+    """
+        Compute 2D model
+        This calculation assumes a 4-fold symmetry of the model.
+        Really is the same calculation time since we have to 
+        calculate points for 0<phi<pi anyway.
+    """
+    
+    def __init__(self, x, y, model,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.x = x
+        self.y = y
+        self.model = model
+        self.starttime = 0
+        
+    def isquit(self):
+        try:
+            CalcThread.isquit(self)
+        except KeyboardInterrupt:
+            #printEVT("Calc %s interrupted" % self.model.name)
+            wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Calc %s interrupted" % self.model.name))
+           
+            raise KeyboardInterrupt
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        y = self.y
+        output = numpy.zeros((len(x),len(y)))
+            
+        self.starttime = time.time()
+        lx = len(self.x)
+        
+        for i_x in range(int(len(self.x)/2)):
+            if i_x%2==1:
+                continue
+            
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+                
+            for i_y in range(int(len(self.y)/2)):
+                value1 = self.model.runXY([self.x[i_x], self.y[i_y]])
+                value2 = self.model.runXY([self.x[i_x], self.y[lx-i_y-1]])
+                output[i_y][i_x] = value1 + value2
+                output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                output[lx-i_y-1][i_x] = value1 + value2
+                output[i_y][lx-i_x-1] = value1 + value2
+                
+        if lx%2==1:
+            i_x = int(len(self.x)/2)
+            for i_y in range(int(len(self.y)/2)):
+                value1 = self.model.runXY([self.x[i_x], self.y[i_y]])
+                value2 = self.model.runXY([self.x[i_x], self.y[lx-i_y-1]])
+                output[i_y][i_x] = value1 + value2
+                output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                output[lx-i_y-1][i_x] = value1 + value2
+                output[i_y][lx-i_x-1] = value1 + value2
+                
+        for i_x in range(int(len(self.x)/2)):
+            if not i_x%2==1:
+                continue
+
+            # Check whether we need to bail out
+            self.update(output=output)
+            self.isquit()
+            
+            for i_y in range(int(len(self.y)/2)):
+                value1 = self.model.runXY([self.x[i_x], self.y[i_y]])
+                value2 = self.model.runXY([self.x[i_x], self.y[lx-i_y-1]])
+                output[i_y][i_x] = value1 + value2
+                output[lx-i_y-1][lx-i_x-1] = value1 + value2
+                output[lx-i_y-1][i_x] = value1 + value2
+                output[i_y][lx-i_x-1] = value1 + value2
+            
+        elapsed = time.time()-self.starttime
+        self.complete(output=output, elapsed=elapsed)
+
+
+
+class Calc1D(CalcThread):
+    """Compute 1D data"""
+    
+    def __init__(self, x, model,
+                 completefn = None,
+                 updatefn   = None,
+                 yieldtime  = 0.01,
+                 worktime   = 0.01
+                 ):
+        CalcThread.__init__(self,completefn,
+                 updatefn,
+                 yieldtime,
+                 worktime)
+        self.x = x
+        self.model = model
+        self.starttime = 0
+        
+    def compute(self):
+        import numpy
+        x = self.x
+        output = numpy.zeros(len(x))
+            
+        self.starttime = time.time()
+        
+        for i_x in range(len(self.x)):
+             
+            # Check whether we need to bail out
+            self.isquit()
+                
+            try:
+                value = self.model.run(self.x[i_x])
+                output[i_x] = value
+            except:
+            
+                wx.PostEvent(self.parent, StatusEvent(status=\
+                       "Error computing %s at %g" %(self.model.name, self.x[i_x])))
+           
+        elapsed = time.time()-self.starttime
+        self.complete(output=output, elapsed=elapsed)
+
+class CalcCommandline:
+    def __init__(self, n=20000):
+        #print thread.get_ident()
+        from sans.models.CylinderModel import CylinderModel
+        from sans.models.DisperseModel import DisperseModel
+        import Averager2D
+        import pylab
+        
+        submodel = CylinderModel()
+        #model = Averager2D.Averager2D()
+        #model.set_model(submodel)
+        #model.set_dispersity([['cyl_phi',0.2,10],
+        #                      ['cyl_theta',0.2,10],
+        #                      ['length',10,10],])
+        
+        model = DisperseModel(submodel, ['cyl_phi', 'cyl_theta', 'length'],
+                                        [0.2, 0.2, 10.0])
+        model.setParam('n_pts', 10)
+         
+        print model.runXY([0.01, 0.02])
+        
+        qmax = 0.01
+        qstep = 0.0001
+        self.done = False
+        
+        x = pylab.arange(-qmax, qmax+qstep*0.01, qstep)
+        y = pylab.arange(-qmax, qmax+qstep*0.01, qstep)
+    
+        calc_thread_2D = Calc2D(x, y, model.clone(), 
+                                        completefn=self.complete,
+                                        updatefn=self.update,
+                                        yieldtime=0.0)
+     
+        calc_thread_2D.queue()
+        calc_thread_2D.ready(2.5)
+        
+        while not self.done:
+            time.sleep(1)
+
+    def update(self,output):
+        print "update"
+
+    def complete(self,output, elapsed=0.0):
+        print "complete"
+        self.done = True
+
+if __name__ == "__main__":
+    CalcCommandline()
+   
Index: sansview/perspectives/fitting/modelpage.py
===================================================================
--- sansview/perspectives/fitting/modelpage.py	(revision 24ea33c05309d2058e555a4f33efcb3955bc0a8c)
+++ sansview/perspectives/fitting/modelpage.py	(revision 20be9463a765b4503ffa26778e9bec366206be3f)
@@ -134,4 +134,5 @@
         # preview selected model name
         self.prevmodel_name=name
+        print "model view prev_model",name
         self.modelbox.SetValue(self.prevmodel_name)
         # flag to check if the user has selected a new model in the combox box
@@ -179,5 +180,5 @@
         if self.enable2D==False:
             self.enable2D=True
-            self.manager.draw_model(model=self.model,name=self.prevmodel_name,
+            self.manager.draw_model(model=self.model,
                                     description=None,
                                      enable2D=self.enable2D,
