Index: sansmodels/src/igor_wrapper/test/Averager2D.py
===================================================================
--- sansmodels/src/igor_wrapper/test/Averager2D.py	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
+++ sansmodels/src/igor_wrapper/test/Averager2D.py	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
@@ -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       
+
+    
Index: sansmodels/src/igor_wrapper/test/Makefile
===================================================================
--- sansmodels/src/igor_wrapper/test/Makefile	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
+++ sansmodels/src/igor_wrapper/test/Makefile	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
@@ -0,0 +1,10 @@
+
+
+
+all:
+	gcc test.c ../src/disp_cylinder.c ../src/c_disperser.c \
+	../../sans/models/c_extensions/cylinder.c \
+	../../libigor/libCylinder.c \
+	../src/weighted_cylinder.c \
+	-I ../../sans/models/c_extensions -I ../../libigor -I ../include \
+	-o test
Index: sansmodels/src/igor_wrapper/test/phi.txt
===================================================================
--- sansmodels/src/igor_wrapper/test/phi.txt	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
+++ sansmodels/src/igor_wrapper/test/phi.txt	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
@@ -0,0 +1,3 @@
+0.01 1.0
+1.5  1.0
+2.0  1.0
Index: sansmodels/src/igor_wrapper/test/test.c
===================================================================
--- sansmodels/src/igor_wrapper/test/test.c	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
+++ sansmodels/src/igor_wrapper/test/test.c	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
@@ -0,0 +1,74 @@
+#include "../include/danse.h"
+#include <stdio.h>
+
+int main(){
+	double output;
+	double pars[11];	
+	double q, phi;
+	double theta_vals[17];
+	double theta_w[17];
+	double phi_vals[17];
+	double phi_w[17];
+	int i;
+	
+	pars[0] = 1.0;
+	pars[1] = 20.0; // radius
+	pars[2] = 400.0; // length
+	pars[3] = 1.0;  // contrast
+	pars[4] = 0.0;  // bck
+	pars[5] = 1.57; //theta
+	pars[6] = 0.0;  // phi
+	pars[7] = 0.0;  // disp theta
+	pars[8] = 0.0;  // disp phi
+	pars[9] = 0.0;  // disp radius
+	pars[10] = 0.0;
+	
+	theta_vals[0] = 0.01;
+	theta_vals[1] = 0.1;
+	theta_vals[2] = 0.2;
+	theta_vals[3] = 0.3;
+	theta_vals[4] = 0.4;
+	theta_vals[5] = 0.5;
+	theta_vals[6] = 0.6;
+	theta_vals[7] = 0.7;
+	theta_vals[8] = 0.8;
+	theta_vals[9] = 0.9;
+	theta_vals[10] = 1.0;
+	theta_vals[11] = 1.1;
+	theta_vals[12] = 1.2;
+	theta_vals[13] = 1.3;
+	theta_vals[14] = 1.4;
+	theta_vals[15] = 1.5;
+	theta_vals[16] = 1.6;
+	
+	for(i=0; i<17; i++) {
+	   theta_w[i] = 1.0;
+	}
+	
+	q = 0.025;
+	phi = 0.0;
+	
+	// Testing oriented cylinder
+	output = oriented_cylinder_2D(pars, q, phi);
+	printf("oriented output = %g\n", output);
+	
+	// Testing dispersed with no dispersion
+	output = disperse_cylinder_analytical_2D(pars, q, phi);
+	printf("disp output     = %g\n", output);
+
+	// Testing dispersed with dispersion
+	pars[10] = 100.0;
+	pars[7]  = 3.0;
+	output = disperse_cylinder_analytical_2D(pars, q, phi);
+	printf("disp output     = %g\n", output);
+
+	// Testing input dist
+	pars[10] = 0.0;
+	pars[7]  = 0.0;
+	pars[1]  = 20.0;
+	output = cylinder_Weights(pars, phi_vals, phi_w, 0, 
+								theta_vals, theta_w, 17, 
+								q, phi); 
+	printf("weight output     = %g\n", output);
+
+}
Index: sansmodels/src/igor_wrapper/test/test.py
===================================================================
--- sansmodels/src/igor_wrapper/test/test.py	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
+++ sansmodels/src/igor_wrapper/test/test.py	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
@@ -0,0 +1,34 @@
+from sans.models.CylinderModel import CylinderModel
+from sans.models.DisperseModel import DisperseModel
+import math
+
+cyl = CylinderModel()
+cyl.setParam('scale', 1.0)
+cyl.setParam('radius', 20.0)
+cyl.setParam('length', 400.0)
+cyl.setParam('contrast', 1.0)
+cyl.setParam('background', 0.0)
+cyl.setParam('cyl_theta', 1.57)
+cyl.setParam('cyl_phi', 0.0)
+
+q=0.025
+phi=0.0
+
+print "oriented output", cyl.run([q, phi])
+
+
+
+name_list=['radius']
+val_list = [3.0]
+dispersed = DisperseModel(cyl, name_list, val_list)
+dispersed.setParam('n_pts', 100)
+print "disp output", dispersed.run([q, phi])
+
+
+
+from Averager2D import Averager2D
+avg = Averager2D()
+avg.set_model(cyl)
+#avg.set_dispersity([['radius', 3.0, 100]])
+avg.setThetaFile('theta.txt')
+print avg.runXY([q, 0])
Index: sansmodels/src/igor_wrapper/test/theta.txt
===================================================================
--- sansmodels/src/igor_wrapper/test/theta.txt	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
+++ sansmodels/src/igor_wrapper/test/theta.txt	(revision ae3ce4eaa593202ebf49122e196897c0d45a25b6)
@@ -0,0 +1,17 @@
+0.01 1
+.1 1
+.2 1
+.3 1
+.4 1
+.5 1
+.6 1
+.7 1
+.8 1
+.9 1
+1. 1
+1.1 1
+1.2 1
+1.3 1
+1.4 1
+1.5 1
+1.6 1
