source: sasview/DataLoader/qsmearing.py @ ec1c554

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 ec1c554 was 023c8e2, checked in by Gervaise Alina <gervyh@…>, 14 years ago

allow smearing for theory1D too

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