Revisão | 87b2db1ac449e67ede14031d16585d6d8ab11659 (tree) |
---|---|
Hora | 2012-10-12 07:31:32 |
Autor | Lorenzo Isella <lorenzo.isella@gmai...> |
Commiter | Lorenzo Isella |
A code to compare analytical and numerical calculation of the projected area of a linear chain with k monomers.
@@ -0,0 +1,321 @@ | ||
1 | +#!/usr/bin/env python | |
2 | +import scipy as s | |
3 | +# import pylab as p | |
4 | +import numpy as n | |
5 | +import sys | |
6 | +import string | |
7 | +import scipy.linalg as sl | |
8 | + | |
9 | + | |
10 | +def generate_chain(k,radius): | |
11 | + | |
12 | + my_mat=s.zeros(3*k).reshape((k,3)) | |
13 | + mon_pos=s.arange(k)*radius*2. | |
14 | + my_mat[:,0]=mon_pos | |
15 | + return my_mat | |
16 | + | |
17 | + | |
18 | +def analytical_area(cluster_pro, R): | |
19 | + d=s.sqrt((cluster_pro[0,0]-cluster_pro[1,0])**2.+\ | |
20 | + (cluster_pro[0,1]-cluster_pro[1,1])**2.) | |
21 | + | |
22 | + # print "d is, ", d | |
23 | + | |
24 | + intersection=2.*R**2.*s.arccos(d/(2.*R))-0.5*d*s.sqrt(4.*R**2-d**2.) | |
25 | + | |
26 | + res=2.*s.pi*R**2-intersection | |
27 | + | |
28 | + return res | |
29 | + | |
30 | + | |
31 | + | |
32 | +def analytical_area_chain(cluster_pro, R,k): | |
33 | + d=s.sqrt((cluster_pro[0,0]-cluster_pro[1,0])**2.+\ | |
34 | + (cluster_pro[0,1]-cluster_pro[1,1])**2.) | |
35 | + | |
36 | + # print "d is, ", d | |
37 | + | |
38 | + intersection=2.*R**2.*s.arccos(d/(2.*R))-0.5*d*s.sqrt(4.*R**2-d**2.) | |
39 | + | |
40 | + res=k*s.pi*R**2-(k-1)*intersection | |
41 | + | |
42 | + return res | |
43 | + | |
44 | + | |
45 | + | |
46 | + | |
47 | +def montecarlo_calc_rect(N,cluster, radius): | |
48 | + | |
49 | + rect=build_rect(cluster, radius) | |
50 | + | |
51 | + print "rect is, ", rect | |
52 | + | |
53 | + counter=0 | |
54 | + for i in xrange(N): | |
55 | + pt=random_in_rect(rect) | |
56 | + counter=counter+accept_reject_point(pt, cluster, radius) | |
57 | + | |
58 | + area=rect[2,0]*rect[2,1] | |
59 | + projected_area=area*counter/N | |
60 | + # print "the projected area is, ", projected_area | |
61 | + return projected_area | |
62 | + | |
63 | + | |
64 | + | |
65 | +def build_rect(cluster, rmon): | |
66 | + extreme_left_x=min(cluster[:,0])-rmon | |
67 | + extreme_right_x=max(cluster[:,0])+rmon | |
68 | + | |
69 | + extreme_lower_y=min(cluster[:,1])-rmon | |
70 | + extreme_upper_y=max(cluster[:,1])+rmon | |
71 | + | |
72 | + Lx=abs(extreme_right_x-extreme_left_x) | |
73 | + Ly=abs(extreme_upper_y-extreme_lower_y) | |
74 | + | |
75 | + res=s.array([[extreme_left_x, extreme_right_x],\ | |
76 | + [extreme_lower_y, extreme_upper_y],\ | |
77 | + [Lx,Ly]]) | |
78 | + return res | |
79 | + | |
80 | + | |
81 | + | |
82 | + | |
83 | +def random_in_rect(rect): | |
84 | + | |
85 | + x=s.random.uniform(rect[0,0],rect[0,1],1)[0] | |
86 | + y=s.random.uniform(rect[1,0],rect[1,1],1)[0] | |
87 | + res=s.array([[x, y]]) | |
88 | + # res=s.vstack((x,y)) | |
89 | + return(res) | |
90 | + | |
91 | + | |
92 | + | |
93 | + | |
94 | +def accept_reject_point(pt, cluster, radius): | |
95 | + distmin=min(s.ravel(euclidean_distances(pt,cluster))) | |
96 | + res=distmin<=radius | |
97 | + return (res) | |
98 | + | |
99 | + | |
100 | + | |
101 | +def rotate_cluster(cluster): | |
102 | + random_rot_mat= random_rot() | |
103 | + n_row_col=s.shape(cluster) | |
104 | + | |
105 | + cluster_rot=s.zeros(s.prod(n_row_col)).reshape((n_row_col[0],\ | |
106 | + n_row_col[1])) | |
107 | + | |
108 | + for i in s.arange(n_row_col[0]): | |
109 | + | |
110 | + cluster_rot[i,:]=s.dot(random_rot_mat, cluster[i,:]) | |
111 | + | |
112 | + return cluster_rot | |
113 | + | |
114 | + | |
115 | +def random_rot(): | |
116 | + theta=s.arccos(1.-2.*s.random.uniform(0.,1.,1)[0])-s.pi/2. | |
117 | + phi=s.random.uniform(-s.pi,s.pi,1)[0] | |
118 | + psi=s.random.uniform(-s.pi,s.pi,1)[0] | |
119 | + | |
120 | + | |
121 | + oneone=s.cos(theta)*s.cos(psi) | |
122 | + onetwo=-s.cos(phi)*s.sin(psi)+s.sin(phi)*s.sin(theta)*s.cos(psi) | |
123 | + onethree=s.sin(phi)*s.sin(psi)+s.cos(phi)*s.sin(theta)*s.cos(psi) | |
124 | + | |
125 | + twoone= s.cos(theta)*s.sin(psi) | |
126 | + twotwo=s.cos(phi)*s.cos(psi)+s.sin(phi)*s.sin(theta)*s.sin(psi) | |
127 | + twothree=-s.sin(phi)*s.cos(psi)+s.cos(phi)*s.sin(theta)*s.sin(psi) | |
128 | + | |
129 | + threeone=-s.sin(theta) | |
130 | + threetwo=s.sin(phi)*s.cos(theta) | |
131 | + threethree=s.cos(phi)*s.cos(theta) | |
132 | + | |
133 | + | |
134 | + my_mat=s.zeros(9).reshape((3,3)) | |
135 | + | |
136 | + my_mat[0,0]=oneone | |
137 | + my_mat[0,1]=onetwo | |
138 | + my_mat[0,2]=onethree | |
139 | + | |
140 | + my_mat[1,0]=twoone | |
141 | + my_mat[1,1]=twotwo | |
142 | + my_mat[1,2]=twothree | |
143 | + | |
144 | + my_mat[2,0]=threeone | |
145 | + my_mat[2,1]=threetwo | |
146 | + my_mat[2,2]=threethree | |
147 | + | |
148 | + return my_mat | |
149 | + | |
150 | + | |
151 | + | |
152 | + | |
153 | + | |
154 | + | |
155 | +def euclidean_distances(X, Y, Y_norm_squared=None, squared=False): | |
156 | + """ | |
157 | +Considering the rows of X (and Y=X) as vectors, compute the | |
158 | +distance matrix between each pair of vectors. | |
159 | + | |
160 | +Parameters | |
161 | +---------- | |
162 | +X: array of shape (n_samples_1, n_features) | |
163 | + | |
164 | +Y: array of shape (n_samples_2, n_features) | |
165 | + | |
166 | +Y_norm_squared: array [n_samples_2], optional | |
167 | +pre-computed (Y**2).sum(axis=1) | |
168 | + | |
169 | +squared: boolean, optional | |
170 | +This routine will return squared Euclidean distances instead. | |
171 | + | |
172 | +Returns | |
173 | +------- | |
174 | +distances: array of shape (n_samples_1, n_samples_2) | |
175 | + | |
176 | +Examples | |
177 | +-------- | |
178 | +>>> from scikits.learn.metrics.pairwise import euclidean_distances | |
179 | +>>> X = [[0, 1], [1, 1]] | |
180 | +>>> # distrance between rows of X | |
181 | +>>> euclidean_distances(X, X) | |
182 | +array([[ 0., 1.], | |
183 | +[ 1., 0.]]) | |
184 | +>>> # get distance to origin | |
185 | +>>> euclidean_distances(X, [[0, 0]]) | |
186 | +array([[ 1. ], | |
187 | +[ 1.41421356]]) | |
188 | +""" | |
189 | + # should not need X_norm_squared because if you could precompute that as | |
190 | + # well as Y, then you should just pre-compute the output and not even | |
191 | + # call this function. | |
192 | + if X is Y: | |
193 | + X = Y = n.asanyarray(X) | |
194 | + else: | |
195 | + X = n.asanyarray(X) | |
196 | + Y = n.asanyarray(Y) | |
197 | + | |
198 | + if X.shape[1] != Y.shape[1]: | |
199 | + raise ValueError("Incompatible dimension for X and Y matrices") | |
200 | + | |
201 | + XX = n.sum(X * X, axis=1)[:, n.newaxis] | |
202 | + if X is Y: # shortcut in the common case euclidean_distances(X, X) | |
203 | + YY = XX.T | |
204 | + elif Y_norm_squared is None: | |
205 | + YY = Y.copy() | |
206 | + YY **= 2 | |
207 | + YY = n.sum(YY, axis=1)[n.newaxis, :] | |
208 | + else: | |
209 | + YY = n.asanyarray(Y_norm_squared) | |
210 | + if YY.shape != (Y.shape[0],): | |
211 | + raise ValueError("Incompatible dimension for Y and Y_norm_squared") | |
212 | + YY = YY[n.newaxis, :] | |
213 | + | |
214 | + # TODO: | |
215 | + # a faster cython implementation would do the dot product first, | |
216 | + # and then add XX, add YY, and do the clipping of negative values in | |
217 | + # a single pass over the output matrix. | |
218 | + distances = XX + YY # Using broadcasting | |
219 | + distances -= 2 * n.dot(X, Y.T) | |
220 | + distances = n.maximum(distances, 0) | |
221 | + if squared: | |
222 | + return distances | |
223 | + else: | |
224 | + return n.sqrt(distances) | |
225 | + | |
226 | +euclidian_distances = euclidean_distances # both spelling for backward compat | |
227 | + | |
228 | + | |
229 | +def find_CM(cluster): | |
230 | + CM=s.mean(cluster, axis=0) | |
231 | + return CM | |
232 | + | |
233 | + | |
234 | +def relocate_cluster(cluster): | |
235 | + cluster_shift=find_CM(cluster) | |
236 | + cluster[:,0]=cluster[:,0]-cluster_shift[0] | |
237 | + cluster[:,1]=cluster[:,1]-cluster_shift[1] | |
238 | + cluster[:,2]=cluster[:,2]-cluster_shift[2] | |
239 | + | |
240 | + return cluster | |
241 | + | |
242 | + | |
243 | +def project_cluster_xy(cluster): | |
244 | + new_clust=cluster[:,0:2] | |
245 | + return new_clust | |
246 | + | |
247 | + | |
248 | +################################### | |
249 | + | |
250 | + | |
251 | +R=1. #monomer radius | |
252 | +k=15 #number of monomers | |
253 | + | |
254 | +N=50000 | |
255 | +Nrot=5000 | |
256 | + | |
257 | +ini_cluster=generate_chain(k,R) | |
258 | + | |
259 | + | |
260 | + | |
261 | +# ini_cluster=s.arange(6).reshape((2,3))*1. | |
262 | + | |
263 | + | |
264 | +# ini_cluster[0,0]=4. | |
265 | +# ini_cluster[0,1]=0. | |
266 | +# ini_cluster[0,2]=0. | |
267 | + | |
268 | + | |
269 | + | |
270 | +# ini_cluster[1,0]=2. | |
271 | +# ini_cluster[1,1]=0. | |
272 | +# ini_cluster[1,2]=0. | |
273 | + | |
274 | + | |
275 | +ini_cluster=relocate_cluster(ini_cluster) | |
276 | + | |
277 | +print "ini_cluster is, ", ini_cluster | |
278 | + | |
279 | +rotated_clust=rotate_cluster(ini_cluster) | |
280 | + | |
281 | +print "rotated_clust is, ", rotated_clust | |
282 | + | |
283 | +projected_clust=project_cluster_xy(rotated_clust) | |
284 | + | |
285 | +print "projected_clust is, ", projected_clust | |
286 | + | |
287 | + | |
288 | + | |
289 | +print "N is, ", N | |
290 | + | |
291 | +area=montecarlo_calc_rect(N,projected_clust, R) | |
292 | +print "area is, ", area | |
293 | + | |
294 | +# area_exact=analytical_area(projected_clust, R) | |
295 | + | |
296 | +area_exact=analytical_area_chain(projected_clust, R,k) | |
297 | + | |
298 | + | |
299 | +print "The analytical area of the projected cluster is, ", area_exact | |
300 | + | |
301 | +rel_err=abs(area-area_exact)/area_exact*100. | |
302 | + | |
303 | +print "the relative (percentual!) error is, ", rel_err | |
304 | +######################################################################## | |
305 | + | |
306 | +# arealist=s.zeros(Nrot) | |
307 | + | |
308 | +# for i in xrange(Nrot): | |
309 | +# rotated_clust=rotate_cluster(ini_cluster) | |
310 | + | |
311 | +# # print "rotated_clust is, ", rotated_clust | |
312 | + | |
313 | +# projected_clust=project_cluster_xy(rotated_clust) | |
314 | + | |
315 | +# # print "projected_clust is, ", projected_clust | |
316 | + | |
317 | +# arealist[i]=analytical_area(projected_clust, R) | |
318 | + | |
319 | +# print "the mean area is, ", s.mean(arealist) | |
320 | + | |
321 | +print "So far so good" |