source: sasview/sansmodels/src/sans/models/smearing_2d.py @ b2d9826

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 b2d9826 was d4bf55e9, checked in by Jae Cho <jhjcho@…>, 14 years ago

Now 2d smearing uses polar symmetry (not rectangular)

  • Property mode set to 100644
File size: 11.7 KB
Line 
1#####################################################################
2#This software was developed by the University of Tennessee as part of the
3#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4#project funded by the US National Science Foundation.
5#See the license text in license.txt
6#copyright 2008, University of Tennessee
7######################################################################
8
9## TODO: Need test,and check Gaussian averaging
10import numpy
11import math
12## Singular point
13SIGMA_ZERO = 1.0e-010
14## Limit of how many sigmas to be covered for the Gaussian smearing
15# default: 2.5 to cover 98.7% of Gaussian
16LIMIT = 3.0
17## Defaults
18R_BIN = {'Xhigh':10.0, 'High':5.0,'Med':5.0,'Low':3.0}
19PHI_BIN ={'Xhigh':20.0,'High':12.0,'Med':6.0,'Low':4.0}   
20
21class Smearer2D:
22    """
23    Gaussian Q smearing class for SANS 2d data
24    """
25     
26    def __init__(self, data=None, model=None, index=None, 
27                 limit=LIMIT, accuracy='Low', coords='polar'):
28        """
29        Assumption: equally spaced bins in dq_r, dq_phi space.
30       
31        :param data: 2d data used to set the smearing parameters
32        :param model: model function
33        :param index: 1d array with len(data) to define the range of the calculation: elements are given as True or False
34        :param nr: number of bins in dq_r-axis
35        :param nphi: number of bins in dq_phi-axis
36        :param coord: coordinates [string], 'polar' or 'cartesian'
37        """
38        ## data
39        self.data = data
40        ## model
41        self.model = model
42        ## Accuracy: Higher stands for more sampling points in both directions of r and phi.
43        self.accuracy = accuracy
44        ## number of bins in r axis for over-sampling
45        self.nr = R_BIN
46        ## number of bins in phi axis for over-sampling
47        self.nphi = PHI_BIN
48        ## maximum nsigmas
49        self.limit = limit
50        self.index = index
51        self.coords = coords
52        self.smearer = True
53       
54       
55    def get_data(self):   
56        """
57        get qx_data, qy_data, dqx_data,dqy_data,and calculate phi_data=arctan(qx_data/qy_data)
58        """
59        if self.data == None or self.data.__class__.__name__ == 'Data1D':
60            return None
61        if self.data.dqx_data == None or self.data.dqy_data == None:
62            return None
63        self.qx_data = self.data.qx_data[self.index]
64        self.qy_data = self.data.qy_data[self.index]
65        self.q_data = self.data.q_data[self.index]
66        # Here dqx and dqy mean dq_parr and dq_perp
67        self.dqx_data = self.data.dqx_data[self.index]
68        self.dqy_data = self.data.dqy_data[self.index]
69        self.phi_data = numpy.arctan(self.qx_data/self.qy_data)
70        ## Remove singular points if exists
71        self.dqx_data[self.dqx_data<SIGMA_ZERO]=SIGMA_ZERO
72        self.dqy_data[self.dqy_data<SIGMA_ZERO]=SIGMA_ZERO
73        return True
74   
75    def set_accuracy(self, accuracy='Low'):   
76        """
77        Set accuracy.
78       
79        :param accuracy:  string
80        """
81        self.accuracy = accuracy
82
83    def set_smearer(self, smearer=True):
84        """
85        Set whether or not smearer will be used
86       
87        :param smearer: smear object
88       
89        """
90        self.smearer = smearer
91       
92    def set_data(self, data=None):   
93        """
94        Set data.
95       
96        :param data: DataLoader.Data_info type
97        """
98        self.data = data
99 
100           
101    def set_model(self, model=None):   
102        """
103        Set model.
104       
105        :param model: sans.models instance
106        """
107        self.model = model 
108           
109    def set_index(self, index=None):   
110        """
111        Set index.
112       
113        :param index: 1d arrays
114        """
115        self.index = index       
116   
117    def get_value(self):
118        """
119        Over sampling of r_nbins times phi_nbins, calculate Gaussian weights,
120        then find smeared intensity
121        For the default values, this is equivalent (but by using numpy array
122        the speed optimized by a factor of ten)to the following: ::
123       
124       
125        Remove the singular points if exists
126        self.dqx_data[self.dqx_data==0]=SIGMA_ZERO
127        self.dqy_data[self.dqy_data==0]=SIGMA_ZERO
128       
129        for phi in range(0,4):
130            for r in range(0,5):
131                n = (phi)*5+(r)
132                r = r+0.25
133                dphi = phi*2.0*math.pi/4.0 + numpy.arctan( \
134                        self.qy_data[index_model]/self.dqy_data[index_model]/ \
135                        self.qx_data[index_model]*/self.dqx_data[index_model])
136                dq = r*sqrt( self.dqx_data[index_model]*\
137                        self.dqx_data[index_model] \
138                    + self.dqy_data[index_model]*self.dqy_data[index_model] )
139                #integrant of exp(-0.5*r*r) r dr at each bins :
140                The integration may not need.
141                weight_res[n] = e^{(-0.5*((r-0.25)*(r-0.25)))}- \
142                                e^{(-0.5*((r-0.25)*(r-0.25)))}
143                #if phi != 0 and r != 0:
144                qx_res = numpy.append(qx_res,self.qx_data[index_model]+ \
145                                                            dq * cos(dphi))
146                qy_res = numpy.append(qy_res,self.qy_data[index_model]+ \
147                                                            dq * sin(dphi))
148                   
149        Then compute I(qx_res,qy_res) and do weighted averaging.
150       
151        """
152        valid = self.get_data()
153        if valid == None:
154            return valid
155        # all zero values of dq
156        if numpy.all(numpy.fabs(self.dqx_data <= 1.1e-10)) and \
157                        numpy.all(numpy.fabs(self.dqy_data <= 1.1e-10)):
158            self.smearer = False
159 
160        if self.smearer == False:
161            return self.model.evalDistribution([self.qx_data, self.qy_data]) 
162
163        nr = self.nr[self.accuracy]
164        nphi = self.nphi[self.accuracy]
165
166        # data length in the range of self.index
167        len_data = len(self.qx_data)
168        len_datay = len(self.qy_data)
169
170        # Number of bins in the dqr direction (polar coordinate of dqx and dqy)
171        bin_size = self.limit / nr
172        # Total number of bins = # of bins
173        # in dq_r-direction times # of bins in dq_phi-direction
174        n_bins = nr * nphi
175        # Mean values of dqr at each bins ,starting from the half of bin size
176        r = bin_size / 2.0 + numpy.arange(nr) * bin_size
177        # mean values of qphi at each bines
178        phi = numpy.arange(nphi)
179        dphi = phi * 2.0 * math.pi / nphi
180        dphi = dphi.repeat(nr)
181
182        ## Transform to polar coordinate,
183        #  and set dphi at each data points ; 1d array
184        dphi = dphi.repeat(len_data)
185        q_phi = self.qy_data / self.qx_data
186       
187        # Starting angle is different between polar and cartesian coordinates.
188        #if self.coords != 'polar':
189        #    dphi += numpy.arctan( q_phi * self.dqx_data/ \
190        #                     self.dqy_data).repeat(n_bins).reshape(len_data,\
191        #                                        n_bins).transpose().flatten()
192
193        # The angle (phi) of the original q point
194        q_phi = numpy.arctan(q_phi).repeat(n_bins).reshape(len_data,\
195                                                n_bins).transpose().flatten()
196        ## Find Gaussian weight for each dq bins: The weight depends only
197        #  on r-direction (The integration may not need)
198        weight_res = numpy.exp(-0.5 * ((r - bin_size / 2.0) * \
199                                    (r - bin_size / 2.0)))- \
200                                    numpy.exp(-0.5 * ((r + bin_size / 2.0 ) *\
201                                    (r + bin_size / 2.0)))
202        weight_res /= numpy.sum(weight_res)
203        weight_res = weight_res.repeat(nphi).reshape(nr, nphi)
204
205        weight_res = weight_res.transpose().flatten()
206       
207        ## Set dr for all dq bins for averaging
208        dr = r.repeat(nphi).reshape(nr,nphi).transpose().flatten()
209        ## Set dqr for all data points
210        dqx = numpy.outer(dr,self.dqx_data).flatten()
211        dqy = numpy.outer(dr,self.dqy_data).flatten()
212
213        qx = self.qx_data.repeat(n_bins).reshape(len_data,\
214                                             n_bins).transpose().flatten()
215        qy = self.qy_data.repeat(n_bins).reshape(len_data,\
216                                             n_bins).transpose().flatten()
217
218        # The polar needs rotation by -q_phi
219        if self.coords == 'polar':
220            qx_res = qx + (dqx*numpy.cos(dphi) * numpy.cos(-q_phi) +\
221                           dqy*numpy.sin(dphi) * numpy.sin(-q_phi))
222            qy_res = qy + (-dqx*numpy.cos(dphi) * numpy.sin(-q_phi) +\
223                           dqy*numpy.sin(dphi) * numpy.cos(-q_phi))
224        else:
225            qx_res = qx +  dqx*numpy.cos(dphi)
226            qy_res = qx +  dqy*numpy.sin(dphi)
227
228        ## Evaluate all points
229        val = self.model.evalDistribution([qx_res, qy_res]) 
230
231        ## Reshape into 2d array to use numpy weighted averaging
232        value_res= val.reshape(n_bins,len(self.qx_data))
233
234        ## Averaging with Gaussian weighting: normalization included.
235        value =numpy.average(value_res,axis=0, weights=weight_res)
236
237        ## Return the smeared values in the range of self.index
238        return value
239   
240if __name__ == '__main__':
241    ## Test w/ 2D linear function
242    x = 0.001*numpy.arange(1,11)
243    dx = numpy.ones(len(x))*0.0003
244    y = 0.001*numpy.arange(1,11)
245    dy = numpy.ones(len(x))*0.001
246    z = numpy.ones(10)
247    dz = numpy.sqrt(z)
248   
249    from DataLoader import Data2D
250    #for i in range(10): print i, 0.001 + i*0.008/9.0
251    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
252    out = Data2D()
253    out.data = z
254    out.qx_data = x
255    out.qy_data = y
256    out.dqx_data = dx
257    out.dqy_data = dy
258    out.q_data = numpy.sqrt(dx * dx + dy * dy)
259    index = numpy.ones(len(x), dtype = bool)
260    out.mask = index
261    from sans.models.LineModel import LineModel
262    model = LineModel()
263    model.setParam("A", 0)
264
265    smear = Smearer2D(out,model,index)
266    #smear.set_accuracy('Xhigh')
267    value = smear.get_value()
268    ## All data are ones, so the smeared should also be ones.
269    print "Data length =",len(value)
270    print " 2D linear function, I = 0 + 1*qy"
271    text = " Gaussian weighted averaging on a 2D linear function will "
272    text += "provides the results same as without the averaging."
273    print text
274    print "qx_data", "qy_data", "I_nonsmear", "I_smeared"
275    for ind in range(len(value)):
276        print x[ind],y[ind],model.evalDistribution([x,y])[ind], value[ind]
277       
278"""
279for i in range(len(qx_res)/(128*128)):
280    k = i * 128*128 +64
281
282    print qx_res[k]-qqx[k], qy_res[k]-qqy[k]
283print qqx[64],qqy[64]
284""" 
285"""   
286if __name__ == '__main__':
287    ## Another Test w/ constant function
288    x = 0.001*numpy.arange(1,11)
289    dx = numpy.ones(len(x))*0.001
290    y = 0.001*numpy.arange(1,11)
291    dy = numpy.ones(len(x))*0.001
292    z = numpy.ones(10)
293    dz = numpy.sqrt(z)
294   
295    from DataLoader import Data2D
296    #for i in range(10): print i, 0.001 + i*0.008/9.0
297    #for i in range(100): print i, int(math.floor( (i/ (100/9.0)) ))
298    out = Data2D()
299    out.data = z
300    out.qx_data = x
301    out.qy_data = y
302    out.dqx_data = dx
303    out.dqy_data = dy
304    index = numpy.ones(len(x), dtype = bool)
305    out.mask = index
306    from sans.models.Constant import Constant
307    model = Constant()
308
309    value = Smearer2D(out,model,index).get_value()
310    ## All data are ones, so the smeared values should also be ones.
311    print "Data length =",len(value), ", Data=",value
312"""   
Note: See TracBrowser for help on using the repository browser.