source: sasview/DataLoader/qsmearing.py @ de1da34

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

fixed a bug in slit smearing

  • Property mode set to 100644
File size: 11.3 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
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           
[d00f8ff]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):
[fe2ade9]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]
[d00f8ff]113            iq_smeared[q_i] = sum/counts
[fe2ade9]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
[d00f8ff]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
[fe2ade9]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
[d00f8ff]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
[fe2ade9]188
[d00f8ff]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
[c0d9981]241            @param width: array standard deviation in Q [A-1]
[d00f8ff]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
[fe2ade9]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) ))
[4fe4394]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]) ) 
[d00f8ff]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       
[c0d9981]295        ## Resolution
[4fe4394]296        self.width = numpy.zeros(len(data1D.x))
[d00f8ff]297        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
[4fe4394]298            self.width = data1D.dx
[d00f8ff]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):
[fe2ade9]325            print x[i],y[i], sy[i]
[d00f8ff]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.