-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgradient.py
More file actions
120 lines (85 loc) · 3.58 KB
/
Copy pathgradient.py
File metadata and controls
120 lines (85 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python
# coding: utf-8
# ------------------------------------------------------------------------------------------------
# Imports
# ------------------------------------------------------------------------------------------------
from common import *
from scipy.interpolate import interpn
from scipy.interpolate import interp1d
# ------------------------------------------------------------------------------------------------
# Gradient
# ------------------------------------------------------------------------------------------------
def compute_grad(mask, U):
"""Compute the gradient of a 3D scalar field."""
n, m, p = mask.shape
# Find the surface.
i, j, k = np.nonzero(np.isin(mask, (V_ST, V_SB, V_SE)))
surf = np.zeros((n, m, p), dtype=bool)
surf[i, j, k] = True
iv, jv, kv = np.nonzero(mask == V_VOLUME)
# Clip the laplacian.
q = .9999
Uclip = np.clip(U, U.min(), np.quantile(U, q))
# Compute the gradient inside the volume.
grad = np.zeros((n, m, p, 3), dtype=np.float32)
grad[iv, jv, kv, 0] = .5 * (Uclip[iv+1, jv, kv] - Uclip[iv-1, jv, kv])
grad[iv, jv, kv, 1] = .5 * (Uclip[iv, jv+1, kv] - Uclip[iv, jv-1, kv])
grad[iv, jv, kv, 2] = .5 * (Uclip[iv, jv, kv+1] - Uclip[iv, jv, kv-1])
# Compute the gradient on the surface.
idx = mask[i+1, j, k] == V_VOLUME
grad[i[idx], j[idx], k[idx], 0] = Uclip[
i[idx]+1, j[idx], k[idx]] - Uclip[i[idx], j[idx], k[idx]]
idx = mask[i-1, j, k] == V_VOLUME
grad[i[idx], j[idx], k[idx], 0] = Uclip[
i[idx], j[idx], k[idx]] - Uclip[i[idx]-1, j[idx], k[idx]]
idx = mask[i, j+1, k] == V_VOLUME
grad[i[idx], j[idx], k[idx], 1] = Uclip[
i[idx], j[idx]+1, k[idx]] - Uclip[i[idx], j[idx], k[idx]]
idx = mask[i, j-1, k] == V_VOLUME
grad[i[idx], j[idx], k[idx], 1] = Uclip[
i[idx], j[idx], k[idx]] - Uclip[i[idx], j[idx]-1, k[idx]]
idx = mask[i, j, k+1] == V_VOLUME
grad[i[idx], j[idx], k[idx], 2] = Uclip[
i[idx], j[idx], k[idx]+1] - Uclip[i[idx], j[idx], k[idx]]
idx = mask[i, j, k-1] == V_VOLUME
grad[i[idx], j[idx], k[idx], 2] = Uclip[
i[idx], j[idx], k[idx]] - Uclip[i[idx], j[idx], k[idx]-1]
return grad
def normalize_gradient(grad, threshold=0):
"""Normalize the gradient."""
# Normalize the gradient.
gradn = np.linalg.norm(grad, axis=3)
idx = gradn > threshold
grad[idx] /= gradn[idx, np.newaxis]
# Kill gradient vectors that are too small.
if threshold > 0:
grad[~idx] = 0
return grad
def get_gradient(region):
"""Compute (or load from the cache) the gradient to the solution of Laplace's equation."""
path = filepath(region, 'gradient')
gradient = load_npy(path)
if gradient is not None:
return gradient
# Load the laplacian to compute the gradient.
U = load_npy(filepath(region, 'laplacian'))
if U is None:
# TODO: compute the laplacian with code in streamlines.py
raise NotImplementedError()
assert U.ndim == 3
# Load the mask.
mask = load_npy(filepath(region, 'mask'))
# Compute the gradient.
gradient = compute_grad(mask, U)
assert gradient.ndim == 4
# Normalize the gradient.
gradient = normalize_gradient(gradient)
# Save the gradient.
save_npy(path, gradient)
del gradient
return load_npy(path)
# ------------------------------------------------------------------------------------------------
# Entry-point
# ------------------------------------------------------------------------------------------------
if __name__ == '__main__':
get_gradient(REGION)