source: sasview/DataLoader/qsmearing.py @ 28ea782

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 28ea782 was d594a81, checked in by Jae Cho <jhjcho@…>, 16 years ago

fixed bugs in smearer

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[d00f8ff]1"""
2This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4project funded by the US National Science Foundation.
5
6See the license text in license.txt
7
8copyright 2008, University of Tennessee
9"""
[4fe4394]10
11
[d00f8ff]12import numpy
13import math
14import scipy.special
15
16def smear_selection(data1D):
17    """
18        Creates the right type of smearer according
[4fe4394]19        to the data.
20   
21        The canSAS format has a rule that either
22        slit smearing data OR resolution smearing data
23        is available.
24       
25        For the present purpose, we choose the one that
26        has none-zero data. If both slit and resolution
27        smearing arrays are filled with good data
28        (which should not happen), then we choose the
29        resolution smearing data.
30       
31        @param data1D: Data1D object
[d00f8ff]32    """
[4fe4394]33    # Sanity check. If we are not dealing with a SANS Data1D
34    # object, just return None
[21d2eb0]35    if  data1D.__class__.__name__ != 'Data1D':
36        return None
37   
38    if  not hasattr(data1D, "dx") and not hasattr(data1D, "dxl") and not hasattr(data1D, "dxw"):
[4fe4394]39        return None
40   
41    # Look for resolution smearing data
42    _found_resolution = False
43    if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
44       
45        # Check that we have non-zero data
46        if data1D.dx[0]>0.0:
47            _found_resolution = True
[21d2eb0]48            print "_found_resolution",_found_resolution
[4fe4394]49    # If we found resolution smearing data, return a QSmearer
50    if _found_resolution == True:
51        return QSmearer(data1D)
52
53    # Look for slit smearing data
54    _found_slit = False
55    if data1D.dxl is not None and len(data1D.dxl)==len(data1D.x) \
56        and data1D.dxw is not None and len(data1D.dxw)==len(data1D.x):
57       
58        # Check that we have non-zero data
59        if data1D.dxl[0]>0.0 or data1D.dxw[0]>0.0:
60            _found_slit = True
61       
62        # Sanity check: all data should be the same as a function of Q
63        for item in data1D.dxl:
64            if data1D.dxl[0] != item:
65                _found_resolution = False
66                break
67           
68        for item in data1D.dxw:
69            if data1D.dxw[0] != item:
70                _found_resolution = False
71                break
72           
73    # If we found slit smearing data, return a slit smearer
74    if _found_slit == True:
75        return SlitSmearer(data1D)
76   
77    return None
78           
[d00f8ff]79
80class _BaseSmearer(object):
81   
82    def __init__(self):
83        self.nbins = 0
84        self._weights = None
85       
86    def _compute_matrix(self): return NotImplemented
87
88    def __call__(self, iq):
89        """
90            Return the smeared I(q) value at the given q.
91            The smeared I(q) is computed using a predetermined
92            smearing matrix for a particular binning.
93       
94            @param q: I(q) array
95            @return: smeared I(q)
96        """
97        # Sanity check
98        if len(iq) != self.nbins:
99            raise RuntimeError, "Invalid I(q) vector: inconsistent array length %s <> %s" % (len(iq), self.nbins)
100       
101        if self._weights == None:
102            self._compute_matrix()
103           
104        iq_smeared = numpy.zeros(self.nbins)
105        # Loop over q-values
106        for q_i in range(self.nbins):
107            sum = 0.0
108            counts = 0.0   
109           
110            for i in range(self.nbins):
[fe2ade9]111                if iq[i]!=0 and self._weights[q_i][i]!=0:
112                    sum += iq[i] * self._weights[q_i][i] 
113                    counts += self._weights[q_i][i]
114                    #print "i,iq[i],self._weights[q_i][i] ",i,iq[i],self._weights[q_i][i]
[0ec0405]115            if counts == 0:
116                iq_smeared[q_i] = 0
117            else:
118                iq_smeared[q_i] = sum/counts
[fe2ade9]119            #print "q_i,iq_smeared[q_i]",q_i,iq[i],iq_smeared[q_i]
120            #print "iq[i],iq_smeared[q_i],sum,counts,self.nbins",iq[i], iq_smeared[q_i],sum,counts,self.nbins
[d00f8ff]121        return iq_smeared   
122   
123class _SlitSmearer(_BaseSmearer):
124    """
125        Slit smearing for I(q) array
126    """
127   
128    def __init__(self, nbins=None, width=None, height=None, min=None, max=None):
129        """
130            Initialization
131           
132            @param iq: I(q) array [cm-1]
133            @param width: slit width [A-1]
134            @param height: slit height [A-1]
135            @param min: Q_min [A-1]
136            @param max: Q_max [A-1]
137        """
138        ## Slit width in Q units
139        self.width  = width
140        ## Slit height in Q units
141        self.height = height
142        ## Q_min (Min Q-value for I(q))
143        self.min    = min
144        ## Q_max (Max Q_value for I(q))
145        self.max    = max
146        ## Number of Q bins
147        self.nbins  = nbins
148        ## Number of points used in the smearing computation
149        self.npts   = 1000
150        ## Smearing matrix
151        self._weights = None
152       
153    def _compute_matrix(self):
154        """
155            Compute the smearing matrix for the current I(q) array
156        """
157        weights = numpy.zeros([self.nbins, self.nbins])
158       
159        # Loop over all q-values
160        for i in range(self.nbins):
161            q = self.min + i*(self.max-self.min)/float(self.nbins-1.0)
162           
163            # For each q-value, compute the weight of each other q-bin
164            # in the I(q) array
[fe2ade9]165            npts_h = self.nbins if self.height>0 else 1 #changed self.npts=>self.nbins
166            npts_w = self.nbins if self.width>0 else 1 #changed self.npts=>self.nbins
[d00f8ff]167           
168            # If both height and width are great than zero,
169            # modify the number of points in each direction so
170            # that the total number of points is still what
171            # the user would expect (downgrade resolution)
172            if npts_h>1 and npts_w>1:
173                npts_h = int(math.ceil(math.sqrt(self.npts)))
174                npts_w = npts_h
175               
176            for k in range(npts_h):
177                if npts_h==1:
178                    shift_h = 0
179                else:
180                    shift_h = self.height/(float(npts_h-1.0)) * k
181                for j in range(npts_w):
182                    if npts_w==1:
183                        shift_w = 0
184                    else:
185                        shift_w = self.width/(float(npts_w-1.0)) * j
186                    q_shifted = math.sqrt( ((q-shift_w)*(q-shift_w) + shift_h*shift_h) )
187                    q_i = int(math.floor( (q_shifted-self.min)/((self.max-self.min)/(self.nbins -1.0)) ))
188                   
189                    # Skip the entries outside our I(q) range
190                    #TODO: be careful with edge effect
191                    if q_i<self.nbins:
192                        weights[i][q_i] = weights[i][q_i]+1.0
[d594a81]193        print "nbin,npts",self.nbins,self.npts
[fe2ade9]194
[d00f8ff]195        self._weights = weights
196        return self._weights
197
198class SlitSmearer(_SlitSmearer):
199    """
200        Adaptor for slit smearing class and SANS data
201    """
202    def __init__(self, data1D):
203        """
204            Assumption: equally spaced bins of increasing q-values.
205           
206            @param data1D: data used to set the smearing parameters
207        """
208        # Initialization from parent class
209        super(SlitSmearer, self).__init__()
210       
211        ## Slit width
212        self.width = 0
213        if data1D.dxw is not None and len(data1D.dxw)==len(data1D.x):
214            self.width = data1D.dxw[0]
215            # Sanity check
216            for value in data1D.dxw:
217                if value != self.width:
218                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
219               
220        ## Slit height
221        self.height = 0
222        if data1D.dxl is not None and len(data1D.dxl)==len(data1D.x):
223            self.height = data1D.dxl[0]
224            # Sanity check
225            for value in data1D.dxl:
226                if value != self.height:
227                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
228       
229        ## Number of Q bins
230        self.nbins = len(data1D.x)
231        ## Minimum Q
232        self.min = data1D.x[0]
233        ## Maximum
234        self.max = data1D.x[len(data1D.x)-1]       
235
236
237class _QSmearer(_BaseSmearer):
238    """
239        Perform Gaussian Q smearing
240    """
241       
242    def __init__(self, nbins=None, width=None, min=None, max=None):
243        """
244            Initialization
245           
246            @param nbins: number of Q bins
[c0d9981]247            @param width: array standard deviation in Q [A-1]
[d00f8ff]248            @param min: Q_min [A-1]
249            @param max: Q_max [A-1]
250        """
251        ## Standard deviation in Q [A-1]
252        self.width  = width
253        ## Q_min (Min Q-value for I(q))
254        self.min    = min
255        ## Q_max (Max Q_value for I(q))
256        self.max    = max
257        ## Number of Q bins
258        self.nbins  = nbins
259        ## Smearing matrix
260        self._weights = None
261       
262    def _compute_matrix(self):
263        """
264            Compute the smearing matrix for the current I(q) array
265        """
266        weights = numpy.zeros([self.nbins, self.nbins])
267       
268        # Loop over all q-values
269        step = (self.max-self.min)/float(self.nbins-1.0)
270        for i in range(self.nbins):
271            q = self.min + i*step
272            q_min = q - 0.5*step
273            q_max = q + 0.5*step
274            for j in range(self.nbins):
275                q_j = self.min + j*step
276               
277                # Compute the fraction of the Gaussian contributing
278                # to the q bin between q_min and q_max
[fe2ade9]279                #value =  math.exp(-math.pow((q_max-q_j),2)/(2*math.pow(self.width[j],2) ))
280                #value +=  math.exp(-math.pow((q_max-q_j),2)/(2*math.pow(self.width[j],2) ))
[4fe4394]281                value =  scipy.special.erf( (q_max-q_j)/(math.sqrt(2.0)*self.width[j]) ) 
282                value -=scipy.special.erf( (q_min-q_j)/(math.sqrt(2.0)*self.width[j]) ) 
[d00f8ff]283                weights[i][j] += value
284                               
285        self._weights = weights
286        return self._weights
287       
288class QSmearer(_QSmearer):
289    """
290        Adaptor for Gaussian Q smearing class and SANS data
291    """
292    def __init__(self, data1D):
293        """
294            Assumption: equally spaced bins of increasing q-values.
295           
296            @param data1D: data used to set the smearing parameters
297        """
298        # Initialization from parent class
299        super(QSmearer, self).__init__()
300       
[c0d9981]301        ## Resolution
[4fe4394]302        self.width = numpy.zeros(len(data1D.x))
[d00f8ff]303        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
[4fe4394]304            self.width = data1D.dx
[d00f8ff]305       
306        ## Number of Q bins
307        self.nbins = len(data1D.x)
308        ## Minimum Q
309        self.min = data1D.x[0]
310        ## Maximum
311        self.max = data1D.x[len(data1D.x)-1]       
312
313
314if __name__ == '__main__':
315    x = 0.001*numpy.arange(1,11)
316    y = 12.0-numpy.arange(1,11)
317    print x
318    #for i in range(10): print i, 0.001 + i*0.008/9.0
319    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
320
321   
322    s = _SlitSmearer(nbins=10, width=0.0, height=0.005, min=0.001, max=0.010)
323    #s = _QSmearer(nbins=10, width=0.001, min=0.001, max=0.010)
324    s._compute_matrix()
325
326    sy = s(y)
327    print sy
328   
329    if True:
330        for i in range(10):
[fe2ade9]331            print x[i],y[i], sy[i]
[d00f8ff]332            #print q, ' : ', s.weight(q), s._compute_iq(q)
333            #print q, ' : ', s(q), s._compute_iq(q)
334            #s._compute_iq(q)
335
336
337
338
Note: See TracBrowser for help on using the repository browser.