Index: DataLoader/extensions/smearer.cpp
===================================================================
--- DataLoader/extensions/smearer.cpp	(revision a3f8d58994d10df4c15d5350e0eb4ab2acfcb19d)
+++ DataLoader/extensions/smearer.cpp	(revision 58598621b309b5bbe6274791cf8c235063c194ce)
@@ -33,4 +33,22 @@
 	// whether we need to compute one
 	has_matrix = false;
+	even_binning = true;
+};
+
+/**
+ * Constructor for BaseSmearer
+ *
+ * Used for uneven binning
+ * @param q: array of Q values
+ * @param nbins: number of Q bins
+ */
+BaseSmearer :: BaseSmearer(double* q, int nbins) {
+	// Number of bins
+	this->nbins = nbins;
+	this->q_values = q;
+	// Flag to keep track of whether we have a smearing matrix or
+	// whether we need to compute one
+	has_matrix = false;
+	even_binning = false;
 };
 
@@ -50,12 +68,26 @@
 };
 
-	/**
-	 * Constructor for SlitSmearer
-	 *
-	 * @param width: array slit widths for each Q point, in Q units
-	 * @param qmin: minimum Q value
-	 * @param qmax: maximum Q value
-	 * @param nbins: number of Q bins
-	 */
+/**
+ * Constructor for SlitSmearer
+ *
+ * @param width: slit width in Q units
+ * @param height: slit height in Q units
+ * @param q: array of Q values
+ * @param nbins: number of Q bins
+ */
+SlitSmearer :: SlitSmearer(double width, double height, double* q, int nbins) :
+	BaseSmearer(q, nbins){
+	this->height = height;
+	this->width = width;
+};
+
+/**
+ * Constructor for QSmearer
+ *
+ * @param width: array slit widths for each Q point, in Q units
+ * @param qmin: minimum Q value
+ * @param qmax: maximum Q value
+ * @param nbins: number of Q bins
+ */
 QSmearer :: QSmearer(double* width, double qmin, double qmax, int nbins) :
 	BaseSmearer(qmin, qmax, nbins){
@@ -64,13 +96,46 @@
 
 /**
+ * Constructor for QSmearer
+ *
+ * @param width: array slit widths for each Q point, in Q units
+ * @param q: array of Q values
+ * @param nbins: number of Q bins
+ */
+QSmearer :: QSmearer(double* width, double* q, int nbins) :
+	BaseSmearer(q, nbins){
+	this->width = width;
+};
+
+/**
  * Compute the slit smearing matrix
+ *
+ * For even binning (q_min to q_max with nbins):
+ *
+ *   step = (q_max-q_min)/(nbins-1)
+ *   first bin goes from q_min to q_min+step
+ *   last bin goes from q_max to q_max+step
+ *
+ * For binning according to q array:
+ *
+ * Each q point represents a bin going from half the distance between it
+ * and the previous point to half the distance between it and the next point.
+ *
+ *    Example: bin i goes from (q_values[i-1]+q_values[i])/2 to (q_values[i]+q_values[i+1])/2
+ *
+ * The exceptions are the first and last bins, which are centered at the first and
+ * last q-values, respectively. The width of the first and last bins is the distance between
+ * their respective neighboring q-value.
  */
 void SlitSmearer :: compute_matrix(){
 
 	weights = new vector<double>(nbins*nbins,0);
+
+	// Check the length of the data
+	if (nbins<2) return;
 
 	// Loop over all q-values
 	for(int i=0; i<nbins; i++) {
-		double q = qmin + (double)i*(qmax-qmin)/((double)nbins-1.0);
+		double q, q_min, q_max;
+		get_bin_range(i, &q, &q_min, &q_max);
 
 		// For each q-value, compute the weight of each other q-bin
@@ -102,5 +167,21 @@
 				}
 				double q_shifted = sqrt( ((q-shift_w)*(q-shift_w) + shift_h*shift_h) );
-				int q_i = (int)(floor( (q_shifted-qmin) /((qmax-qmin)/((double)nbins -1.0)) ));
+
+				// Find in which bin this shifted value belongs
+				int q_i=nbins;
+				if (even_binning) {
+					// This is kept for backward compatibility since the binning
+					// was originally defined differently for even bins.
+					q_i = (int)(floor( (q_shifted-qmin) /((qmax-qmin)/((double)nbins -1.0)) ));
+				} else {
+					for(int t=0; t<nbins; t++) {
+						double q_t, q_high, q_low;
+						get_bin_range(t, &q_t, &q_low, &q_high);
+						if(q_shifted>=q_low && q_shifted<q_high) {
+							q_i = t;
+							break;
+						}
+					}
+				}
 
 				// Skip the entries outside our I(q) range
@@ -121,11 +202,11 @@
 	// Loop over all q-values
 	double step = (qmax-qmin)/((double)nbins-1.0);
+	double q, q_min, q_max;
+	double q_j, q_jmax, q_jmin;
 	for(int i=0; i<nbins; i++) {
-		double q = qmin + (double)i*step;
-		double q_min = q - 0.5*step;
-		double q_max = q + 0.5*step;
+		get_bin_range(i, &q, &q_min, &q_max);
 
 		for(int j=0; j<nbins; j++) {
-			double q_j = qmin + (double)j*step;
+			get_bin_range(j, &q_j, &q_jmin, &q_jmax);
 
 			// Compute the fraction of the Gaussian contributing
@@ -139,4 +220,38 @@
 
 /**
+ * Computes the Q range of a given bin of the Q distribution.
+ * The range is computed according the the data distribution that
+ * was given to the object at initialization.
+ *
+ * @param i: number of the bin in the distribution
+ * @param q: q-value of bin i
+ * @param q_min: lower bound of the bin
+ * @param q_max: higher bound of the bin
+ *
+ */
+void BaseSmearer :: get_bin_range(int i, double* q, double* q_min, double* q_max) {
+	if (even_binning) {
+		double step = (qmax-qmin)/((double)nbins-1.0);
+		*q = qmin + (double)i*step;
+		*q_min = *q - 0.5*step;
+		*q_max = *q + 0.5*step;
+	} else {
+		*q = q_values[i];
+		if (i==0) {
+			double step = (q_values[1]-q_values[0])/2.0;
+			*q_min = *q - step;
+			*q_max = *q + step;
+		} else if (i==nbins-1) {
+			double step = (q_values[i]-q_values[i-1])/2.0;
+			*q_min = *q - step;
+			*q_max = *q + step;
+		} else {
+			*q_min = *q - (q_values[i]-q_values[i-1])/2.0;
+			*q_max = *q + (q_values[i+1]-q_values[i])/2.0;
+		}
+	}
+}
+
+/**
  * Perform smearing by applying the smearing matrix to the input Q array
  */
Index: DataLoader/extensions/smearer.hh
===================================================================
--- DataLoader/extensions/smearer.hh	(revision a3f8d58994d10df4c15d5350e0eb4ab2acfcb19d)
+++ DataLoader/extensions/smearer.hh	(revision 58598621b309b5bbe6274791cf8c235063c194ce)
@@ -24,7 +24,12 @@
 class BaseSmearer {
 protected:
+	// Internal flag: true when the weights vector is filled
 	bool has_matrix;
-    // Smearing matrix
-    vector<double>* weights;
+	// True when only qmin, qmax and nbins are given. Bins are equidistant
+	bool even_binning;
+	// Smearing matrix
+	vector<double>* weights;
+	// Q vector
+	double* q_values;
     // Q_min (Min Q-value for I(q))
     double qmin;
@@ -37,4 +42,5 @@
     // Constructor
     BaseSmearer(double qmin, double qmax, int nbins);
+    BaseSmearer(double* q, int nbins);
 	// Smear function
 	virtual void smear(double *, double *, int, int);
@@ -43,4 +49,6 @@
 	// Utility function to check the number of bins
 	int get_nbins() { return nbins; }
+	// Get the q range of a particular bin
+	virtual void get_bin_range(int, double*, double*, double*);
 };
 
@@ -63,4 +71,5 @@
     // Constructor
 	SlitSmearer(double width, double height, double qmin, double qmax, int nbins);
+	SlitSmearer(double width, double height, double* q, int nbins);
 	// Compute the smearing matrix
 	virtual void compute_matrix();
@@ -80,5 +89,6 @@
 
     // Constructor
-    QSmearer(double* width,double qmin, double qmax, int nbins);
+    QSmearer(double* width, double qmin, double qmax, int nbins);
+    QSmearer(double* width, double* q, int nbins);
 	// Compute the smearing matrix
 	virtual void compute_matrix();
Index: DataLoader/extensions/smearer_module.cpp
===================================================================
--- DataLoader/extensions/smearer_module.cpp	(revision a3f8d58994d10df4c15d5350e0eb4ab2acfcb19d)
+++ DataLoader/extensions/smearer_module.cpp	(revision 58598621b309b5bbe6274791cf8c235063c194ce)
@@ -54,4 +54,20 @@
 
 /**
+ * Create a SlitSmearer as a python object by supplying a q array
+ */
+PyObject * new_slit_smearer_with_q(PyObject *, PyObject *args) {
+	PyObject *qvalues_obj;
+	Py_ssize_t n_q;
+	double* qvalues;
+	double width;
+	double height;
+
+	if (!PyArg_ParseTuple(args, "ddO", &width, &height, &qvalues_obj)) return NULL;
+	OUTVECTOR(qvalues_obj, qvalues, n_q);
+	SlitSmearer* smearer = new SlitSmearer(width, height, qvalues, n_q);
+	return PyCObject_FromVoidPtr(smearer, del_slit_smearer);
+}
+
+/**
  * Delete a QSmearer object
  */
@@ -76,4 +92,22 @@
 	OUTVECTOR(width_obj, width, n_w);
 	QSmearer* smearer = new QSmearer(width, qmin, qmax, nbins);
+	return PyCObject_FromVoidPtr(smearer, del_q_smearer);
+}
+
+/**
+ * Create a QSmearer as a python object by supplying a q array
+ */
+PyObject * new_q_smearer_with_q(PyObject *, PyObject *args) {
+	PyObject *width_obj;
+	Py_ssize_t n_w;
+	double* width;
+	PyObject *qvalues_obj;
+	Py_ssize_t n_q;
+	double* qvalues;
+
+	if (!PyArg_ParseTuple(args, "OO", &width_obj, &qvalues_obj)) return NULL;
+	OUTVECTOR(width_obj, width, n_w);
+	OUTVECTOR(qvalues_obj, qvalues, n_q);
+	QSmearer* smearer = new QSmearer(width, qvalues, n_q);
 	return PyCObject_FromVoidPtr(smearer, del_q_smearer);
 }
@@ -114,4 +148,23 @@
 }
 
+/**
+ * Get the q-value of a given bin
+ */
+PyObject * get_q(PyObject *, PyObject *args) {
+	PyObject *smear_obj;
+	int bin;
+
+	if (!PyArg_ParseTuple(args, "Oi", &smear_obj, &bin)) return NULL;
+
+	// Set the array pointers
+	void *temp = PyCObject_AsVoidPtr(smear_obj);
+	BaseSmearer* s = static_cast<BaseSmearer *>(temp);
+
+	double q, q_min, q_max;
+	s->get_bin_range(bin, &q, &q_min, &q_max);
+
+	return Py_BuildValue("d", q);
+}
+
 
 /**
@@ -121,8 +174,14 @@
 	{"new_slit_smearer", (PyCFunction)new_slit_smearer, METH_VARARGS,
 		  "Create a new Slit Smearer object"},
+	{"new_slit_smearer_with_q", (PyCFunction)new_slit_smearer_with_q, METH_VARARGS,
+		  "Create a new Slit Smearer object by supplying an array of Q values"},
 	{"new_q_smearer", (PyCFunction)new_q_smearer, METH_VARARGS,
 		  "Create a new Q Smearer object"},
+	{"new_q_smearer_with_q", (PyCFunction)new_q_smearer_with_q, METH_VARARGS,
+		  "Create a new Q Smearer object by supplying an array of Q values"},
 	{"smear",(PyCFunction)smear_input, METH_VARARGS,
 		  "Smear the given input array"},
+	{"get_q",(PyCFunction)get_q, METH_VARARGS,
+		  "Get the q-value of a given bin"},
     {NULL}
 };
Index: DataLoader/qsmearing.py
===================================================================
--- DataLoader/qsmearing.py	(revision a3f8d58994d10df4c15d5350e0eb4ab2acfcb19d)
+++ DataLoader/qsmearing.py	(revision 58598621b309b5bbe6274791cf8c235063c194ce)
@@ -12,4 +12,5 @@
 import numpy
 import math
+import logging, sys
 import scipy.special
 
@@ -99,4 +100,32 @@
         
     def _compute_matrix(self): return NotImplemented
+
+    def get_bin_range(self, q_min=None, q_max=None):
+        """
+            @param q_min: minimum q-value to smear
+            @param q_max: maximum q-value to smear 
+        """
+        if q_min == None:
+            q_min = self.min
+        
+        if q_max == None:
+            q_max = self.max
+        
+        _qmin_unsmeared, _qmax_unsmeared = self.get_unsmeared_range(q_min, q_max)
+        
+        _first_bin = None
+        _last_bin  = None
+
+        step = (self.max-self.min)/(self.nbins-1.0)
+        for i in range(self.nbins):
+            q_i = smearer.get_q(self._smearer, i)
+            if (q_i >= _qmin_unsmeared) and (q_i <= _qmax_unsmeared):
+                # Identify first and last bin
+                if _first_bin is None:
+                    _first_bin = i
+                else:
+                    _last_bin  = i
+               
+        return _first_bin, _last_bin
 
     def __call__(self, iq_in, first_bin=0, last_bin=None):
@@ -161,7 +190,22 @@
             This method HAS to be called before smearing
         """
-        self._smearer = smearer.new_slit_smearer(self.width, self.height, self.min, self.max, self.nbins)
+        #self._smearer = smearer.new_slit_smearer(self.width, self.height, self.min, self.max, self.nbins)
+        self._smearer = smearer.new_slit_smearer_with_q(self.width, self.height, self.qvalues)
         self._init_complete = True
 
+    def get_unsmeared_range(self, q_min, q_max):
+        """
+            Determine the range needed in unsmeared-Q to cover
+            the smeared Q range
+        """
+        # Range used for input to smearing
+        _qmin_unsmeared = q_min
+        _qmax_unsmeared = q_max 
+        try:
+            _qmin_unsmeared = self.min
+            _qmax_unsmeared = self.max
+        except:
+            logging.error("_SlitSmearer.get_bin_range: %s" % sys.exc_value)
+        return _qmin_unsmeared, _qmax_unsmeared
 
 class SlitSmearer(_SlitSmearer):
@@ -199,9 +243,10 @@
         self.nbins = len(data1D.x)
         ## Minimum Q 
-        self.min = data1D.x[0]
+        self.min = min(data1D.x)
         ## Maximum
-        self.max = data1D.x[len(data1D.x)-1]        
-
-        #print "nbin,npts",self.nbins,self.npts
+        self.max = max(data1D.x)
+        ## Q-values
+        self.qvalues = data1D.x
+        
 
 class _QSmearer(_BaseSmearer):
@@ -236,6 +281,26 @@
             This method HAS to be called before smearing
         """
-        self._smearer = smearer.new_q_smearer(numpy.asarray(self.width), self.min, self.max, self.nbins)
+        #self._smearer = smearer.new_q_smearer(numpy.asarray(self.width), self.min, self.max, self.nbins)
+        self._smearer = smearer.new_q_smearer_with_q(numpy.asarray(self.width), self.qvalues)
         self._init_complete = True
+        
+    def get_unsmeared_range(self, q_min, q_max):
+        """
+            Determine the range needed in unsmeared-Q to cover
+            the smeared Q range
+            Take 3 sigmas as the offset between smeared and unsmeared space
+        """
+        # Range used for input to smearing
+        _qmin_unsmeared = q_min
+        _qmax_unsmeared = q_max 
+        try:
+            offset = 3.0*max(self.width)
+            _qmin_unsmeared = max([self.min, q_min-offset])
+            _qmax_unsmeared = min([self.max, q_max+offset])
+        except:
+            logging.error("_QSmearer.get_bin_range: %s" % sys.exc_value)
+        return _qmin_unsmeared, _qmax_unsmeared
+        
+        
         
 class QSmearer(_QSmearer):
@@ -260,7 +325,9 @@
         self.nbins = len(data1D.x)
         ## Minimum Q 
-        self.min = data1D.x[0]
+        self.min = min(data1D.x)
         ## Maximum
-        self.max = data1D.x[len(data1D.x)-1]        
+        self.max = max(data1D.x)
+        ## Q-values
+        self.qvalues = data1D.x
 
 
Index: DataLoader/test/utest_smearing.py
===================================================================
--- DataLoader/test/utest_smearing.py	(revision a3f8d58994d10df4c15d5350e0eb4ab2acfcb19d)
+++ DataLoader/test/utest_smearing.py	(revision 58598621b309b5bbe6274791cf8c235063c194ce)
@@ -54,5 +54,7 @@
         input = 12.0-numpy.arange(1,11)
         output = s(input)
-        answer = [ 9.666,  9.056,  8.329,  7.494,  6.642,  5.721,  4.774,  3.824,  2.871, 2.   ]
+        # The following commented line was the correct output for even bins [see smearer.cpp for details] 
+        #answer = [ 9.666,  9.056,  8.329,  7.494,  6.642,  5.721,  4.774,  3.824,  2.871, 2.   ]
+        answer = [ 9.2302,  8.6806,  7.9533,  7.1673,  6.2889,  5.4,     4.5028,  3.5744,  2.6083, 2.    ]
         for i in range(len(input)):
             self.assertAlmostEqual(answer[i], output[i], 2)
