source: sasview/pr_inversion/invertor.py @ b43a009

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 b43a009 was 2d06beb, checked in by Mathieu Doucet <doucetm@…>, 17 years ago

Use simple least-square fit

  • Property mode set to 100644
File size: 7.8 KB
Line 
1from sans.pr.core.pr_inversion import Cinvertor
2import numpy
3
4class Invertor(Cinvertor):
5   
6    ## Chisqr of the last computation
7    chi2  = 0
8    ## Time elapsed for last computation
9    elapsed = 0
10   
11    def __init__(self):
12        Cinvertor.__init__(self)
13       
14    def __setattr__(self, name, value):
15        """
16            Set the value of an attribute.
17            Access the parent class methods for
18            x, y, err and d_max.
19        """
20        if   name=='x':
21            if 0.0 in value:
22                raise ValueError, "Invertor: one of your q-values is zero. Delete that entry before proceeding"
23            return self.set_x(value)
24        elif name=='y':
25            return self.set_y(value)
26        elif name=='err':
27            return self.set_err(value)
28        elif name=='d_max':
29            return self.set_dmax(value)
30        elif name=='alpha':
31            return self.set_alpha(value)
32           
33        return Cinvertor.__setattr__(self, name, value)
34   
35    def __getattr__(self, name):
36        """
37           Return the value of an attribute
38           For the moment x, y, err and d_max are write-only
39           TODO: change that!
40        """
41        import numpy
42        if   name=='x':
43            out = numpy.ones(self.get_nx())
44            self.get_x(out)
45            return out
46        elif name=='y':
47            out = numpy.ones(self.get_ny())
48            self.get_y(out)
49            return out
50        elif name=='err':
51            out = numpy.ones(self.get_nerr())
52            self.get_err(out)
53            return out
54        elif name=='d_max':
55            return self.get_dmax()
56        elif name=='alpha':
57            return self.get_alpha()
58        elif name in self.__dict__:
59            return self.__dict__[name]
60        return None
61   
62    def clone(self):
63        """
64            Return a clone of this instance
65        """
66        invertor = Invertor()
67        invertor.chi2    = self.chi2
68        invertor.elapsed = self.elapsed
69        invertor.alpha   = self.alpha
70        invertor.d_max   = self.d_max
71       
72        invertor.x = self.x
73        invertor.y = self.y
74        invertor.err = self.err
75       
76        return invertor
77   
78    def invert(self, nfunc=5):
79        """
80            Perform inversion to P(r)
81        """
82        from scipy import optimize
83        import time
84       
85        # First, check that the current data is valid
86        if self.is_valid()<=0:
87            raise RuntimeError, "Invertor.invert: Data array are of different length"
88       
89        p = numpy.ones(nfunc)
90        t_0 = time.time()
91        out, cov_x, info, mesg, success = optimize.leastsq(self.residuals, p, full_output=1, warning=True)
92       
93        # Compute chi^2
94        res = self.residuals(out)
95        chisqr = 0
96        for i in range(len(res)):
97            chisqr += res[i]
98       
99        self.chi2 = chisqr
100
101        # Store computation time
102        self.elapsed = time.time() - t_0
103       
104        return out, cov_x
105   
106    def pr_fit(self, nfunc=5):
107        """
108            Perform inversion to P(r)
109        """
110        from scipy import optimize
111       
112        # First, check that the current data is valid
113        if self.is_valid()<=0:
114            raise RuntimeError, "Invertor.invert: Data arrays are of different length"
115       
116        p = numpy.ones(nfunc)
117        t_0 = time.time()
118        out, cov_x, info, mesg, success = optimize.leastsq(self.pr_residuals, p, full_output=1, warning=True)
119       
120        # Compute chi^2
121        res = self.pr_residuals(out)
122        chisqr = 0
123        for i in range(len(res)):
124            chisqr += res[i]
125       
126        self.chisqr = chisqr
127       
128        # Store computation time
129        self.elapsed = time.time() - t_0
130
131        return out, cov_x
132   
133    def pr_err(self, c, c_cov, r):
134        import math
135        c_err = numpy.zeros(len(c))
136        for i in range(len(c)):
137            try:
138                c_err[i] = math.sqrt(math.fabs(c_cov[i][i]))
139            except:
140                import sys
141                print sys.exc_value
142                print "oups", c_cov[i][i]
143                c_err[i] = c[i]
144
145        return self.get_pr_err(c, c_err, r)
146       
147    def lstsq(self, nfunc=5):
148        import math
149        from scipy.linalg.basic import lstsq
150       
151        # a -- An M x N matrix.
152        # b -- An M x nrhs matrix or M vector.
153        npts = len(self.x)
154        nq   = 20
155        sqrt_alpha = math.sqrt(self.alpha)
156       
157        a = numpy.zeros([npts+nq, nfunc])
158        b = numpy.zeros(npts+nq)
159        err = numpy.zeros(nfunc)
160       
161        for j in range(nfunc):
162            for i in range(npts):
163                a[i][j] = self.basefunc_ft(self.d_max, j+1, self.x[i])/self.err[i]
164            for i_q in range(nq):
165                r = self.d_max/nq*i_q
166                #a[i_q+npts][j] = sqrt_alpha * 1.0/nq*self.d_max*2.0*math.fabs(math.sin(math.pi*(j+1)*r/self.d_max) + math.pi*(j+1)*r/self.d_max * math.cos(math.pi*(j+1)*r/self.d_max))     
167                a[i_q+npts][j] = sqrt_alpha * 1.0/nq*self.d_max*2.0*(2.0*math.pi*(j+1)/self.d_max*math.cos(math.pi*(j+1)*r/self.d_max) + math.pi**2*(j+1)**2*r/self.d_max**2 * math.sin(math.pi*(j+1)*r/self.d_max))     
168       
169        for i in range(npts):
170            b[i] = self.y[i]/self.err[i]
171           
172        c, chi2, rank, n = lstsq(a, b)
173        self.chi2 = chi2
174               
175        at = numpy.transpose(a)
176        inv_cov = numpy.zeros([nfunc,nfunc])
177        for i in range(nfunc):
178            for j in range(nfunc):
179                inv_cov[i][j] = 0.0
180                for k in range(npts):
181                    inv_cov[i][j] = at[i][k]*a[k][j]
182                   
183        # Compute the reg term size for the output
184        sum_sig = 0.0
185        sum_reg = 0.0
186        for j in range(nfunc):
187            for i in range(npts):
188                sum_sig += (a[i][j])**2
189            for i in range(nq):
190                sum_reg += (a[i_q+npts][j])**2
191                   
192        new_alpha = sum_sig/(sum_reg/self.alpha)
193        print "Suggested alpha =", 0.1*new_alpha
194       
195        try:
196            err = math.fabs(chi2/(npts-nfunc))* inv_cov
197        except:
198            print "Error estimating uncertainties"
199           
200       
201        return c, err
202       
203    def svd(self, nfunc=5):
204        import math, time
205        # Ac - b = 0
206       
207        A = numpy.zeros([nfunc, nfunc])
208        y = numpy.zeros(nfunc)
209       
210        t_0 = time.time()
211        for i in range(nfunc):
212            # A
213            for j in range(nfunc):
214                A[i][j] = 0.0
215                for k in range(len(self.x)):
216                    err = self.err[k]
217                    A[i][j] += 1.0/err/err*self.basefunc_ft(self.d_max, j+1, self.x[k]) \
218                            *self.basefunc_ft(self.d_max, i+1, self.x[k]);
219                #print A[i][j]
220                #A[i][j] -= self.alpha*(math.cos(math.pi*(i+j)) - math.cos(math.pi*(i-j)));
221                if i==j:
222                    A[i][j] += -1.0*self.alpha
223                elif i-j==1 or i-j==-1:
224                    A[i][j] += 1.0*self.alpha
225                #print "   ",A[i][j]
226            # y
227            y[i] = 0.0
228            for k in range(len(self.x)):
229                y[i] = self.y[k]/self.err[k]/self.err[k]*self.basefunc_ft(self.d_max, i+1, self.x[k])
230           
231        print time.time()-t_0, 'secs'
232       
233        # use numpy.pinv(A)
234        #inv_A = numpy.linalg.inv(A)
235        #c = y*inv_A
236        print y
237        c = numpy.linalg.solve(A, y)
238       
239       
240        print c
241       
242        err = numpy.zeros(len(c))
243        return c, err
244       
245       
246       
247       
248   
249if __name__ == "__main__":
250    o = Invertor()
251
252   
253   
254   
255   
Note: See TracBrowser for help on using the repository browser.