source: sasview/DataLoader/qsmearing.py @ 0ec0405

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

fixed sigular. at sum

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