source: sasview/DataLoader/qsmearing.py @ d594a81

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 d594a81 was d594a81, checked in by Jae Cho <jhjcho@…>, 15 years ago

fixed bugs in smearer

  • Property mode set to 100644
File size: 11.6 KB
Line 
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"""
10
11
12import numpy
13import math
14import scipy.special
15
16def smear_selection(data1D):
17    """
18        Creates the right type of smearer according
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
32    """
33    # Sanity check. If we are not dealing with a SANS Data1D
34    # object, just return None
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"):
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
48            print "_found_resolution",_found_resolution
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           
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):
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]
115            if counts == 0:
116                iq_smeared[q_i] = 0
117            else:
118                iq_smeared[q_i] = sum/counts
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
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
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
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
193        print "nbin,npts",self.nbins,self.npts
194
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
247            @param width: array standard deviation in Q [A-1]
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
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) ))
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]) ) 
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       
301        ## Resolution
302        self.width = numpy.zeros(len(data1D.x))
303        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
304            self.width = data1D.dx
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):
331            print x[i],y[i], sy[i]
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.