Index: sansmodels/igor_wrapper/test/Averager2D.py
===================================================================
--- sansmodels/igor_wrapper/test/Averager2D.py	(revision 25a60dc18cfd6e9a29a6a6c01bf49e2862c62e61)
+++ sansmodels/igor_wrapper/test/Averager2D.py	(revision 25a60dc18cfd6e9a29a6a6c01bf49e2862c62e61)
@@ -0,0 +1,320 @@
+"""
+    Class to average an oriented model
+    Options:
+        - flat average in one or both coordinates (specified)
+        - given distribution in one or both coordinates (specified)
+        
+    Uses DisperseModel to allow for polydispersity
+"""
+
+from sans.models.BaseComponent import BaseComponent
+import copy, os, math
+    
+class Averager2D(BaseComponent):
+    
+
+    def __init__(self):
+        BaseComponent.__init__(self)
+        self.params = {}
+        self.model      = None
+        self.dispersed  = None
+        self.phi_file   = None
+        self.theta_file = None
+        self.phi_name   = None
+        self.theta_name = None
+        self.phi_on     = False
+        self.theta_on   = False
+        
+        self.phi_data   = None
+        self.theta_data = None
+        self.dispersion = []
+        self.runXY      = self.run_oriented
+        self.run        = self.run_oriented
+        self.disp_model_run = None
+        self.details    = None
+
+    def __str__(self):
+        info  = "%s (%s)\n" % (self.name, self.model.__class__.__name__)
+        info += "Pars: %s\n" % self.model.params
+        info += "Disp: %s\n" % self.dispersion
+        info += "Disp: %s\n" % self.dispersed.params
+        return info
+
+    def clone(self):
+        obj            = Averager2D()
+        obj.params     = copy.deepcopy(self.params)
+        obj.details    = copy.deepcopy(self.details)
+        obj.model      = self.model.clone()
+        obj.phi_file   = copy.deepcopy(self.phi_file)
+        obj.theta_file = copy.deepcopy(self.theta_file)
+        obj.phi_name   = copy.deepcopy(self.phi_name)
+        obj.theta_name = copy.deepcopy(self.theta_name)
+        obj.name       = copy.deepcopy(self.name)
+        obj.phi_on = self.phi_on
+        obj.theta_on = self.theta_on
+        obj.dispersion = copy.deepcopy(self.dispersion)
+        obj.update_functor()
+        return obj   
+
+    def set_model(self, model):
+        self.name = model.name
+        self.model = model
+        self.params = model.params
+        self.details = model.details
+        retval = self._find_angles()
+        self.update_functor()
+        self.disp_model_run = self.model.runXY
+        return retval
+        
+    def setParam(self, name, value):
+        # Keep a local copy for badly implemented code
+        # that access params directly
+        #TODO: fix that!
+        if name.lower() in self.params:
+            self.params[name.lower()] = value
+        return self.model.setParam(name, value)
+        
+    def getParam(self, name):
+        return self.model.getParam(name)
+
+    def _find_angles(self):
+        """
+            Find which model parameters represent
+            theta and phi
+            @return: True if at least one angle was found
+        """
+        self.theta_name = None
+        self.phi_name   = None
+        for item in self.model.params:
+            if item.lower().count("theta")>0:
+                self.theta_name = item
+            elif item.lower().count("phi")>0:
+                self.phi_name = item
+                
+        if self.theta_name == None and self.phi_name == None:
+            return False
+        return True
+        
+    def setPhiFile(self, path):
+        """
+            Check the validity of a path and store it
+            @param path: file path
+            @return: True if all OK, False if can't be set
+        """
+        
+        # If it's the same file, do nothing
+        if self.phi_file == path:
+            return True
+        
+        if path==None or self.phi_name == None:
+            self.phi_file = None
+            self.phi_data = None
+            self.phi_on   = False
+            self.update_functor()
+        elif os.path.isfile(path):
+            self.phi_file = path
+            #self.phi_data = self.read_file(path)
+            self.phi_on = True
+            self.update_functor()
+        else:
+            raise ValueError, "%s is not a file" % path
+        
+        if self.phi_name == None:
+            return False
+        else:
+            return True
+
+    def read_file(self, path):
+        input_f = open(path, 'r')
+        buff = input_f.read()
+        lines = buff.split('\n')
+        
+        angles = []
+        
+        for line in lines:
+            toks = line.split()
+            if len(toks)==2:
+                try:
+                    angle = float(toks[0])
+                    weight = float(toks[1])
+                except:
+                    # Skip non-data lines
+                    pass
+                angles.append([angle, weight])
+        return angles
+                
+
+    def setThetaFile(self, path):
+        """
+            Check the validity of a path and store it
+            @param path: file path
+            @return: True if all OK, False if can't be set
+        """
+        
+        # If it's the same file, do nothing
+        if self.theta_file == path:
+            return True
+        
+        if path==None or self.theta_name == None:
+            self.theta_file = None
+            self.theta_data = None
+            self.theta_on   = False
+            self.update_functor()
+        elif os.path.isfile(path):
+            self.theta_file = path
+            #self.theta_data = self.read_file(path)
+            self.theta_on = True
+            self.update_functor()
+        else:
+            raise ValueError, "%s is not a file" % path
+
+        if self.theta_name == None:
+            return False
+        else:
+            return True
+
+    def update_functor(self):
+        # Protect against empty model
+        if self.model==None:
+            return
+        
+        self.set_dispersity(self.dispersion)
+        #phi_points = [[self.model.getParam(self.phi_name), 1.0]]
+        #theta_points = [[self.model.getParam(self.theta_name), 1.0]]
+        
+       # Initialize theta points to visit
+        if self.theta_on:
+            # Check whether we have the data
+            if not self.theta_file == None and self.theta_data == None:
+                self.theta_data = self.read_file(self.theta_file)
+            elif not self.model == None:
+                self.theta_data = [[self.model.getParam(self.phi_name), 1.0]]
+            else:
+                self.theta_data = []
+            
+        # Initialize phi points to visit
+        if self.phi_on:
+            # Check whether we have the data
+            if not self.phi_file == None and self.phi_data == None:
+                self.phi_data = self.read_file(self.phi_file)
+            elif not self.model == None:
+                self.phi_data = [[self.model.getParam(self.theta_name), 1.0]]
+            else:
+                self.phi_data = []
+                
+        if self.phi_on and self.theta_on:
+            self.runXY = self.run_theta_phi
+        elif not self.phi_on and self.theta_on:
+            self.runXY = self.run_theta
+        elif not self.theta_on and self.phi_on:
+            self.runXY = self.run_phi
+        else:
+            self.runXY = self.run_oriented
+                
+    def get_dispersity(self):
+        return self.dispersion
+    
+    def set_dispersity(self, disp):
+        from sans.models.DisperseModel import DisperseModel
+        
+        if len(disp) == 0 and len(self.dispersion) == 0:
+            self.disp_model_run = self.model.runXY
+            return False
+        
+        self.dispersion = disp
+        if len(self.dispersion)==0:
+            self.disp_model_run = self.model.runXY
+            self.dispersed = None
+            
+            return True
+        
+        
+        name_list = []
+        val_list  = []
+        npts = 0
+        for item in disp:
+            name_list.append(item[0])
+            val_list.append(item[1])
+            # For now, us largest
+            if item[2]>npts:
+                npts = item[2]
+            
+        self.dispersed = DisperseModel(self.model, name_list, val_list)
+        self.dispersed.setParam('n_pts', npts)
+        self.disp_model_run = self.dispersed.runXY
+        
+        return True
+                
+    def run_oriented(self, x=0):
+        return self.disp_model_run(x)
+    
+    def run_phi(self, x=0):
+        sum  = 0
+        norm = 0
+        background = 0
+        
+        # If we have a background, perform the average
+        # only with bck=0 and add it at the end
+        if "background" in self.model.getParamList():
+            background = self.model.getParam('background')
+            self.model.setParam('background', 0.0)
+
+        for ph_i in self.phi_data:
+            self.model.setParam(self.phi_name, ph_i[0])
+            sum += self.disp_model_run(x) * ph_i[1]
+            norm += ph_i[1]
+                
+        # Restore original background value
+        if "background" in self.model.getParamList():
+            self.model.setParam('background', background)
+
+        return sum / norm + background
+    
+    def run_theta(self, x=0):
+        sum  = 0
+        norm = 0
+        background = 0
+        
+        # If we have a background, perform the average
+        # only with bck=0 and add it at the end
+        if "background" in self.model.getParamList():
+            background = self.model.getParam('background')
+            self.model.setParam('background', 0.0)
+            
+        for th_i in self.theta_data:
+            self.model.setParam(self.theta_name, th_i[0])
+            sum += self.disp_model_run(x) * math.sin(th_i[0]) * th_i[1]
+            norm += th_i[1]
+                
+        # Restore original background value
+        if "background" in self.model.getParamList():
+            self.model.setParam('background', background)
+
+        return sum / norm + background
+    
+    def run_theta_phi(self, x=0):
+        sum  = 0
+        norm = 0
+        background = 0
+        
+        # If we have a background, perform the average
+        # only with bck=0 and add it at the end
+        if "background" in self.model.getParamList():
+            background = self.model.getParam('background')
+            self.model.setParam('background', 0.0)
+
+        for th_i in self.theta_data:
+            self.model.setParam(self.theta_name, th_i[0])
+            
+            for ph_i in self.phi_data:
+                self.model.setParam(self.phi_name, ph_i[0])
+                sum += self.disp_model_run(x) * math.sin(th_i[0]) * ph_i[1] * th_i[1]
+                norm += ph_i[1] * th_i[1]
+        
+        # Restore original background value
+        if "background" in self.model.getParamList():
+            self.model.setParam('background', background)
+       
+        return sum / norm + background       
+
+    
