1 | import math |
---|
2 | import pylab, numpy |
---|
3 | |
---|
4 | class PrInverse: |
---|
5 | |
---|
6 | D = 70.0 |
---|
7 | #alpha = 0.0001 |
---|
8 | alpha = 0.0 |
---|
9 | |
---|
10 | data_x = [] |
---|
11 | data_y = [] |
---|
12 | data_err = [] |
---|
13 | |
---|
14 | r = [] |
---|
15 | pr = [] |
---|
16 | pr_err = [] |
---|
17 | |
---|
18 | xmult = [] |
---|
19 | |
---|
20 | c = None |
---|
21 | |
---|
22 | def __init__(self, D=60.0): |
---|
23 | ## Max distance |
---|
24 | self.D = D |
---|
25 | self.xmult = pylab.arange(0.001, self.D, self.D/21.0) |
---|
26 | |
---|
27 | def l_multiplier(self, c): |
---|
28 | return self.alpha * self._lmult2(c) |
---|
29 | |
---|
30 | def _lmult1(self, c): |
---|
31 | sum = 0 |
---|
32 | for i in range(len(c)-1): |
---|
33 | sum += (c[i+1]-c[i])**2 |
---|
34 | return sum |
---|
35 | |
---|
36 | def _lmult2(self, c): |
---|
37 | sum = 0 |
---|
38 | for i in range(len(self.xmult)): |
---|
39 | dp = 0 |
---|
40 | for j in range(len(c)): |
---|
41 | dp += c[j] * self._ortho_derived(j+1, self.xmult[i]) |
---|
42 | sum += (dp**2) |
---|
43 | return sum * self.D/len(self.xmult) |
---|
44 | |
---|
45 | def _ortho_transformed(self, n, q): |
---|
46 | """ |
---|
47 | Fourier transform of the nth orthogonal function |
---|
48 | """ |
---|
49 | return 8.0*math.pi**2/q * self.D * n * (-1)**(n+1) * \ |
---|
50 | math.sin(q*self.D) / ( (math.pi*n)**2 - (q*self.D)**2) |
---|
51 | |
---|
52 | def _ortho_derived(self, n, r): |
---|
53 | |
---|
54 | return 2.0*math.sin(math.pi*n*r/self.D) + 2.0*r*math.cos(math.pi*n*r/self.D) |
---|
55 | |
---|
56 | def iq(self, c, q): |
---|
57 | sum = 0.0 |
---|
58 | N = len(c) |
---|
59 | #str = '' |
---|
60 | for i in range(N): |
---|
61 | # n goes from 1 to N in the formulas |
---|
62 | sum += c[i] * self._ortho_transformed(i+1, q) |
---|
63 | #str += "c%i=%g " % (i, c[i]); |
---|
64 | #print str |
---|
65 | #import time |
---|
66 | #time.sleep(10) |
---|
67 | return sum |
---|
68 | |
---|
69 | def residuals(self, params): |
---|
70 | """ |
---|
71 | Calculates the vector of residuals for each point |
---|
72 | in y for a given set of input parameters. |
---|
73 | @param params: list of parameter values |
---|
74 | @return: vector of residuals |
---|
75 | """ |
---|
76 | residuals = [] |
---|
77 | M = len(self.data_x) |
---|
78 | #lmult = self.l_multiplier(params) |
---|
79 | lmult = 0 |
---|
80 | for j in range(M): |
---|
81 | if self.data_x[j]>0.0: |
---|
82 | #print j |
---|
83 | value = (self.data_y[j] - self.iq(params, self.data_x[j]))**2 / self.data_err[j]**2 |
---|
84 | #print self.data_x[j], value, lmult/float(M) |
---|
85 | value += lmult/float(M) |
---|
86 | residuals.append( value ) |
---|
87 | |
---|
88 | return residuals |
---|
89 | |
---|
90 | def convert_res(self, res): |
---|
91 | v = numpy.asarray(res) |
---|
92 | if not v.flags.contiguous: |
---|
93 | print "not contiguous" |
---|
94 | v = numpy.array(res) |
---|
95 | |
---|
96 | print v |
---|
97 | res = self.c.residuals(v) |
---|
98 | print res |
---|
99 | #return self.c.residuals(v) |
---|
100 | return res |
---|
101 | |
---|
102 | def new_fit(self): |
---|
103 | from sans.pr.invertor import Invertor |
---|
104 | from scipy import optimize |
---|
105 | |
---|
106 | c = Invertor() |
---|
107 | c.set_dmax(self.D) |
---|
108 | c.set_x(self.data_x) |
---|
109 | c.set_y(self.data_y) |
---|
110 | c.set_err(self.data_err) |
---|
111 | |
---|
112 | out, cov_x = c.invert() |
---|
113 | |
---|
114 | return out, cov_x |
---|
115 | |
---|
116 | def new_fit_0(self): |
---|
117 | from sans.pr.core.pr_inversion import Cinvertor |
---|
118 | from scipy import optimize |
---|
119 | |
---|
120 | self.c = Cinvertor() |
---|
121 | self.c.set_dmax(self.D) |
---|
122 | self.c.set_x(self.data_x) |
---|
123 | self.c.set_y(self.data_y) |
---|
124 | self.c.set_err(self.data_err) |
---|
125 | print "Valid", self.c.is_valid() |
---|
126 | M=10 |
---|
127 | p = numpy.ones(M) |
---|
128 | |
---|
129 | p[0] = 10.0 |
---|
130 | |
---|
131 | out, cov_x, info, mesg, success = optimize.leastsq(self.c.residuals, p, full_output=1, warning=True) |
---|
132 | #out, cov_x, info, mesg, success = optimize.leastsq(self.convert_res, p, full_output=1, warning=True) |
---|
133 | |
---|
134 | |
---|
135 | return out, cov_x |
---|
136 | |
---|
137 | def fit(self): |
---|
138 | return self.new_fit() |
---|
139 | |
---|
140 | import numpy |
---|
141 | from scipy import optimize |
---|
142 | |
---|
143 | |
---|
144 | M = len(self.data_x)-3 |
---|
145 | M=3 |
---|
146 | print "Number of functions: ", M |
---|
147 | p = numpy.zeros(M) |
---|
148 | p[0] = 1000.0 |
---|
149 | |
---|
150 | out, cov_x, info, mesg, success = optimize.leastsq(self.residuals, p, full_output=1, warning=True) |
---|
151 | |
---|
152 | |
---|
153 | return out, cov_x |
---|
154 | |
---|
155 | def pr_theory(self, r, R): |
---|
156 | """ |
---|
157 | |
---|
158 | """ |
---|
159 | if r<=2*R: |
---|
160 | return 12.0* ((0.5*r/R)**2) * ((1.0-0.5*r/R)**2) * ( 2.0 + 0.5*r/R ) |
---|
161 | else: |
---|
162 | return 0.0 |
---|
163 | |
---|
164 | |
---|
165 | def residuals_pr(self, params): |
---|
166 | import pylab |
---|
167 | |
---|
168 | residuals = [] |
---|
169 | M = len(self.r) |
---|
170 | |
---|
171 | |
---|
172 | for j in range(M): |
---|
173 | |
---|
174 | if self.r[j]>0: |
---|
175 | err2 = (self.pr_err[j])**2 |
---|
176 | if j>0: |
---|
177 | err2 += 0.25*(self.pr[j-1]-self.pr[j-1])**2 |
---|
178 | value = (self.pr[j]-self.pr_calc(params, self.r[j]))**2/err2 |
---|
179 | residuals.append( value ) |
---|
180 | |
---|
181 | return residuals |
---|
182 | |
---|
183 | def pr_calc(self, c, r): |
---|
184 | sum = 0 |
---|
185 | N = len(c) |
---|
186 | for i in range(N): |
---|
187 | sum += c[i]*2.0*r*math.sin(math.pi*(i+1)*r/self.D) |
---|
188 | |
---|
189 | return sum |
---|
190 | |
---|
191 | def fill_sphere(self, radius=60): |
---|
192 | import pylab |
---|
193 | import numpy |
---|
194 | self.r = pylab.arange(0.0, radius, radius/50.0) |
---|
195 | M = len(self.r) |
---|
196 | self.pr = numpy.zeros(M) |
---|
197 | self.pr_err = numpy.zeros(M) |
---|
198 | |
---|
199 | for j in range(M): |
---|
200 | self.pr[j] = self.pr_theory(self.r[j], radius) |
---|
201 | self.pr_err[j] = math.sqrt(self.pr[j]) |
---|
202 | |
---|
203 | |
---|
204 | def fit_pr(self): |
---|
205 | import numpy |
---|
206 | from scipy import optimize |
---|
207 | |
---|
208 | |
---|
209 | M = len(self.r)-3 |
---|
210 | M=2 |
---|
211 | print "Number of functions: ", M |
---|
212 | p = numpy.ones(M) |
---|
213 | #p = numpy.ones(15) |
---|
214 | |
---|
215 | out, cov_x, info, mesg, success = optimize.leastsq(self.residuals_pr, p, full_output=1, warning=True) |
---|
216 | |
---|
217 | return out, cov_x |
---|
218 | |
---|
219 | |
---|
220 | |
---|
221 | def load(self, path = "sphere_test_data.txt"): |
---|
222 | # Read the data from the data file |
---|
223 | self.data_x = numpy.zeros(0) |
---|
224 | self.data_y = numpy.zeros(0) |
---|
225 | self.data_err = numpy.zeros(0) |
---|
226 | if not path == None: |
---|
227 | input_f = open(path,'r') |
---|
228 | buff = input_f.read() |
---|
229 | lines = buff.split('\n') |
---|
230 | for line in lines: |
---|
231 | try: |
---|
232 | toks = line.split() |
---|
233 | x = float(toks[0]) |
---|
234 | y = float(toks[1]) |
---|
235 | self.data_x = numpy.append(self.data_x, x) |
---|
236 | self.data_y = numpy.append(self.data_y, y) |
---|
237 | self.data_err = numpy.append(self.data_err, math.sqrt(y)+1000.0) |
---|
238 | except: |
---|
239 | print "Error reading line: ", line |
---|
240 | |
---|
241 | print "Lines read:", len(self.data_x) |
---|
242 | |
---|
243 | |
---|
244 | if __name__ == "__main__": |
---|
245 | from sans.pr.core.pr_inversion import Cinvertor |
---|
246 | pr = PrInverse() |
---|
247 | pr.load("sphere_80.txt") |
---|
248 | out, cov = pr.fit() |
---|
249 | |
---|
250 | print "output:" |
---|
251 | print out |
---|
252 | |
---|