Skip to content

Commit 9bd69cd

Browse files
committed
fixed 2 major PCA bugs
1 parent 2558dcc commit 9bd69cd

File tree

4 files changed

+134
-29
lines changed

4 files changed

+134
-29
lines changed

CCA.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import copy
33
import csv
44
import numba
5+
from numpy.core.multiarray import ndarray
56
from PCA import PCA_subcluster
67

78
def CCA_subcluster(R: np.ndarray, N: int, DF: float, kf: float,iter: int,N_subcl_perc: float ,ext_case: int ,tolerance: float=1e-7) -> tuple[bool,bool]:
@@ -243,28 +244,28 @@ def generate_CCA_pairs(I_t: int, i_orden: np.ndarray, X: np.ndarray,Y: np.ndarra
243244
ID_agglom[loc,loc] = 1
244245
return ID_agglom, CCA_ok
245246

246-
def CCA_agg_properties(X: np.ndarray, Y: np.ndarray, Z: np.ndarray, R: np.ndarray, npp: int, Df: float, kf: float):
247+
def CCA_agg_properties(X: np.ndarray, Y: np.ndarray, Z: np.ndarray, R: np.ndarray, npp: int, Df: float, kf: float) -> tuple[float ,float, float, float, float, float]:
247248
m_vec = np.zeros((npp))
248249
R_i = np.zeros((npp))
249-
sum_xm = 0
250-
sum_ym = 0
251-
sum_zm = 0
250+
sum_xm: float = 0
251+
sum_ym: float = 0
252+
sum_zm: float = 0
252253
for i in range(npp):
253254
m_vec[i] = 4/3 * np.pi * np.power(R[i], 3)
254255
sum_xm += X[i]*m_vec[i]
255256
sum_ym += Y[i]*m_vec[i]
256257
sum_zm += Z[i]*m_vec[i]
257258

258-
m = np.sum(m_vec)
259+
m = float(np.sum(m_vec))
259260
X_cm = sum_xm/m
260261
Y_cm = sum_ym/m
261262
Z_cm = sum_zm/m
262263

263-
rg = (np.exp(np.sum(np.log(R)/np.log(R).size)))*np.power(npp/kf, 1/Df)
264+
rg = float((np.exp(np.sum(np.log(R)/np.log(R).size)))*np.power(npp/kf, 1/Df))
264265
for i in range(npp):
265266
R_i[i] = np.sqrt(np.power(X_cm-X[i],2) + np.power(Y_cm-Y[i],2) + np.power(Z_cm-Z[i],2))
266267

267-
R_max = np.max(R_i)
268+
R_max = float(np.max(R_i))
268269
return rg, R_max, m, X_cm, Y_cm, Z_cm
269270

270271
def CCA_identify_monomers(i_orden: np.ndarray):
@@ -276,7 +277,7 @@ def CCA_identify_monomers(i_orden: np.ndarray):
276277
return ID_mon
277278

278279
@numba.njit()
279-
def CCA_random_select_list(X1: np.ndarray, Y1: np.ndarray, Z1: np.ndarray, R1: np.ndarray, X_cm1: np.ndarray, Y_cm1: np.ndarray, Z_cm1: np.ndarray, X2: np.ndarray, Y2: np.ndarray, Z2: np.ndarray,R2: np.ndarray, X_cm2: np.ndarray, Y_cm2: np.ndarray, Z_cm2: np.ndarray, curr_list: np.ndarray, gamma_pc: float, gamma_real: bool, ext_case: int):
280+
def CCA_random_select_list(X1: np.ndarray, Y1: np.ndarray, Z1: np.ndarray, R1: np.ndarray, X_cm1: float, Y_cm1: float, Z_cm1: float, X2: np.ndarray, Y2: np.ndarray, Z2: np.ndarray,R2: np.ndarray, X_cm2: float, Y_cm2: float, Z_cm2: float, curr_list: np.ndarray, gamma_pc: float, gamma_real: bool, ext_case: int):
280281
if gamma_real and ext_case == 1:
281282
for i in range(curr_list.shape[0]-1):
282283
d_i_min = np.sqrt(np.power(X1[i]-X_cm1,2) + np.power(Y1[i]-Y_cm1,2) + np.power(Z1[i]-Z_cm1,2)) - R1[i]
@@ -392,6 +393,7 @@ def CCA(X: np.ndarray,Y: np.ndarray,Z: np.ndarray,R: np.ndarray, N: int, ID_mon:
392393
prev_cand2 = 0
393394
cov_max = 1
394395

396+
# TODO: this here should go into its own function. run different tries in parallel, check if it fits, then break out.
395397
while cov_max > tolerance:
396398
if np.sum(curr_list) > 1:
397399
prev_cand1 = CCA_random_pick(curr_list,prev_cand1)
@@ -434,6 +436,7 @@ def CCA(X: np.ndarray,Y: np.ndarray,Z: np.ndarray,R: np.ndarray, N: int, ID_mon:
434436
curr_try += 1
435437

436438
if int(np.mod(curr_try, 359)) == 0 and np.sum(curr_list[prev_cand1,:]) > 1:
439+
print("OOF")
437440
prev_cand2 = CCA_random_pick(curr_list,prev_cand1,prev_cand2)
438441

439442
COR1[:,0] = X1
@@ -545,7 +548,7 @@ def CCA_random_pick(curr_list: np.ndarray, prev_cand1: int, prev_cand2=None):
545548
prev_cand2 = selected_real
546549
return prev_cand2
547550

548-
def CCA_sticking_process(gamma_real: bool, gamma_pc: float, COR1,COR2,CM1,CM2, prev_cand1: int, prev_cand2: int, ext_case: int,n1: int, n2: int):
551+
def CCA_sticking_process(gamma_real: bool, gamma_pc: float, COR1,COR2,CM1,CM2, prev_cand1: int, prev_cand2: int, ext_case: int,n1: int, n2: int) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray,np.ndarray, np.ndarray]:
549552
if gamma_real:
550553
X1 = COR1[:,0]
551554
Y1 = COR1[:,1]
@@ -605,6 +608,7 @@ def CCA_sticking_process(gamma_real: bool, gamma_pc: float, COR1,COR2,CM1,CM2, p
605608
sphere1 = np.array([x1_sph1, y1_sph1, z1_sph1, d1_min, d1_max])
606609
sphere2 = np.array([x2_sph2, y2_sph2, z2_sph2, d2_min, d2_max])
607610

611+
u_s1_cm1 = np.array([X_cm1, Y_cm1, Z_cm1])
608612
if ext_case == 1:
609613
if np.abs(d2_max-d1_max) < gamma_pc:
610614
case = 1
@@ -697,7 +701,10 @@ def CCA_sticking_process(gamma_real: bool, gamma_pc: float, COR1,COR2,CM1,CM2, p
697701

698702
return COR1, COR2, CM2, vec0, i_vec, j_vec
699703
else:
700-
pass
704+
vec0 = np.zeros(())
705+
i_vec = np.zeros(())
706+
j_vec = np.zeros(())
707+
return COR1, COR2, CM2, vec0, i_vec, j_vec
701708

702709
def random_point_SC(case: int,sphere1: np.ndarray, sphere2: np.ndarray):
703710
phi_crit_max = 0

PCA.py

Lines changed: 111 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,55 @@
11
import numpy as np
22
import numba
33
import time
4+
from time import sleep
5+
import pyvista as pv
6+
47

58
def PCA(number: int, mass: np.ndarray, r: np.ndarray, Df: float, kf: float, tolerance: float) -> tuple[bool, np.ndarray]:
69
PCA_ok = True
710
n1,m1,rg1,x_cm,y_cm,z_cm, X,Y,Z = First_two_monomers(r, mass, number, Df, kf)
811

912
if number > 2:
1013
k=3
11-
while k < number+1:
14+
while k <= number:
1215
n2 = 1
1316
m2 = mass[k-1]
1417

1518
rg2 = np.sqrt(0.6)*r[k-1]
1619

1720
n3 = n1+n2
1821
m3 = m1+m2
19-
2022
rg3 = (np.exp(np.sum(np.log(r))/r.size))*np.power(n3/kf,1/Df)
23+
2124
gamma_ok, gamma_pc = gamma_calc(rg1,rg2,rg3,n1,n2,n3)
2225
monomer_candidates = np.zeros((number-k+1)) # 0 = not considered
2326
monomer_candidates[0] = 1 # first one has been considered
27+
2428
candidates, rmax = random_list_selection(gamma_ok, gamma_pc, X,Y,Z,r,n1,x_cm,y_cm,z_cm)
25-
list_sum = 0
2629

30+
list_sum = 0
31+
# print("here")
2732
while list_sum == 0:
28-
while np.sum(candidates) == 0 and np.sum(monomer_candidates) < number-k:
33+
# print(f"{np.sum(candidates) == 0 = }")
34+
# print(f"{np.sum(monomer_candidates) <= number-k = }")
35+
# if not np.sum(monomer_candidates) <= number-k-1:
36+
# print(f"{number = }")
37+
# print(f"{k = }")
38+
# print(f"{number-k = }")
39+
# print(f"{list_sum = }")
40+
# print(f"{np.sum(candidates) = }")
41+
# print(f"{monomer_candidates = }")
42+
while np.sum(candidates) == 0 and np.sum(monomer_candidates) <= number-k:
2943
candidates, rmax = search_monomer_candidates(r,mass,monomer_candidates,number,k,n3,Df,kf,rg1,n1,X,Y,Z,x_cm,y_cm,z_cm)
3044

31-
previous_candidate = 0
45+
previous_candidate = -1
3246

3347
if np.sum(candidates) > 0:
3448
candidates, selected_real = random_list_selection_one(candidates, previous_candidate)
3549
previous_candidate = selected_real
3650
elif np.sum(candidates) == number-k+1:
3751
PCA_ok = False
52+
exit(-1)
3853

3954
curr_try = 1
4055
X_sel = X[selected_real]
@@ -43,13 +58,28 @@ def PCA(number: int, mass: np.ndarray, r: np.ndarray, Df: float, kf: float, tole
4358
R_sel = r[selected_real]
4459
r_k = r[k-1]
4560

61+
# print(f"modified {k-1 = }")
4662
x_k, y_k, z_k, r0,x0,y0,z0,i_vec,j_vec = sticking_process(X_sel,Y_sel,Z_sel,R_sel,r_k,x_cm,y_cm,z_cm,gamma_pc)
4763
X[k-1] = x_k
4864
Y[k-1] = y_k
4965
Z[k-1] = z_k
5066

5167
cov_max = overlap_check(X[0:k], Y[0:k], Z[0:k], r[0:k],k)
5268

69+
positions = [[X[i], Y[i], Z[i]] for i in range(X.shape[0])]
70+
# print(f"{len(positions) = }")
71+
# print(f"{positions}")
72+
# point_cloud = pv.PolyData(positions)
73+
# point_cloud["radius"] = [2 for i in range(X.shape[0])]
74+
75+
# geom = pv.Sphere(theta_resolution=8, phi_resolution=8)
76+
# glyphed = point_cloud.glyph(scale="radius", geom=geom,)
77+
# # p = pv.Plotter(notebook=False, off_screen=True, window_size=(2000,2000))
78+
# p = pv.Plotter(notebook=False)
79+
# p.add_mesh(glyphed, color='white',smooth_shading=True)
80+
# p.show()
81+
# if cov_max > tolerance:
82+
# print("Need to readjust")
5383
while cov_max > tolerance and curr_try < 360:
5484
x_k, y_k, z_k,_ = sticking_process2(x0,y0,z0,r0,i_vec,j_vec)
5585

@@ -61,6 +91,8 @@ def PCA(number: int, mass: np.ndarray, r: np.ndarray, Df: float, kf: float, tole
6191

6292
if np.mod(curr_try,359) == 0 and np.sum(candidates) > 1:
6393
candidates, selected_real = random_list_selection_one(candidates, previous_candidate)
94+
# if np.sum(candidates) == 0:
95+
# print("FOURTH, candidates all ZERO")
6496
X_sel = X[selected_real]
6597
Y_sel = Y[selected_real]
6698
Z_sel = Z[selected_real]
@@ -73,15 +105,27 @@ def PCA(number: int, mass: np.ndarray, r: np.ndarray, Df: float, kf: float, tole
73105
previous_candidate = selected_real
74106
curr_try += 1
75107

108+
# print("huh1")
76109
cov_max = overlap_check(X[0:k], Y[0:k], Z[0:k], r[0:k],k)
110+
# print("huh2")
77111

112+
# FIXME: candidates may be full of zeros at some point which causes the program to get stuck
78113
list_sum = np.sum(candidates)
114+
if np.sum(candidates) == 0:
115+
print("FIFTH, candidates all ZERO")
116+
sleep(2)
117+
79118

80119
if cov_max > tolerance:
81120
list_sum = 0
82121
candidates *= 0
122+
# print("SIXTH, set all candidates to ZERO")
123+
if number == k:
124+
print("Failure -- restarting PCA routine")
125+
return False, np.zeros((number,4))
83126

84127

128+
# print("bruh")
85129
x_cm = (x_cm*m1 + X[k-1]*m2)/(m1+m2)
86130
y_cm = (y_cm*m1 + Y[k-1]*m2)/(m1+m2)
87131
z_cm = (z_cm*m1 + Z[k-1]*m2)/(m1+m2)
@@ -91,10 +135,21 @@ def PCA(number: int, mass: np.ndarray, r: np.ndarray, Df: float, kf: float, tole
91135
rg1 = (np.exp(np.sum(np.log(r))/np.log(r).size))*(np.power(n1/kf, 1/Df))
92136
k = k + 1
93137
# FIXME: this gets stuck for some reason (no apparent connection to the arcos issue)
138+
# print("hi")
94139

95140
data_new = np.zeros((number,4))
96141
for i in range(number):
97142
data_new[i,:] = np.array([X[i], Y[i], Z[i], r[i]])
143+
144+
# point_cloud = pv.PolyData(data_new[:,:-1])
145+
# point_cloud["radius"] = [2 for i in range(X.shape[0])]
146+
147+
# geom = pv.Sphere(theta_resolution=8, phi_resolution=8)
148+
# glyphed = point_cloud.glyph(scale="radius", geom=geom,)
149+
# # p = pv.Plotter(notebook=False, off_screen=True, window_size=(2000,2000))
150+
# p = pv.Plotter(notebook=False)
151+
# p.add_mesh(glyphed, color='white',smooth_shading=True)
152+
# p.show()
98153
return PCA_ok, data_new
99154

100155
def PCA_subcluster(N: int, N_subcluster: int, R: np.ndarray, DF: float, kf: float, tolerance: float) -> tuple[bool, np.ndarray, int, np.ndarray]:
@@ -120,7 +175,11 @@ def PCA_subcluster(N: int, N_subcluster: int, R: np.ndarray, DF: float, kf: floa
120175
for j in range(radius.size):
121176
mass[j] = 4/3 * np.pi * np.power(R[j],3)
122177

123-
PCA_OK, data_new = PCA(number,mass,radius,DF,kf,tolerance)
178+
PCA_OK = False
179+
while not PCA_OK:
180+
PCA_OK, data_new = PCA(number,mass,radius,DF,kf,tolerance)
181+
print(f"PCA LOOP {i} DONE!")
182+
# time.sleep(1)
124183

125184
if i == 0:
126185
acum = number
@@ -145,10 +204,16 @@ def First_two_monomers(R: np.ndarray,M: np.ndarray,N: int,DF: float,kf:float) ->
145204

146205
u = np.random.rand()
147206
v = np.random.rand()
207+
# print("first two monomers")
208+
# print(f"{u = }, {v = }")
209+
210+
211+
# u = 0.007316022089059793
212+
# v = 0.43406326698233766
148213
theta = 2*np.pi*u
149214
phi = np.arccos(2*v-1)
150-
theta = 1
151-
phi = 1
215+
# theta = 0.5
216+
# phi = 0.1
152217

153218
X[1] = X[0] + (R[0]+R[1])*np.cos(theta)*np.sin(phi)
154219
Y[1] = Y[0] + (R[0]+R[1])*np.sin(theta)*np.sin(phi)
@@ -158,11 +223,17 @@ def First_two_monomers(R: np.ndarray,M: np.ndarray,N: int,DF: float,kf:float) ->
158223
n1 = 2
159224

160225
rg1 = (np.exp(np.sum(np.log(R[:2]))/2))*np.power(n1/kf,1/DF)
226+
# print(f"{rg1 = }")
161227

162228
x_cm = (X[0]*M[0]+X[1]*M[1])/(M[0] + M[1])
163229
y_cm = (Y[0]*M[0]+Y[1]*M[1])/(M[0] + M[1])
164230
z_cm = (Z[0]*M[0]+Z[1]*M[1])/(M[0] + M[1])
165231

232+
233+
# print(f"{X[0] = }, {Y[0] = }, {Z[0] = }")
234+
# print(f"{x_cm = }, {y_cm = }, {z_cm = }")
235+
# print(f"{M = }")
236+
166237
return n1,m1,rg1,x_cm,y_cm,z_cm, X,Y,Z
167238

168239
def gamma_calc(rg1: float,rg2: float,rg3: float,n1: int,n2: int,n3: int) -> tuple[bool,float]:
@@ -178,7 +249,7 @@ def gamma_calc(rg1: float,rg2: float,rg3: float,n1: int,n2: int,n3: int) -> tupl
178249
gamma_pc = np.sqrt((np.power(n3,2)*np.power(rg3_aux,2)-n3*(n1*np.power(rg1,2)+n2*np.power(rg2,2)))/(n1*n2))
179250
else:
180251
gamma_ok = False
181-
252+
182253
return gamma_ok, gamma_pc
183254

184255
@numba.njit()
@@ -202,7 +273,8 @@ def search_monomer_candidates(R: np.ndarray, M: np.ndarray, monomer_candidates:
202273
M_sl = M
203274
vector_search = np.zeros((N-k+1))
204275
for i in range(vector_search.size):
205-
vector_search[i] = i+k
276+
vector_search[i] = i+k-2
277+
# print(f"{i+k-2 = }")
206278

207279
for i in range(monomer_candidates.size):
208280
if monomer_candidates[i] == 1:
@@ -211,6 +283,8 @@ def search_monomer_candidates(R: np.ndarray, M: np.ndarray, monomer_candidates:
211283

212284
if vector_search2.size > 1:
213285
u = np.random.rand()
286+
# print("search monomer candidates")
287+
# print(f"{u = }")
214288
RS_1 = int(vector_search2[int(u*(vector_search.size-1))])
215289
else:
216290
RS_1 = int(vector_search2[0])
@@ -229,15 +303,16 @@ def search_monomer_candidates(R: np.ndarray, M: np.ndarray, monomer_candidates:
229303

230304
candidates, rmax = random_list_selection(gamma_ok, gamma_pc, X,Y,Z,R,n1,x_cm,y_cm,z_cm)
231305

232-
# FIXME: this fails once kf > 1.5 LMFAO
233-
candidates[RS_1-k-1] = 1
234306
return candidates, rmax
235307

236308
def random_list_selection_one(candidates: np.ndarray, previous_candidate: int):
237-
if previous_candidate > 0:
309+
if previous_candidate > -1:
238310
candidates[previous_candidate] = 0
239311
candidates2 = candidates[candidates > 0]
240312
n = np.random.rand()
313+
# print("random list selection one")
314+
# print(f"{n = }")
315+
# n = 0.5
241316
selected = 1+int(n*(candidates2.size-1))
242317

243318
selected_real = 0
@@ -260,6 +335,9 @@ def sticking_process(x: float,y: float,z: float,r: float,r_k: float, x_cm: float
260335
z2 = z_cm
261336
r2 = gamma_pc
262337

338+
# print(f"{x1 = }, {y1 = }, {z1 = }, {r1 = }")
339+
# print(f"{x2 = }, {y2 = }, {z2 = }, {r2 = }")
340+
263341
a = 2*(x2-x1)
264342
b = 2*(y2-y1)
265343
c = 2*(z2-z1)
@@ -273,9 +351,24 @@ def sticking_process(x: float,y: float,z: float,r: float,r_k: float, x_cm: float
273351

274352
distance = np.sqrt(np.power(x2-x1,2) + np.power(y2-y1,2) + np.power(z2-z1,2))
275353

354+
355+
# print(f"{distance = }")
356+
276357
alpha = np.arccos((np.power(r1,2) + np.power(distance,2) - np.power(r2,2))/(2*r1*distance))
358+
# print(f"{alpha = }")
277359
if abs((np.power(r1,2) + np.power(distance,2) - np.power(r2,2))/(2*r1*distance)) > 1:
278360
# FIXME: this should never happen!
361+
362+
pos = [[x1,y1,z1], [x2,y2,z2]]
363+
point_cloud = pv.PolyData(pos)
364+
point_cloud["radius"] = [2,2]
365+
366+
geom = pv.Sphere(theta_resolution=8, phi_resolution=8)
367+
glyphed = point_cloud.glyph(scale="radius", geom=geom,)
368+
# p = pv.Plotter(notebook=False, off_screen=True, window_size=(2000,2000))
369+
p = pv.Plotter(notebook=False)
370+
p.add_mesh(glyphed, color='white',smooth_shading=True)
371+
p.show()
279372
print(f"{(np.power(r1,2) + np.power(distance,2) - np.power(r2,2))/(2*r1*distance) = }")
280373
exit(-1)
281374
r0 = r1*np.sin(alpha)
@@ -289,6 +382,9 @@ def sticking_process(x: float,y: float,z: float,r: float,r_k: float, x_cm: float
289382

290383
u = np.random.rand()
291384
v = np.random.rand()
385+
# print("sticking process")
386+
# print(f"{u = }, {v = }")
387+
292388
theta = 2.*np.pi*u
293389
phi = np.arccos(2.*v-1.)
294390

@@ -300,6 +396,8 @@ def sticking_process(x: float,y: float,z: float,r: float,r_k: float, x_cm: float
300396

301397
def sticking_process2(x0, y0, z0, r0,i_vec,j_vec):
302398
u = np.random.rand()
399+
# print("sticking process2")
400+
# print(f"{u = }")
303401
theta = 2 * np.pi * u
304402

305403
x_k = x0 + r0*np.cos(theta)*i_vec[0]+r0*np.sin(theta)*j_vec[0]

0 commit comments

Comments
 (0)