source: sasview/DataLoader/qsmearing.py @ 690003a

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 690003a was 65883cf, checked in by Mathieu Doucet <doucetm@…>, 15 years ago

dataloader: fixed get_bin_range method for smearer objects

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