source: sasview/DataLoader/qsmearing.py @ f83b94a

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 f83b94a was f72333f, checked in by Jae Cho <jhjcho@…>, 15 years ago

Plugged in 2D smear: traditional over-sampling method

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