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
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
[a3f8d58]8copyright 2009, University of Tennessee
[d00f8ff]9"""
[4fe4394]10
[a3f8d58]11import DataLoader.extensions.smearer as smearer
[d00f8ff]12import numpy
13import math
[5859862]14import logging, sys
[d00f8ff]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
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           
[d00f8ff]79
80class _BaseSmearer(object):
81   
82    def __init__(self):
83        self.nbins = 0
84        self._weights = None
[a3f8d58]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
[d00f8ff]99       
100    def _compute_matrix(self): return NotImplemented
101
[5859862]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        """
[65883cf]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           
[5859862]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)
[65883cf]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
[5859862]135               
136        return _first_bin, _last_bin
137
[a3f8d58]138    def __call__(self, iq_in, first_bin=0, last_bin=None):
[d00f8ff]139        """
[a3f8d58]140            Perform smearing
[d00f8ff]141        """
[a3f8d58]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
[d00f8ff]153           
[a3f8d58]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)
[65883cf]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
[a3f8d58]163        return iq_out
[d00f8ff]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        """
[a3f8d58]180        _BaseSmearer.__init__(self)
[d00f8ff]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
[4834cba]192        self.npts   = 1000
[d00f8ff]193        ## Smearing matrix
194        self._weights = None
[65883cf]195        self.qvalues  = None
[d00f8ff]196       
[a3f8d58]197    def _initialize_smearer(self):
[d00f8ff]198        """
[a3f8d58]199            Initialize the C++ smearer object.
200            This method HAS to be called before smearing
[d00f8ff]201        """
[5859862]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)
[a3f8d58]204        self._init_complete = True
[fe2ade9]205
[5859862]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
[d00f8ff]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
[5859862]255        self.min = min(data1D.x)
[d00f8ff]256        ## Maximum
[5859862]257        self.max = max(data1D.x)
258        ## Q-values
259        self.qvalues = data1D.x
260       
[d00f8ff]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
[c0d9981]272            @param width: array standard deviation in Q [A-1]
[d00f8ff]273            @param min: Q_min [A-1]
274            @param max: Q_max [A-1]
275        """
[a3f8d58]276        _BaseSmearer.__init__(self)
[d00f8ff]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
[65883cf]287        self.qvalues  = None
[d00f8ff]288       
[a3f8d58]289    def _initialize_smearer(self):
[d00f8ff]290        """
[a3f8d58]291            Initialize the C++ smearer object.
292            This method HAS to be called before smearing
[d00f8ff]293        """
[5859862]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)
[a3f8d58]296        self._init_complete = True
[d00f8ff]297       
[5859862]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       
[d00f8ff]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       
[c0d9981]330        ## Resolution
[4fe4394]331        self.width = numpy.zeros(len(data1D.x))
[d00f8ff]332        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
[4fe4394]333            self.width = data1D.dx
[d00f8ff]334       
335        ## Number of Q bins
336        self.nbins = len(data1D.x)
337        ## Minimum Q
[5859862]338        self.min = min(data1D.x)
[d00f8ff]339        ## Maximum
[5859862]340        self.max = max(data1D.x)
341        ## Q-values
342        self.qvalues = data1D.x
[d00f8ff]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):
[fe2ade9]362            print x[i],y[i], sy[i]
[d00f8ff]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.