source: sasview/DataLoader/qsmearing.py @ d902cf0

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

corrected some problems

  • Property mode set to 100644
File size: 11.7 KB
RevLine 
[d00f8ff]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"""
[4fe4394]10
11
[d00f8ff]12import numpy
13import math
14import scipy.special
15
16def smear_selection(data1D):
17    """
18        Creates the right type of smearer according
[4fe4394]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
[d00f8ff]32    """
[4fe4394]33    # Sanity check. If we are not dealing with a SANS Data1D
34    # object, just return None
[21d2eb0]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"):
[4fe4394]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
[c7ac15e]48            #print "_found_resolution",_found_resolution
49            #print "data1D.dx[0]",data1D.dx[0],data1D.dxl[0]
[4fe4394]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
[c7ac15e]73    #print "_found_slit",_found_slit
74    #print "data1D.dx[0]",data1D.dx[0],data1D.dxl[0]       
[4fe4394]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           
[d00f8ff]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
[c7ac15e]108        idwb=[]
109       
[d00f8ff]110        for q_i in range(self.nbins):
111            sum = 0.0
[c7ac15e]112            counts = 0.0 
113
[d00f8ff]114            for i in range(self.nbins):
[c7ac15e]115                if iq[i]==0 or self._weights[q_i][i]==0:
116                    continue
117                else:
[fe2ade9]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]
[0ec0405]121            if counts == 0:
122                iq_smeared[q_i] = 0
123            else:
124                iq_smeared[q_i] = sum/counts
[fe2ade9]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
[d00f8ff]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
[c7ac15e]155        self.npts   = 10000
[d00f8ff]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
[c7ac15e]171            npts_h = self.npts if self.height>0 else 1 
172            npts_w = self.npts if self.width>0 else 1 
[d00f8ff]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
[fe2ade9]199
[d00f8ff]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
[c7ac15e]241        #print "nbin,npts",self.nbins,self.npts
[d00f8ff]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
[c0d9981]253            @param width: array standard deviation in Q [A-1]
[d00f8ff]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
[fe2ade9]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) ))
[4fe4394]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]) ) 
[d00f8ff]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       
[c0d9981]307        ## Resolution
[4fe4394]308        self.width = numpy.zeros(len(data1D.x))
[d00f8ff]309        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
[4fe4394]310            self.width = data1D.dx
[d00f8ff]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):
[fe2ade9]337            print x[i],y[i], sy[i]
[d00f8ff]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.