source: sasview/DataLoader/qsmearing.py @ fe2ade9

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

fixed a bug in slit smearing

  • Property mode set to 100644
File size: 11.3 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            iq_smeared[q_i] = sum/counts
114            #print "q_i,iq_smeared[q_i]",q_i,iq[i],iq_smeared[q_i]
115            #print "iq[i],iq_smeared[q_i],sum,counts,self.nbins",iq[i], iq_smeared[q_i],sum,counts,self.nbins
116        return iq_smeared   
117   
118class _SlitSmearer(_BaseSmearer):
119    """
120        Slit smearing for I(q) array
121    """
122   
123    def __init__(self, nbins=None, width=None, height=None, min=None, max=None):
124        """
125            Initialization
126           
127            @param iq: I(q) array [cm-1]
128            @param width: slit width [A-1]
129            @param height: slit height [A-1]
130            @param min: Q_min [A-1]
131            @param max: Q_max [A-1]
132        """
133        ## Slit width in Q units
134        self.width  = width
135        ## Slit height in Q units
136        self.height = height
137        ## Q_min (Min Q-value for I(q))
138        self.min    = min
139        ## Q_max (Max Q_value for I(q))
140        self.max    = max
141        ## Number of Q bins
142        self.nbins  = nbins
143        ## Number of points used in the smearing computation
144        self.npts   = 1000
145        ## Smearing matrix
146        self._weights = None
147       
148    def _compute_matrix(self):
149        """
150            Compute the smearing matrix for the current I(q) array
151        """
152        weights = numpy.zeros([self.nbins, self.nbins])
153       
154        # Loop over all q-values
155        for i in range(self.nbins):
156            q = self.min + i*(self.max-self.min)/float(self.nbins-1.0)
157           
158            # For each q-value, compute the weight of each other q-bin
159            # in the I(q) array
160            npts_h = self.nbins if self.height>0 else 1 #changed self.npts=>self.nbins
161            npts_w = self.nbins if self.width>0 else 1 #changed self.npts=>self.nbins
162           
163            # If both height and width are great than zero,
164            # modify the number of points in each direction so
165            # that the total number of points is still what
166            # the user would expect (downgrade resolution)
167            if npts_h>1 and npts_w>1:
168                npts_h = int(math.ceil(math.sqrt(self.npts)))
169                npts_w = npts_h
170               
171            for k in range(npts_h):
172                if npts_h==1:
173                    shift_h = 0
174                else:
175                    shift_h = self.height/(float(npts_h-1.0)) * k
176                for j in range(npts_w):
177                    if npts_w==1:
178                        shift_w = 0
179                    else:
180                        shift_w = self.width/(float(npts_w-1.0)) * j
181                    q_shifted = math.sqrt( ((q-shift_w)*(q-shift_w) + shift_h*shift_h) )
182                    q_i = int(math.floor( (q_shifted-self.min)/((self.max-self.min)/(self.nbins -1.0)) ))
183                   
184                    # Skip the entries outside our I(q) range
185                    #TODO: be careful with edge effect
186                    if q_i<self.nbins:
187                        weights[i][q_i] = weights[i][q_i]+1.0
188
189        self._weights = weights
190        return self._weights
191
192class SlitSmearer(_SlitSmearer):
193    """
194        Adaptor for slit smearing class and SANS data
195    """
196    def __init__(self, data1D):
197        """
198            Assumption: equally spaced bins of increasing q-values.
199           
200            @param data1D: data used to set the smearing parameters
201        """
202        # Initialization from parent class
203        super(SlitSmearer, self).__init__()
204       
205        ## Slit width
206        self.width = 0
207        if data1D.dxw is not None and len(data1D.dxw)==len(data1D.x):
208            self.width = data1D.dxw[0]
209            # Sanity check
210            for value in data1D.dxw:
211                if value != self.width:
212                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
213               
214        ## Slit height
215        self.height = 0
216        if data1D.dxl is not None and len(data1D.dxl)==len(data1D.x):
217            self.height = data1D.dxl[0]
218            # Sanity check
219            for value in data1D.dxl:
220                if value != self.height:
221                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
222       
223        ## Number of Q bins
224        self.nbins = len(data1D.x)
225        ## Minimum Q
226        self.min = data1D.x[0]
227        ## Maximum
228        self.max = data1D.x[len(data1D.x)-1]       
229
230
231class _QSmearer(_BaseSmearer):
232    """
233        Perform Gaussian Q smearing
234    """
235       
236    def __init__(self, nbins=None, width=None, min=None, max=None):
237        """
238            Initialization
239           
240            @param nbins: number of Q bins
241            @param width: array standard deviation in Q [A-1]
242            @param min: Q_min [A-1]
243            @param max: Q_max [A-1]
244        """
245        ## Standard deviation in Q [A-1]
246        self.width  = width
247        ## Q_min (Min Q-value for I(q))
248        self.min    = min
249        ## Q_max (Max Q_value for I(q))
250        self.max    = max
251        ## Number of Q bins
252        self.nbins  = nbins
253        ## Smearing matrix
254        self._weights = None
255       
256    def _compute_matrix(self):
257        """
258            Compute the smearing matrix for the current I(q) array
259        """
260        weights = numpy.zeros([self.nbins, self.nbins])
261       
262        # Loop over all q-values
263        step = (self.max-self.min)/float(self.nbins-1.0)
264        for i in range(self.nbins):
265            q = self.min + i*step
266            q_min = q - 0.5*step
267            q_max = q + 0.5*step
268            for j in range(self.nbins):
269                q_j = self.min + j*step
270               
271                # Compute the fraction of the Gaussian contributing
272                # to the q bin between q_min and q_max
273                #value =  math.exp(-math.pow((q_max-q_j),2)/(2*math.pow(self.width[j],2) ))
274                #value +=  math.exp(-math.pow((q_max-q_j),2)/(2*math.pow(self.width[j],2) ))
275                value =  scipy.special.erf( (q_max-q_j)/(math.sqrt(2.0)*self.width[j]) ) 
276                value -=scipy.special.erf( (q_min-q_j)/(math.sqrt(2.0)*self.width[j]) ) 
277                weights[i][j] += value
278                               
279        self._weights = weights
280        return self._weights
281       
282class QSmearer(_QSmearer):
283    """
284        Adaptor for Gaussian Q smearing class and SANS data
285    """
286    def __init__(self, data1D):
287        """
288            Assumption: equally spaced bins of increasing q-values.
289           
290            @param data1D: data used to set the smearing parameters
291        """
292        # Initialization from parent class
293        super(QSmearer, self).__init__()
294       
295        ## Resolution
296        self.width = numpy.zeros(len(data1D.x))
297        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
298            self.width = data1D.dx
299       
300        ## Number of Q bins
301        self.nbins = len(data1D.x)
302        ## Minimum Q
303        self.min = data1D.x[0]
304        ## Maximum
305        self.max = data1D.x[len(data1D.x)-1]       
306
307
308if __name__ == '__main__':
309    x = 0.001*numpy.arange(1,11)
310    y = 12.0-numpy.arange(1,11)
311    print x
312    #for i in range(10): print i, 0.001 + i*0.008/9.0
313    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
314
315   
316    s = _SlitSmearer(nbins=10, width=0.0, height=0.005, min=0.001, max=0.010)
317    #s = _QSmearer(nbins=10, width=0.001, min=0.001, max=0.010)
318    s._compute_matrix()
319
320    sy = s(y)
321    print sy
322   
323    if True:
324        for i in range(10):
325            print x[i],y[i], sy[i]
326            #print q, ' : ', s.weight(q), s._compute_iq(q)
327            #print q, ' : ', s(q), s._compute_iq(q)
328            #s._compute_iq(q)
329
330
331
332
Note: See TracBrowser for help on using the repository browser.