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

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 2d409fa was 4834cba, checked in by Jae Cho <jhjcho@…>, 15 years ago

reduced Npts to 1000: 10000 was too large for slit-smearing

  • Property mode set to 100644
File size: 12.2 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 2009, University of Tennessee
9"""
10
11import DataLoader.extensions.smearer as smearer
12import numpy
13import math
14import logging, sys
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    # 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        ## Internal flag to keep track of C++ smearer initialization
86        self._init_complete = False
87        self._smearer = None
88       
89    def __deepcopy__(self, memo={}):
90        """
91            Return a valid copy of self.
92            Avoid copying the _smearer C object and force a matrix recompute
93            when the copy is used. 
94        """
95        result = _BaseSmearer()
96        result.nbins = self.nbins
97        return result
98
99       
100    def _compute_matrix(self): return NotImplemented
101
102    def get_bin_range(self, q_min=None, q_max=None):
103        """
104            @param q_min: minimum q-value to smear
105            @param q_max: maximum q-value to smear
106        """
107        # If this is the first time we call for smearing,
108        # initialize the C++ smearer object first
109        if not self._init_complete:
110            self._initialize_smearer()
111           
112        if q_min == None:
113            q_min = self.min
114       
115        if q_max == None:
116            q_max = self.max
117       
118        _qmin_unsmeared, _qmax_unsmeared = self.get_unsmeared_range(q_min, q_max)
119       
120        _first_bin = None
121        _last_bin  = None
122
123        step = (self.max-self.min)/(self.nbins-1.0)
124        try:
125            for i in range(self.nbins):
126                q_i = smearer.get_q(self._smearer, i)
127                if (q_i >= _qmin_unsmeared) and (q_i <= _qmax_unsmeared):
128                    # Identify first and last bin
129                    if _first_bin is None:
130                        _first_bin = i
131                    else:
132                        _last_bin  = i
133        except:
134            raise RuntimeError, "_BaseSmearer.get_bin_range: error getting range\n  %s" % sys.exc_value
135               
136        return _first_bin, _last_bin
137
138    def __call__(self, iq_in, first_bin=0, last_bin=None):
139        """
140            Perform smearing
141        """
142        # If this is the first time we call for smearing,
143        # initialize the C++ smearer object first
144        if not self._init_complete:
145            self._initialize_smearer()
146             
147        # Get the max value for the last bin
148        if last_bin is None or last_bin>=len(iq_in):
149            last_bin = len(iq_in)-1
150        # Check that the first bin is positive
151        if first_bin<0:
152            first_bin = 0
153           
154        # Sanity check
155        if len(iq_in) != self.nbins:
156            raise RuntimeError, "Invalid I(q) vector: inconsistent array length %d != %s" % (len(iq_in), str(self.nbins))
157             
158        # Storage for smeared I(q)   
159        iq_out = numpy.zeros(self.nbins)
160        smear_output = smearer.smear(self._smearer, iq_in, iq_out, first_bin, last_bin)
161        if smear_output < 0:
162            raise RuntimeError, "_BaseSmearer: could not smear, code = %g" % smear_output
163        return iq_out
164   
165class _SlitSmearer(_BaseSmearer):
166    """
167        Slit smearing for I(q) array
168    """
169   
170    def __init__(self, nbins=None, width=None, height=None, min=None, max=None):
171        """
172            Initialization
173           
174            @param iq: I(q) array [cm-1]
175            @param width: slit width [A-1]
176            @param height: slit height [A-1]
177            @param min: Q_min [A-1]
178            @param max: Q_max [A-1]
179        """
180        _BaseSmearer.__init__(self)
181        ## Slit width in Q units
182        self.width  = width
183        ## Slit height in Q units
184        self.height = height
185        ## Q_min (Min Q-value for I(q))
186        self.min    = min
187        ## Q_max (Max Q_value for I(q))
188        self.max    = max
189        ## Number of Q bins
190        self.nbins  = nbins
191        ## Number of points used in the smearing computation
192        self.npts   = 1000
193        ## Smearing matrix
194        self._weights = None
195        self.qvalues  = None
196       
197    def _initialize_smearer(self):
198        """
199            Initialize the C++ smearer object.
200            This method HAS to be called before smearing
201        """
202        #self._smearer = smearer.new_slit_smearer(self.width, self.height, self.min, self.max, self.nbins)
203        self._smearer = smearer.new_slit_smearer_with_q(self.width, self.height, self.qvalues)
204        self._init_complete = True
205
206    def get_unsmeared_range(self, q_min, q_max):
207        """
208            Determine the range needed in unsmeared-Q to cover
209            the smeared Q range
210        """
211        # Range used for input to smearing
212        _qmin_unsmeared = q_min
213        _qmax_unsmeared = q_max
214        try:
215            _qmin_unsmeared = self.min
216            _qmax_unsmeared = self.max
217        except:
218            logging.error("_SlitSmearer.get_bin_range: %s" % sys.exc_value)
219        return _qmin_unsmeared, _qmax_unsmeared
220
221class SlitSmearer(_SlitSmearer):
222    """
223        Adaptor for slit smearing class and SANS data
224    """
225    def __init__(self, data1D):
226        """
227            Assumption: equally spaced bins of increasing q-values.
228           
229            @param data1D: data used to set the smearing parameters
230        """
231        # Initialization from parent class
232        super(SlitSmearer, self).__init__()
233       
234        ## Slit width
235        self.width = 0
236        if data1D.dxw is not None and len(data1D.dxw)==len(data1D.x):
237            self.width = data1D.dxw[0]
238            # Sanity check
239            for value in data1D.dxw:
240                if value != self.width:
241                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
242               
243        ## Slit height
244        self.height = 0
245        if data1D.dxl is not None and len(data1D.dxl)==len(data1D.x):
246            self.height = data1D.dxl[0]
247            # Sanity check
248            for value in data1D.dxl:
249                if value != self.height:
250                    raise RuntimeError, "Slit smearing parameters must be the same for all data"
251       
252        ## Number of Q bins
253        self.nbins = len(data1D.x)
254        ## Minimum Q
255        self.min = min(data1D.x)
256        ## Maximum
257        self.max = max(data1D.x)
258        ## Q-values
259        self.qvalues = data1D.x
260       
261
262class _QSmearer(_BaseSmearer):
263    """
264        Perform Gaussian Q smearing
265    """
266       
267    def __init__(self, nbins=None, width=None, min=None, max=None):
268        """
269            Initialization
270           
271            @param nbins: number of Q bins
272            @param width: array standard deviation in Q [A-1]
273            @param min: Q_min [A-1]
274            @param max: Q_max [A-1]
275        """
276        _BaseSmearer.__init__(self)
277        ## Standard deviation in Q [A-1]
278        self.width  = width
279        ## Q_min (Min Q-value for I(q))
280        self.min    = min
281        ## Q_max (Max Q_value for I(q))
282        self.max    = max
283        ## Number of Q bins
284        self.nbins  = nbins
285        ## Smearing matrix
286        self._weights = None
287        self.qvalues  = None
288       
289    def _initialize_smearer(self):
290        """
291            Initialize the C++ smearer object.
292            This method HAS to be called before smearing
293        """
294        #self._smearer = smearer.new_q_smearer(numpy.asarray(self.width), self.min, self.max, self.nbins)
295        self._smearer = smearer.new_q_smearer_with_q(numpy.asarray(self.width), self.qvalues)
296        self._init_complete = True
297       
298    def get_unsmeared_range(self, q_min, q_max):
299        """
300            Determine the range needed in unsmeared-Q to cover
301            the smeared Q range
302            Take 3 sigmas as the offset between smeared and unsmeared space
303        """
304        # Range used for input to smearing
305        _qmin_unsmeared = q_min
306        _qmax_unsmeared = q_max
307        try:
308            offset = 3.0*max(self.width)
309            _qmin_unsmeared = max([self.min, q_min-offset])
310            _qmax_unsmeared = min([self.max, q_max+offset])
311        except:
312            logging.error("_QSmearer.get_bin_range: %s" % sys.exc_value)
313        return _qmin_unsmeared, _qmax_unsmeared
314       
315       
316       
317class QSmearer(_QSmearer):
318    """
319        Adaptor for Gaussian Q smearing class and SANS data
320    """
321    def __init__(self, data1D):
322        """
323            Assumption: equally spaced bins of increasing q-values.
324           
325            @param data1D: data used to set the smearing parameters
326        """
327        # Initialization from parent class
328        super(QSmearer, self).__init__()
329       
330        ## Resolution
331        self.width = numpy.zeros(len(data1D.x))
332        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
333            self.width = data1D.dx
334       
335        ## Number of Q bins
336        self.nbins = len(data1D.x)
337        ## Minimum Q
338        self.min = min(data1D.x)
339        ## Maximum
340        self.max = max(data1D.x)
341        ## Q-values
342        self.qvalues = data1D.x
343
344
345if __name__ == '__main__':
346    x = 0.001*numpy.arange(1,11)
347    y = 12.0-numpy.arange(1,11)
348    print x
349    #for i in range(10): print i, 0.001 + i*0.008/9.0
350    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
351
352   
353    s = _SlitSmearer(nbins=10, width=0.0, height=0.005, min=0.001, max=0.010)
354    #s = _QSmearer(nbins=10, width=0.001, min=0.001, max=0.010)
355    s._compute_matrix()
356
357    sy = s(y)
358    print sy
359   
360    if True:
361        for i in range(10):
362            print x[i],y[i], sy[i]
363            #print q, ' : ', s.weight(q), s._compute_iq(q)
364            #print q, ' : ', s(q), s._compute_iq(q)
365            #s._compute_iq(q)
366
367
368
369
Note: See TracBrowser for help on using the repository browser.