source: sasview/DataLoader/qsmearing.py @ 232c3db

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 232c3db 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
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
[f72333f]15from DataLoader.smearing_2d import Smearer2D
[d00f8ff]16
17def smear_selection(data1D):
18    """
19        Creates the right type of smearer according
[4fe4394]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
[d00f8ff]33    """
[4fe4394]34    # Sanity check. If we are not dealing with a SANS Data1D
35    # object, just return None
[21d2eb0]36    if  data1D.__class__.__name__ != 'Data1D':
[f72333f]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)
[21d2eb0]42   
43    if  not hasattr(data1D, "dx") and not hasattr(data1D, "dxl") and not hasattr(data1D, "dxw"):
[4fe4394]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
[c7ac15e]53            #print "_found_resolution",_found_resolution
54            #print "data1D.dx[0]",data1D.dx[0],data1D.dxl[0]
[4fe4394]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           
[d00f8ff]84
85class _BaseSmearer(object):
86   
87    def __init__(self):
88        self.nbins = 0
89        self._weights = None
[a3f8d58]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
[d00f8ff]104       
105    def _compute_matrix(self): return NotImplemented
106
[5859862]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        """
[65883cf]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           
[5859862]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)
[65883cf]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
[5859862]140               
141        return _first_bin, _last_bin
142
[a3f8d58]143    def __call__(self, iq_in, first_bin=0, last_bin=None):
[d00f8ff]144        """
[a3f8d58]145            Perform smearing
[d00f8ff]146        """
[a3f8d58]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
[d00f8ff]158           
[a3f8d58]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)
[65883cf]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
[a3f8d58]168        return iq_out
[d00f8ff]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        """
[a3f8d58]185        _BaseSmearer.__init__(self)
[d00f8ff]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
[4834cba]197        self.npts   = 1000
[d00f8ff]198        ## Smearing matrix
199        self._weights = None
[65883cf]200        self.qvalues  = None
[d00f8ff]201       
[a3f8d58]202    def _initialize_smearer(self):
[d00f8ff]203        """
[a3f8d58]204            Initialize the C++ smearer object.
205            This method HAS to be called before smearing
[d00f8ff]206        """
[5859862]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)
[a3f8d58]209        self._init_complete = True
[fe2ade9]210
[5859862]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
[d00f8ff]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
[5859862]260        self.min = min(data1D.x)
[d00f8ff]261        ## Maximum
[5859862]262        self.max = max(data1D.x)
263        ## Q-values
264        self.qvalues = data1D.x
265       
[d00f8ff]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
[c0d9981]277            @param width: array standard deviation in Q [A-1]
[d00f8ff]278            @param min: Q_min [A-1]
279            @param max: Q_max [A-1]
280        """
[a3f8d58]281        _BaseSmearer.__init__(self)
[d00f8ff]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
[65883cf]292        self.qvalues  = None
[d00f8ff]293       
[a3f8d58]294    def _initialize_smearer(self):
[d00f8ff]295        """
[a3f8d58]296            Initialize the C++ smearer object.
297            This method HAS to be called before smearing
[d00f8ff]298        """
[5859862]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)
[a3f8d58]301        self._init_complete = True
[d00f8ff]302       
[5859862]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       
[d00f8ff]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       
[c0d9981]335        ## Resolution
[4fe4394]336        self.width = numpy.zeros(len(data1D.x))
[d00f8ff]337        if data1D.dx is not None and len(data1D.dx)==len(data1D.x):
[4fe4394]338            self.width = data1D.dx
[d00f8ff]339       
340        ## Number of Q bins
341        self.nbins = len(data1D.x)
342        ## Minimum Q
[5859862]343        self.min = min(data1D.x)
[d00f8ff]344        ## Maximum
[5859862]345        self.max = max(data1D.x)
346        ## Q-values
347        self.qvalues = data1D.x
[d00f8ff]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):
[fe2ade9]367            print x[i],y[i], sy[i]
[d00f8ff]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.