source: sasview/DataLoader/qsmearing.py @ 53ddcdb

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 53ddcdb was a7a5886, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working pylint

  • Property mode set to 100644
File size: 12.9 KB
RevLine 
[d00f8ff]1
[0997158f]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######################################################################
[d00f8ff]9import numpy
[a7a5886]10#import math
11import logging
12import sys
13import DataLoader.extensions.smearer as smearer
[f72333f]14from DataLoader.smearing_2d import Smearer2D
[d00f8ff]15
16def smear_selection(data1D):
17    """
[0997158f]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.
[4fe4394]24   
[0997158f]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
[023c8e2]35    if  data1D.__class__.__name__ not in ['Data1D', 'Theory1D']:
[f72333f]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)
[21d2eb0]41   
[a7a5886]42    if  not hasattr(data1D, "dx") and not hasattr(data1D, "dxl")\
43         and not hasattr(data1D, "dxw"):
[4fe4394]44        return None
45   
46    # Look for resolution smearing data
47    _found_resolution = False
[a7a5886]48    if data1D.dx is not None and len(data1D.dx) == len(data1D.x):
[4fe4394]49       
50        # Check that we have non-zero data
[a7a5886]51        if data1D.dx[0] > 0.0:
[4fe4394]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
[a7a5886]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):
[4fe4394]63       
64        # Check that we have non-zero data
[a7a5886]65        if data1D.dxl[0] > 0.0 or data1D.dxw[0] > 0.0:
[4fe4394]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    return None
82           
[d00f8ff]83
84class _BaseSmearer(object):
85   
86    def __init__(self):
87        self.nbins = 0
88        self._weights = None
[a3f8d58]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        """
[0997158f]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. 
[a3f8d58]98        """
99        result = _BaseSmearer()
100        result.nbins = self.nbins
101        return result
102
[a7a5886]103    def _compute_matrix(self):
104        """
105        """
106        return NotImplemented
[d00f8ff]107
[5859862]108    def get_bin_range(self, q_min=None, q_max=None):
109        """
[0997158f]110       
111        :param q_min: minimum q-value to smear
112        :param q_max: maximum q-value to smear
113         
[5859862]114        """
[65883cf]115        # If this is the first time we call for smearing,
116        # initialize the C++ smearer object first
117        if not self._init_complete:
118            self._initialize_smearer()
[5859862]119        if q_min == None:
120            q_min = self.min
121        if q_max == None:
122            q_max = self.max
[a7a5886]123        _qmin_unsmeared, _qmax_unsmeared = self.get_unsmeared_range(q_min,
124                                                                     q_max)
[5859862]125        _first_bin = None
126        _last_bin  = None
127
[a7a5886]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:
[a7a5886]139            msg = "_BaseSmearer.get_bin_range: "
140            msg += " error getting range\n  %s" % sys.exc_value
141            raise RuntimeError, msg
[5859862]142               
143        return _first_bin, _last_bin
144
[a3f8d58]145    def __call__(self, iq_in, first_bin=0, last_bin=None):
[d00f8ff]146        """
[0997158f]147        Perform smearing
[d00f8ff]148        """
[a3f8d58]149        # If this is the first time we call for smearing,
150        # initialize the C++ smearer object first
151        if not self._init_complete:
152            self._initialize_smearer()
153             
154        # Get the max value for the last bin
[a7a5886]155        if last_bin is None or last_bin >= len(iq_in):
156            last_bin = len(iq_in) - 1
[a3f8d58]157        # Check that the first bin is positive
[a7a5886]158        if first_bin < 0:
[a3f8d58]159            first_bin = 0
[d00f8ff]160           
[a3f8d58]161        # Sanity check
162        if len(iq_in) != self.nbins:
[a7a5886]163            msg = "Invalid I(q) vector: inconsistent array "
164            msg += " length %d != %s" % (len(iq_in), str(self.nbins))
165            raise RuntimeError, msg
[a3f8d58]166             
167        # Storage for smeared I(q)   
168        iq_out = numpy.zeros(self.nbins)
[a7a5886]169        smear_output = smearer.smear(self._smearer, iq_in, iq_out,
170                                      first_bin, last_bin)
[65883cf]171        if smear_output < 0:
[a7a5886]172            msg = "_BaseSmearer: could not smear, code = %g" % smear_output
173            raise RuntimeError, msg
[a3f8d58]174        return iq_out
[d00f8ff]175   
[a7a5886]176    def _initialize_smearer(self):
177        """
178        """
179        return NotImplemented
180   
[d00f8ff]181class _SlitSmearer(_BaseSmearer):
182    """
[0997158f]183    Slit smearing for I(q) array
[d00f8ff]184    """
185   
186    def __init__(self, nbins=None, width=None, height=None, min=None, max=None):
187        """
[0997158f]188        Initialization
[d00f8ff]189           
[0997158f]190        :param iq: I(q) array [cm-1]
191        :param width: slit width [A-1]
192        :param height: slit height [A-1]
193        :param min: Q_min [A-1]
194        :param max: Q_max [A-1]
195       
[d00f8ff]196        """
[a3f8d58]197        _BaseSmearer.__init__(self)
[d00f8ff]198        ## Slit width in Q units
199        self.width  = width
200        ## Slit height in Q units
201        self.height = height
202        ## Q_min (Min Q-value for I(q))
203        self.min    = min
204        ## Q_max (Max Q_value for I(q))
205        self.max    = max
206        ## Number of Q bins
207        self.nbins  = nbins
208        ## Number of points used in the smearing computation
[4834cba]209        self.npts   = 1000
[d00f8ff]210        ## Smearing matrix
211        self._weights = None
[65883cf]212        self.qvalues  = None
[d00f8ff]213       
[a3f8d58]214    def _initialize_smearer(self):
[d00f8ff]215        """
[0997158f]216        Initialize the C++ smearer object.
217        This method HAS to be called before smearing
[d00f8ff]218        """
[a7a5886]219        #self._smearer = smearer.new_slit_smearer(self.width,
220        # self.height, self.min, self.max, self.nbins)
221        self._smearer = smearer.new_slit_smearer_with_q(self.width, 
222                                                    self.height, self.qvalues)
[a3f8d58]223        self._init_complete = True
[fe2ade9]224
[5859862]225    def get_unsmeared_range(self, q_min, q_max):
226        """
[0997158f]227        Determine the range needed in unsmeared-Q to cover
228        the smeared Q range
[5859862]229        """
230        # Range used for input to smearing
231        _qmin_unsmeared = q_min
232        _qmax_unsmeared = q_max
233        try:
234            _qmin_unsmeared = self.min
235            _qmax_unsmeared = self.max
236        except:
237            logging.error("_SlitSmearer.get_bin_range: %s" % sys.exc_value)
238        return _qmin_unsmeared, _qmax_unsmeared
[d00f8ff]239
240class SlitSmearer(_SlitSmearer):
241    """
[0997158f]242    Adaptor for slit smearing class and SANS data
[d00f8ff]243    """
244    def __init__(self, data1D):
245        """
[0997158f]246        Assumption: equally spaced bins of increasing q-values.
247       
248        :param data1D: data used to set the smearing parameters
[d00f8ff]249        """
250        # Initialization from parent class
251        super(SlitSmearer, self).__init__()
252       
253        ## Slit width
254        self.width = 0
[a7a5886]255        if data1D.dxw is not None and len(data1D.dxw) == len(data1D.x):
[d00f8ff]256            self.width = data1D.dxw[0]
257            # Sanity check
258            for value in data1D.dxw:
259                if value != self.width:
[a7a5886]260                    msg = "Slit smearing parameters must "
261                    msg += " be the same for all data"
262                    raise RuntimeError, msg
[d00f8ff]263        ## Slit height
264        self.height = 0
[a7a5886]265        if data1D.dxl is not None and len(data1D.dxl) == len(data1D.x):
[d00f8ff]266            self.height = data1D.dxl[0]
267            # Sanity check
268            for value in data1D.dxl:
269                if value != self.height:
[a7a5886]270                    msg = "Slit smearing parameters must be"
271                    msg += " the same for all data"
272                    raise RuntimeError, msg
[d00f8ff]273       
274        ## Number of Q bins
275        self.nbins = len(data1D.x)
276        ## Minimum Q
[5859862]277        self.min = min(data1D.x)
[d00f8ff]278        ## Maximum
[5859862]279        self.max = max(data1D.x)
280        ## Q-values
281        self.qvalues = data1D.x
282       
[d00f8ff]283
284class _QSmearer(_BaseSmearer):
285    """
[0997158f]286    Perform Gaussian Q smearing
[d00f8ff]287    """
288       
289    def __init__(self, nbins=None, width=None, min=None, max=None):
290        """
[0997158f]291        Initialization
292       
293        :param nbins: number of Q bins
294        :param width: array standard deviation in Q [A-1]
295        :param min: Q_min [A-1]
296        :param max: Q_max [A-1]
[d00f8ff]297        """
[a3f8d58]298        _BaseSmearer.__init__(self)
[d00f8ff]299        ## Standard deviation in Q [A-1]
[a7a5886]300        self.width = width
[d00f8ff]301        ## Q_min (Min Q-value for I(q))
[a7a5886]302        self.min = min
[d00f8ff]303        ## Q_max (Max Q_value for I(q))
[a7a5886]304        self.max = max
[d00f8ff]305        ## Number of Q bins
[a7a5886]306        self.nbins = nbins
[d00f8ff]307        ## Smearing matrix
308        self._weights = None
[65883cf]309        self.qvalues  = None
[d00f8ff]310       
[a3f8d58]311    def _initialize_smearer(self):
[d00f8ff]312        """
[0997158f]313        Initialize the C++ smearer object.
314        This method HAS to be called before smearing
[d00f8ff]315        """
[a7a5886]316        #self._smearer = smearer.new_q_smearer(numpy.asarray(self.width),
317        # self.min, self.max, self.nbins)
318        self._smearer = smearer.new_q_smearer_with_q(numpy.asarray(self.width),
319                                                      self.qvalues)
[a3f8d58]320        self._init_complete = True
[d00f8ff]321       
[5859862]322    def get_unsmeared_range(self, q_min, q_max):
323        """
[0997158f]324        Determine the range needed in unsmeared-Q to cover
325        the smeared Q range
326        Take 3 sigmas as the offset between smeared and unsmeared space
[5859862]327        """
328        # Range used for input to smearing
329        _qmin_unsmeared = q_min
330        _qmax_unsmeared = q_max
331        try:
[a7a5886]332            offset = 3.0 * max(self.width)
333            _qmin_unsmeared = max([self.min, q_min - offset])
334            _qmax_unsmeared = min([self.max, q_max + offset])
[5859862]335        except:
336            logging.error("_QSmearer.get_bin_range: %s" % sys.exc_value)
337        return _qmin_unsmeared, _qmax_unsmeared
338       
[0997158f]339   
[d00f8ff]340class QSmearer(_QSmearer):
341    """
[0997158f]342    Adaptor for Gaussian Q smearing class and SANS data
[d00f8ff]343    """
344    def __init__(self, data1D):
345        """
[0997158f]346        Assumption: equally spaced bins of increasing q-values.
347       
348        :param data1D: data used to set the smearing parameters
[d00f8ff]349        """
350        # Initialization from parent class
351        super(QSmearer, self).__init__()
352       
[c0d9981]353        ## Resolution
[4fe4394]354        self.width = numpy.zeros(len(data1D.x))
[a7a5886]355        if data1D.dx is not None and len(data1D.dx) == len(data1D.x):
[4fe4394]356            self.width = data1D.dx
[d00f8ff]357       
358        ## Number of Q bins
359        self.nbins = len(data1D.x)
360        ## Minimum Q
[5859862]361        self.min = min(data1D.x)
[d00f8ff]362        ## Maximum
[5859862]363        self.max = max(data1D.x)
364        ## Q-values
365        self.qvalues = data1D.x
[d00f8ff]366
367
368if __name__ == '__main__':
[a7a5886]369    x = 0.001 * numpy.arange(1, 11)
370    y = 12.0 - numpy.arange(1, 11)
[d00f8ff]371    print x
372    #for i in range(10): print i, 0.001 + i*0.008/9.0
373    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
374    s = _SlitSmearer(nbins=10, width=0.0, height=0.005, min=0.001, max=0.010)
375    #s = _QSmearer(nbins=10, width=0.001, min=0.001, max=0.010)
376    s._compute_matrix()
377
378    sy = s(y)
379    print sy
380   
381    if True:
382        for i in range(10):
[a7a5886]383            print x[i], y[i], sy[i]
[d00f8ff]384            #print q, ' : ', s.weight(q), s._compute_iq(q)
385            #print q, ' : ', s(q), s._compute_iq(q)
386            #s._compute_iq(q)
387
388
389
390
Note: See TracBrowser for help on using the repository browser.