source: sasview/DataLoader/qsmearing.py @ 2dbb681

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 2dbb681 was 4fe4394, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

implemented smearer selection

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