source: sasview/DataLoader/qsmearing.py @ c405c69

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

corrected some problems

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