source: sasview/DataLoader/qsmearing.py @ 21d2eb0

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

FIxed the conditional selection of q smearer that was not properly working

  • Property mode set to 100644
File size: 11.5 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
194        self._weights = weights
195        return self._weights
196
197class SlitSmearer(_SlitSmearer):
198    """
199        Adaptor for slit smearing class and SANS data
200    """
201    def __init__(self, data1D):
202        """
203            Assumption: equally spaced bins of increasing q-values.
204           
205            @param data1D: data used to set the smearing parameters
206        """
207        # Initialization from parent class
208        super(SlitSmearer, self).__init__()
209       
210        ## Slit width
211        self.width = 0
212        if data1D.dxw is not None and len(data1D.dxw)==len(data1D.x):
213            self.width = data1D.dxw[0]
214            # Sanity check
215            for value in data1D.dxw:
216                if value != self.width:
217                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
218               
219        ## Slit height
220        self.height = 0
221        if data1D.dxl is not None and len(data1D.dxl)==len(data1D.x):
222            self.height = data1D.dxl[0]
223            # Sanity check
224            for value in data1D.dxl:
225                if value != self.height:
226                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
227       
228        ## Number of Q bins
229        self.nbins = len(data1D.x)
230        ## Minimum Q
231        self.min = data1D.x[0]
232        ## Maximum
233        self.max = data1D.x[len(data1D.x)-1]       
234
235
236class _QSmearer(_BaseSmearer):
237    """
238        Perform Gaussian Q smearing
239    """
240       
241    def __init__(self, nbins=None, width=None, min=None, max=None):
242        """
243            Initialization
244           
245            @param nbins: number of Q bins
246            @param width: array standard deviation in Q [A-1]
247            @param min: Q_min [A-1]
248            @param max: Q_max [A-1]
249        """
250        ## Standard deviation in Q [A-1]
251        self.width  = width
252        ## Q_min (Min Q-value for I(q))
253        self.min    = min
254        ## Q_max (Max Q_value for I(q))
255        self.max    = max
256        ## Number of Q bins
257        self.nbins  = nbins
258        ## Smearing matrix
259        self._weights = None
260       
261    def _compute_matrix(self):
262        """
263            Compute the smearing matrix for the current I(q) array
264        """
265        weights = numpy.zeros([self.nbins, self.nbins])
266       
267        # Loop over all q-values
268        step = (self.max-self.min)/float(self.nbins-1.0)
269        for i in range(self.nbins):
270            q = self.min + i*step
271            q_min = q - 0.5*step
272            q_max = q + 0.5*step
273            for j in range(self.nbins):
274                q_j = self.min + j*step
275               
276                # Compute the fraction of the Gaussian contributing
277                # to the q bin between q_min and q_max
278                #value =  math.exp(-math.pow((q_max-q_j),2)/(2*math.pow(self.width[j],2) ))
279                #value +=  math.exp(-math.pow((q_max-q_j),2)/(2*math.pow(self.width[j],2) ))
280                value =  scipy.special.erf( (q_max-q_j)/(math.sqrt(2.0)*self.width[j]) ) 
281                value -=scipy.special.erf( (q_min-q_j)/(math.sqrt(2.0)*self.width[j]) ) 
282                weights[i][j] += value
283                               
284        self._weights = weights
285        return self._weights
286       
287class QSmearer(_QSmearer):
288    """
289        Adaptor for Gaussian Q smearing class and SANS data
290    """
291    def __init__(self, data1D):
292        """
293            Assumption: equally spaced bins of increasing q-values.
294           
295            @param data1D: data used to set the smearing parameters
296        """
297        # Initialization from parent class
298        super(QSmearer, self).__init__()
299       
300        ## Resolution
301        self.width = numpy.zeros(len(data1D.x))
302        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
303            self.width = data1D.dx
304       
305        ## Number of Q bins
306        self.nbins = len(data1D.x)
307        ## Minimum Q
308        self.min = data1D.x[0]
309        ## Maximum
310        self.max = data1D.x[len(data1D.x)-1]       
311
312
313if __name__ == '__main__':
314    x = 0.001*numpy.arange(1,11)
315    y = 12.0-numpy.arange(1,11)
316    print x
317    #for i in range(10): print i, 0.001 + i*0.008/9.0
318    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
319
320   
321    s = _SlitSmearer(nbins=10, width=0.0, height=0.005, min=0.001, max=0.010)
322    #s = _QSmearer(nbins=10, width=0.001, min=0.001, max=0.010)
323    s._compute_matrix()
324
325    sy = s(y)
326    print sy
327   
328    if True:
329        for i in range(10):
330            print x[i],y[i], sy[i]
331            #print q, ' : ', s.weight(q), s._compute_iq(q)
332            #print q, ' : ', s(q), s._compute_iq(q)
333            #s._compute_iq(q)
334
335
336
337
Note: See TracBrowser for help on using the repository browser.