1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
12 from .utils_pip
import Pip
13 Pip
._ensure
_user
_site
_package
()
14 from numba
import jit
, njit
, guvectorize
, float64
, int32
, prange
15 from numba
.typed
import List
21 from .utils_pip import Pip
23 Pip.install('llvmlite')
25 from numba import jit, njit, guvectorize, float64, int32, prange
27 print('Tissue: Numba successfully installed!')
29 print('Tissue: Numba not loaded correctly. Try restarting Blender')
33 #from numba import jit, njit, guvectorize, float64, int32, prange
37 #@cuda.jit('void(float32[:,:], float32[:,:])')
38 def tex_laplacian(lap
, arr
):
49 #lap[i+1,j+1] = arr[i, j+1] + arr[i+2, j+1] + arr[i+1, j] + arr[i+1, j+2] - 4*arr[i+1,j+1]
51 lap
[i
,j
] = ((arr
[i0
, j
] + arr
[i1
, j
] - arr2
[i
,j
]) + \
52 (arr
[i
, j0
] + arr
[i
, j1
] - arr2
[i
,j
]) + \
53 (arr
[i0
, j0
] + arr
[i1
, j1
] - arr2
[i
,j
])*diag
+ \
54 (arr
[i1
, j0
] + arr
[i0
, j1
] - arr2
[i
,j
])*diag
)*0.75
57 def tex_laplacian_ani(lap
, arr
, VF
):
71 lap
[i
,j
] = (arr
[i0
[i
], j
] + arr
[i1
[i
], j
] - arr2
[i
,j
])*VF
[0,i
,j
] + \
72 (arr
[i
, j0
[j
]] + arr
[i
, j1
[j
]] - arr2
[i
,j
])*VF
[1,i
,j
] + \
73 (arr
[i0
[i
], j0
[j
]] + arr
[i1
[i
], j1
[j
]] - arr2
[i
,j
])*VF
[2,i
,j
] + \
74 (arr
[i1
[i
], j0
[j
]] + arr
[i0
[i
], j1
[j
]] - arr2
[i
,j
])*VF
[3,i
,j
]
77 #lap[-1,:] = lap[-2,:]
78 #lap[:,-1] = lap[:,-2]
80 #@cuda.jit(parallel=True)
82 def run_tex_rd(A
, B
, lap_A
, lap_B
, diff_A
, diff_B
, f
, k
, dt
, steps
, brush
):
83 for t
in range(steps
):
84 tex_laplacian(lap_A
, A
)
85 tex_laplacian(lap_B
, B
)
91 ab2
= A
[i
,j
]*B
[i
,j
]**2
92 A
[i
,j
] += (lap_A
[i
,j
]*diff_A
- ab2
+ f
*(1-A
[i
,j
]))*dt
93 B
[i
,j
] += (lap_B
[i
,j
]*diff_B
+ ab2
- (k
+f
)*B
[i
,j
])*dt
96 def run_tex_rd_ani(A
, B
, lap_A
, lap_B
, diff_A
, diff_B
, f
, k
, dt
, steps
, vf1
, vf2
, brush
):
97 for t
in range(steps
):
98 tex_laplacian_ani(lap_A
, A
, vf2
)
100 tex_laplacian_ani(lap_B
, B
, vf1
)
106 ab2
= A
[i
,j
]*B
[i
,j
]**2
107 A
[i
,j
] += (lap_A
[i
,j
]*diff_A
[i
,j
] - ab2
+ f
[i
,j
]*(1-A
[i
,j
]))*dt
108 B
[i
,j
] += (lap_B
[i
,j
]*diff_B
[i
,j
] + ab2
- (k
[i
,j
]+f
[i
,j
])*B
[i
,j
])*dt
112 def numba_reaction_diffusion(n_verts
, n_edges
, edge_verts
, a
, b
, brush
, diff_a
, diff_b
, f
, k
, dt
, time_steps
):
113 arr
= np
.arange(n_edges
)
114 id0
= edge_verts
[arr
*2]
115 id1
= edge_verts
[arr
*2+1]
116 for i
in range(time_steps
):
117 lap_a
, lap_b
= rd_init_laplacian(n_verts
)
118 numba_rd_laplacian(id0
, id1
, a
, b
, lap_a
, lap_b
)
119 numba_rd_core(a
, b
, lap_a
, lap_b
, diff_a
, diff_b
, f
, k
, dt
)
120 numba_set_ab(a
,b
,brush
)
123 @njit(parallel
=False)
124 def integrate_field(n_edges
, id0
, id1
, values
, edge_flow
, mult
, time_steps
):
125 #n_edges = len(edge_flow)
126 for i
in range(time_steps
):
128 for j
in range(n_edges
):
131 values
[v0
] -= values0
[v1
] * edge_flow
[j
] * 0.001#mult[v1]
132 values
[v1
] += values0
[v0
] * edge_flow
[j
] * 0.001#mult[v0]
133 for j
in range(n_edges
):
136 values
[v0
] = max(values
[v0
],0)
137 values
[v1
] = max(values
[v1
],0)
141 def numba_reaction_diffusion_anisotropic(n_verts
, n_edges
, edge_verts
, a
, b
, brush
, diff_a
, diff_b
, f
, k
, dt
, time_steps
, field_mult
):
142 arr
= np
.arange(n_edges
)
143 id0
= edge_verts
[arr
*2]
144 id1
= edge_verts
[arr
*2+1]
145 mult
= field_mult
[arr
]
146 for i
in range(time_steps
):
147 lap_a
, lap_b
= rd_init_laplacian(n_verts
)
148 numba_rd_laplacian_anisotropic(id0
, id1
, a
, b
, lap_a
, lap_b
, mult
)
149 numba_rd_core(a
, b
, lap_a
, lap_b
, diff_a
, diff_b
, f
, k
, dt
)
150 numba_set_ab(a
,b
,brush
)
153 #@guvectorize(['(float64[:] ,float64[:] , float64[:], float64[:], float64[:], float64[:], float64[:], float64[:], float64)'],'(n),(n),(n),(n),(n),(n),(n),(n),()',target='parallel')
155 def numba_rd_core(a
, b
, lap_a
, lap_b
, diff_a
, diff_b
, f
, k
, dt
):
157 _f
= np
.full(n
, f
[0]) if len(f
) == 1 else f
158 _k
= np
.full(n
, k
[0]) if len(k
) == 1 else k
159 _diff_a
= np
.full(n
, diff_a
[0]) if len(diff_a
) == 1 else diff_a
160 _diff_b
= np
.full(n
, diff_b
[0]) if len(diff_b
) == 1 else diff_b
168 a
[i
] += (diff_ai
* lap_a
[i
] - ab2
+ fi
*(1-a
[i
]))*dt
169 b
[i
] += (diff_bi
* lap_b
[i
] + ab2
- (ki
+fi
)*b
[i
])*dt
172 def numba_rd_core_(a
, b
, lap_a
, lap_b
, diff_a
, diff_b
, f
, k
, dt
):
174 a
+= (diff_a
*lap_a
- ab2
+ f
*(1-a
))*dt
175 b
+= (diff_b
*lap_b
+ ab2
- (k
+f
)*b
)*dt
178 def numba_set_ab(a
, b
, brush
):
180 _brush
= np
.full(n
, brush
[0]) if len(brush
) == 1 else brush
181 for i
in prange(len(b
)):
183 if b
[i
] < 0: b
[i
] = 0
184 elif b
[i
] > 1: b
[i
] = 1
185 if a
[i
] < 0: a
[i
] = 0
186 elif a
[i
] > 1: a
[i
] = 1
189 def numba_rd_laplacian(id0
, id1
, a
, b
, lap_a
, lap_b
):
190 for i
in prange(len(id0
)):
193 lap_a
[v0
] += (a
[v1
] - a
[v0
])
194 lap_a
[v1
] += (a
[v0
] - a
[v1
])
195 lap_b
[v0
] += (b
[v1
] - b
[v0
])
196 lap_b
[v1
] += (b
[v0
] - b
[v1
])
200 def numba_rd_laplacian_anisotropic(id0
, id1
, a
, b
, lap_a
, lap_b
, mult
):
201 for i
in prange(len(id0
)):
205 lap_a
[v0
] += (a
[v1
] - a
[v0
])# * multiplier
206 lap_a
[v1
] += (a
[v0
] - a
[v1
])# * multiplier
207 lap_b
[v0
] += (b
[v1
] - b
[v0
]) * multiplier
208 lap_b
[v1
] += (b
[v0
] - b
[v1
]) * multiplier
212 def numba_rd_neigh_vertices(edge_verts
):
213 n_edges
= len(edge_verts
)/2
214 id0
= np
.zeros(n_edges
)
215 id1
= np
.zeros(n_edges
)
216 for i
in prange(n_edges
):
217 id0
[i
] = edge_verts
[i
*2] # first vertex indices for each edge
218 id1
[i
] = edge_verts
[i
*2+1] # second vertex indices for each edge
221 #@guvectorize(['(float64[:] ,float64[:] , float64[:], float64[:], float64[:])'],'(m),(n),(n),(n),(n)',target='parallel')
224 def numba_rd_laplacian_(edge_verts
, a
, b
, lap_a
, lap_b
):
225 for i
in prange(len(edge_verts
)/2):
227 v1
= edge_verts
[i
*2+1]
228 lap_a
[v0
] += a
[v1
] - a
[v0
]
229 lap_a
[v1
] += a
[v0
] - a
[v1
]
230 lap_b
[v0
] += b
[v1
] - b
[v0
]
231 lap_b
[v1
] += b
[v0
] - b
[v1
]
235 def rd_fill_laplacian(lap_a
, lap_b
, id0
, id1
, lap_a0
, lap_b0
):
236 #for i, j, la0, lb0 in zip(id0,id1,lap_a0,lap_b0):
237 for index
in prange(len(id0
)):
248 def rd_init_laplacian(n_verts
):
249 lap_a
= np
.zeros(n_verts
)
250 lap_b
= np
.zeros(n_verts
)
255 def numba_reaction_diffusion(n_verts, n_edges, edge_verts, a, b, diff_a, diff_b, f, k, dt, time_steps, db):
256 arr = np.arange(n_edges)*2
257 id0 = edge_verts[arr] # first vertex indices for each edge
258 id1 = edge_verts[arr+1] # second vertex indices for each edge
259 #dgrad = abs(grad[id1] - grad[id0])
260 for i in range(time_steps):
261 lap_a = np.zeros(n_verts)
262 lap_b = np.zeros(n_verts)
264 lap_a0 = a[id1] - a[id0] # laplacian increment for first vertex of each edge
265 lap_b0 = b[id1] - b[id0] # laplacian increment for first vertex of each edge
269 for i, j, la0, lb0 in zip(id0,id1,lap_a0,lap_b0):
275 #a += eval("(diff_a*lap_a - ab2 + f*(1-a))*dt")
276 #b += eval("(diff_b*lap_b + ab2 - (k+f)*b)*dt")
277 a += (diff_a*lap_a - ab2 + f*(1-a))*dt
278 b += (diff_b*lap_b + ab2 - (k+f)*b)*dt
283 def numba_lerp2_(v00, v10, v01, v11, vx, vy):
285 co2 = np.zeros((sh[0],len(vx),sh[-1]))
286 for i in prange(len(v00)):
287 for j in prange(len(vx)):
288 for k in prange(len(v00[0][0])):
289 co0 = v00[i][0][k] + (v10[i][0][k] - v00[i][0][k]) * vx[j][0]
290 co1 = v01[i][0][k] + (v11[i][0][k] - v01[i][0][k]) * vx[j][0]
291 co2[i][j][k] = co0 + (co1 - co0) * vy[j][0]
296 def numba_lerp2_vec(v0, vx, vy):
297 n_faces = v0.shape[0]
298 co2 = np.zeros((n_faces,len(vx),3))
299 for i in prange(n_faces):
300 for j in prange(len(vx)):
302 co0 = v0[i][0][k] + (v0[i][1][k] - v0[i][0][k]) * vx[j][0]
303 co1 = v0[i][3][k] + (v0[i][2][k] - v0[i][3][k]) * vx[j][0]
304 co2[i][j][k] = co0 + (co1 - co0) * vy[j][0]
308 def numba_lerp2__(val, vx, vy):
310 co2 = np.zeros((n_faces,len(vx),1))
311 for i in prange(n_faces):
312 for j in prange(len(vx)):
313 co0 = val[i][0] + (val[i][1] - val[i][0]) * val[j][0]
314 co1 = val[i][3] + (val[i][2] - val[i][3]) * val[j][0]
315 co2[i][j][0] = co0 + (co1 - co0) * vy[j][0]
320 def numba_combine_and_flatten(arrays
):
321 n_faces
= len(arrays
)
322 n_verts
= len(arrays
[0])
323 new_list
= [0.0]*n_faces
*n_verts
*3
324 for i
in prange(n_faces
):
325 for j
in prange(n_verts
):
327 new_list
[i
*n_verts
*3+j
*3+k
] = arrays
[i
][j
,k
]
331 def numba_calc_thickness_area_weight(co2
,n2
,vz
,a
,weight
):
338 nw
= weight
.shape
[1]-1
339 co3
= np
.zeros((n_patches
,n_verts
,n_co
))
340 for i
in prange(n_patches
):
341 for j
in prange(n_verts
):
342 for k
in prange(n_co
):
343 co3
[i
,j
,k
] = co2
[i
,j
,k
] + n2
[i
,min(j
,nn
),k
] * vz
[0,j
,0] * a
[i
,min(j
,na
),0] * weight
[i
,min(j
,nw
),0]
347 def numba_calc_thickness_area(co2,n2,vz,a):
352 #co3 = [0.0]*n_patches*n_verts*n_co #np.zeros((n_patches,n_verts,n_co))
353 co3 = np.zeros((n_patches,n_verts,n_co))
354 for i in prange(n_patches):
355 for j in prange(n_verts):
356 for k in prange(n_co):
357 #co3[i,j,k] = co2[i,j,k] + n2[i,j,k] * vz[0,j,0] * a[i,j,0]
358 co3[i,j,k] = co2[i,j,k] + n2[i,min(j,nor_len),k] * vz[0,j,0] * a[i,j,0]
362 def numba_calc_thickness_weight(co2
,n2
,vz
,weight
):
368 nw
= weight
.shape
[1]-1
369 co3
= np
.zeros((n_patches
,n_verts
,n_co
))
370 for i
in prange(n_patches
):
371 for j
in prange(n_verts
):
372 for k
in prange(n_co
):
373 co3
[i
,j
,k
] = co2
[i
,j
,k
] + n2
[i
,min(j
,nn
),k
] * vz
[0,j
,0] * weight
[i
,min(j
,nw
),0]
377 def numba_calc_thickness(co2
,n2
,vz
):
383 co3
= np
.zeros((n_patches
,n_verts
,n_co
))
384 for i
in prange(n_patches
):
385 for j
in prange(n_verts
):
386 for k
in prange(n_co
):
387 co3
[i
,j
,k
] = co2
[i
,j
,k
] + n2
[i
,min(j
,nn
),k
] * vz
[0,j
,0]
391 def numba_interp_points(v00
, v10
, v01
, v11
, vx
, vy
):
392 n_patches
= v00
.shape
[0]
393 n_verts
= vx
.shape
[1]
394 n_verts0
= v00
.shape
[1]
396 vxy
= np
.zeros((n_patches
,n_verts
,n_co
))
397 for i
in prange(n_patches
):
398 for j
in prange(n_verts
):
399 j0
= min(j
,n_verts0
-1)
400 for k
in prange(n_co
):
401 co0
= v00
[i
,j0
,k
] + (v10
[i
,j0
,k
] - v00
[i
,j0
,k
]) * vx
[0,j
,0]
402 co1
= v01
[i
,j0
,k
] + (v11
[i
,j0
,k
] - v01
[i
,j0
,k
]) * vx
[0,j
,0]
403 vxy
[i
,j
,k
] = co0
+ (co1
- co0
) * vy
[0,j
,0]
407 def numba_interp_points_sk(v00
, v10
, v01
, v11
, vx
, vy
):
408 n_patches
= v00
.shape
[0]
410 n_verts
= v00
.shape
[2]
412 vxy
= np
.zeros((n_patches
,n_sk
,n_verts
,n_co
))
413 for i
in prange(n_patches
):
414 for sk
in prange(n_sk
):
415 for j
in prange(n_verts
):
416 for k
in prange(n_co
):
417 co0
= v00
[i
,sk
,j
,k
] + (v10
[i
,sk
,j
,k
] - v00
[i
,sk
,j
,k
]) * vx
[0,sk
,j
,0]
418 co1
= v01
[i
,sk
,j
,k
] + (v11
[i
,sk
,j
,k
] - v01
[i
,sk
,j
,k
]) * vx
[0,sk
,j
,0]
419 vxy
[i
,sk
,j
,k
] = co0
+ (co1
- co0
) * vy
[0,sk
,j
,0]
423 def numba_lerp(v0
, v1
, x
):
424 return v0
+ (v1
- v0
) * x
427 def numba_lerp2(v00
, v10
, v01
, v11
, vx
, vy
):
428 co0
= numba_lerp(v00
, v10
, vx
)
429 co1
= numba_lerp(v01
, v11
, vx
)
430 co2
= numba_lerp(co0
, co1
, vy
)
434 def numba_lerp2_________________(v00
, v10
, v01
, v11
, vx
, vy
):
438 co2
= np
.zeros((ni
,nj
,nk
))
446 co0
= _v00
+ (_v10
- _v00
) * vx
[i
,j
,k
]
447 co1
= _v01
+ (_v11
- _v01
) * vx
[i
,j
,k
]
448 co2
[i
,j
,k
] = co0
+ (co1
- co0
) * vy
[i
,j
,k
]
452 def numba_lerp2_4(v00
, v10
, v01
, v11
, vx
, vy
):
456 nw
= len(v00
[0][0][0])
457 co2
= np
.zeros((ni
,nj
,nk
,nw
))
466 co0
= _v00
+ (_v10
- _v00
) * vx
[i
,j
,k
]
467 co1
= _v01
+ (_v11
- _v01
) * vx
[i
,j
,k
]
468 co2
[i
,j
,k
] = co0
+ (co1
- co0
) * vy
[i
,j
,k
]
473 # print("Tissue: Numba cannot be installed. Try to restart Blender.")