|
13 | 13 | import numpy as np |
14 | 14 | from scipy.optimize import LinearConstraint, differential_evolution |
15 | 15 |
|
| 16 | + |
16 | 17 | class CFFD(FFD): |
17 | 18 | """ |
18 | 19 | Class that handles the Constrained Free Form Deformation on the mesh points. |
@@ -44,77 +45,79 @@ class CFFD(FFD): |
44 | 45 | on x,y,z respectively. Default is all true. It used only in the triaffine mode. |
45 | 46 |
|
46 | 47 | :Example: |
47 | | -
|
48 | 48 | >>> from pygem import CFFD |
49 | 49 | >>> import numpy as np |
50 | | - >>> original_mesh_points = np.load('tests/test_datasets/meshpoints_sphere_orig.npy') |
| 50 | + >>> original_mesh_points = np.random.rand(100, 3) |
51 | 51 | >>> A = np.random.rand(3, original_mesh_points[:-4].reshape(-1).shape[0]) |
52 | 52 | >>> fun = lambda x: A @ x.reshape(-1) |
53 | 53 | >>> b = np.random.rand(3) |
54 | 54 | >>> cffd = CFFD(b, fun, [2, 2, 2]) |
55 | | - >>> cffd.read_parameters('tests/test_datasets/parameters_test_ffd_sphere.prm') |
| 55 | + >>> cffd.read_parameters('tests/test_datasets/parameters_test_cffd.prm') |
56 | 56 | >>> cffd.adjust_control_points(original_mesh_points[:-4]) |
57 | | - >>> assert np.isclose(np.linalg.norm(fun(cffd.ffd(original_mesh_points[:-4])) - b), np.array([0.]),atol = 1e-06) |
| 57 | + >>> assert np.isclose(np.linalg.norm(fun(cffd.ffd(original_mesh_points[:-4])) - b), np.array([0.]), atol = 1e-06) |
58 | 58 | >>> new_mesh_points = cffd.ffd(original_mesh_points) |
59 | | - """ |
60 | 59 |
|
| 60 | + """ |
61 | 61 | def __init__(self, |
62 | | - fixval, |
63 | | - fun, |
64 | | - n_control_points=None, |
65 | | - ffd_mask=None, |
66 | | - fun_mask=None): |
| 62 | + fixval, |
| 63 | + fun, |
| 64 | + n_control_points=None, |
| 65 | + ffd_mask=None, |
| 66 | + fun_mask=None): |
67 | 67 | super().__init__(n_control_points) |
68 | 68 |
|
69 | 69 | if ffd_mask is None: |
70 | | - self.ffd_mask = np.full((*self.n_control_points, 3), True, dtype=bool) |
| 70 | + self.ffd_mask = np.full((*self.n_control_points, 3), |
| 71 | + True, |
| 72 | + dtype=bool) |
71 | 73 | else: |
72 | 74 | self.ffd_mask = ffd_mask |
73 | 75 |
|
74 | | - self.num_cons=len(fixval) |
75 | | - self.fun=fun |
76 | | - self.fixval=fixval |
| 76 | + self.num_cons = len(fixval) |
| 77 | + self.fun = fun |
| 78 | + self.fixval = fixval |
77 | 79 | if fun_mask is None: |
78 | 80 | self.fun_mask = np.full((self.num_cons, 3), True, dtype=bool) |
79 | 81 | else: |
80 | 82 | self.fun_mask = fun_mask |
81 | | - def adjust_control_points(self,src_pts): |
| 83 | + |
| 84 | + def adjust_control_points(self, src_pts): |
82 | 85 | ''' |
83 | 86 | Adjust the FFD control points such that fun(ffd(src_pts))=fixval |
84 | 87 | |
85 | 88 | :param np.ndarray src_pts: the points whose deformation we want to be |
86 | 89 | constrained. |
87 | 90 | :rtype: None. |
88 | 91 | ''' |
89 | | - hyper_param=self.fun_mask.copy().astype(float) |
90 | | - hyper_param=hyper_param/np.sum(hyper_param,axis=1) |
| 92 | + hyper_param = self.fun_mask.copy().astype(float) |
| 93 | + hyper_param = hyper_param / np.sum(hyper_param, axis=1) |
91 | 94 | mask_bak = self.ffd_mask.copy() |
92 | | - fixval_bak=self.fixval.copy() |
| 95 | + fixval_bak = self.fixval.copy() |
93 | 96 | diffvolume = self.fixval - self.fun(self.ffd(src_pts)) |
94 | 97 | for i in range(3): |
95 | | - self.ffd_mask = np.full((*self.n_control_points, 3), False, dtype=bool) |
| 98 | + self.ffd_mask = np.full((*self.n_control_points, 3), |
| 99 | + False, |
| 100 | + dtype=bool) |
96 | 101 | self.ffd_mask[:, :, :, i] = mask_bak[:, :, :, i].copy() |
97 | | - self.fixval = self.fun(self.ffd(src_pts)) + hyper_param[:,i] * ( |
98 | | - diffvolume |
99 | | - ) |
| 102 | + self.fixval = self.fun( |
| 103 | + self.ffd(src_pts)) + hyper_param[:, i] * (diffvolume) |
100 | 104 | saved_parameters = self._save_parameters() |
101 | 105 | indices = np.arange(np.prod(self.n_control_points) * |
102 | 106 | 3)[self.ffd_mask.reshape(-1)] |
103 | 107 | A, b = self._compute_linear_map(src_pts, saved_parameters.copy(), |
104 | | - indices) |
105 | | - A=A[self.fun_mask[:,i].reshape(-1),:] |
106 | | - b=b[self.fun_mask[:,i].reshape(-1)] |
| 108 | + indices) |
| 109 | + A = A[self.fun_mask[:, i].reshape(-1), :] |
| 110 | + b = b[self.fun_mask[:, i].reshape(-1)] |
107 | 111 | d = A @ saved_parameters[indices] + b |
108 | | - fixval=self.fixval[self.fun_mask[:,i].reshape(-1)] |
| 112 | + fixval = self.fixval[self.fun_mask[:, i].reshape(-1)] |
109 | 113 | deltax = np.linalg.multi_dot([ |
110 | 114 | A.T, |
111 | | - np.linalg.inv(np.linalg.multi_dot([A, A.T])), |
112 | | - (fixval - d) |
| 115 | + np.linalg.inv(np.linalg.multi_dot([A, A.T])), (fixval - d) |
113 | 116 | ]) |
114 | 117 | saved_parameters[indices] = saved_parameters[indices] + deltax |
115 | 118 | self._load_parameters(saved_parameters) |
116 | 119 | self.ffd_mask = mask_bak.copy() |
117 | | - self.fixval=fixval_bak.copy() |
| 120 | + self.fixval = fixval_bak.copy() |
118 | 121 |
|
119 | 122 | def ffd(self, src_pts): |
120 | 123 | ''' |
@@ -182,7 +185,7 @@ def _compute_linear_map(self, src_pts, saved_parameters, indices): |
182 | 185 | A = sol[0].T[:, :-1] #coefficient |
183 | 186 | b = sol[0].T[:, -1] #intercept |
184 | 187 | return A, b |
185 | | - |
| 188 | + |
186 | 189 |
|
187 | 190 | class BFFD(CFFD): |
188 | 191 | ''' |
@@ -213,33 +216,27 @@ class BFFD(CFFD): |
213 | 216 | :Example: |
214 | 217 |
|
215 | 218 | >>> from pygem import BFFD |
216 | | - >>> import numpy as np |
217 | 219 | >>> b = np.random.rand(3) |
218 | 220 | >>> bffd = BFFD(b, [2, 2, 2]) |
219 | | - >>> bffd.read_parameters('tests/test_datasets/parameters_test_ffd_sphere.prm') |
220 | | - >>> original_mesh_points = np.load('tests/test_datasets/meshpoints_sphere_orig.npy') |
| 221 | + >>> bffd.read_parameters('tests/test_datasets/parameters_test_cffd') |
| 222 | + >>> original_mesh_points = np.random.rand(100, 3) |
221 | 223 | >>> bffd.adjust_control_points(original_mesh_points[:-4]) |
222 | 224 | >>> assert np.isclose(np.linalg.norm(bffd.fun(bffd.ffd(original_mesh_points[:-4])) - b), np.array([0.])) |
223 | | - >>> new_mesh_points = bffd.ffd(original_mesh_points) |
| 225 | + new_mesh_points = bffd.ffd(original_mesh_points) |
224 | 226 | ''' |
225 | 227 |
|
226 | | - def __init__(self, |
227 | | - fixval=None, |
228 | | - n_control_points=None, |
229 | | - ffd_mask=None): |
230 | | - super().__init__(fixval,None,n_control_points,ffd_mask,None) |
| 228 | + def __init__(self, fixval=None, n_control_points=None, ffd_mask=None): |
| 229 | + super().__init__(fixval, None, n_control_points, ffd_mask, None) |
231 | 230 |
|
232 | 231 | def linfun(x): |
233 | 232 | return np.mean(x.reshape(-1, 3), axis=0) |
234 | 233 |
|
235 | 234 | self.fun = linfun |
236 | 235 | self.fixval = fixval |
237 | | - self.fun_mask = np.array([[True, False, False], |
238 | | - [False, True, False], |
| 236 | + self.fun_mask = np.array([[True, False, False], [False, True, False], |
239 | 237 | [False, False, True]]) |
240 | 238 |
|
241 | 239 |
|
242 | | - |
243 | 240 | class VFFD(CFFD): |
244 | 241 | ''' |
245 | 242 | Class that handles the Volumetric Free Form Deformation on the mesh points. |
@@ -275,35 +272,33 @@ class VFFD(CFFD): |
275 | 272 | >>> from pygem import VFFD |
276 | 273 | >>> import numpy as np |
277 | 274 | >>> import meshio |
278 | | - >>> mesh = meshio.read('tests/test_datasets/test_sphere.stl') |
| 275 | + >>> mesh = meshio.read('tests/test_datasets/test_sphere_cffd.stl') |
279 | 276 | >>> original_mesh_points = mesh.points |
280 | 277 | >>> triangles = mesh.cells_dict["triangle"] |
281 | | - >>> b = np.random.rand() |
282 | | - >>> vffd = VFFD(triangles, b,[2, 2, 2]) |
283 | | - >>> vffd.read_parameters('tests/test_datasets/parameters_test_ffd_sphere.prm') |
| 278 | + >>> b = np.random.rand(1) |
| 279 | + >>> vffd = VFFD(triangles, b, [2, 2, 2]) |
| 280 | + >>> vffd.read_parameters('tests/test_datasets/parameters_test_cffd.prm') |
284 | 281 | >>> vffd.adjust_control_points(original_mesh_points) |
285 | 282 | >>> new_mesh_points = vffd(original_mesh_points) |
286 | | - >>> assert np.isclose(np.linalg.norm(vffd.fun(new_mesh_points) - b),np.array([0.]), atol=1e-07) |
| 283 | + >>> assert np.isclose(np.linalg.norm(vffd.fun(new_mesh_points) - b), np.array([0.]), atol=1e-07) |
287 | 284 |
|
288 | 285 | ''' |
| 286 | + def __init__(self, triangles, fixval, n_control_points=None, ffd_mask=None): |
| 287 | + super().__init__(fixval, None, n_control_points, ffd_mask, None) |
289 | 288 |
|
290 | | - def __init__(self, |
291 | | - triangles, |
292 | | - fixval, |
293 | | - n_control_points=None, |
294 | | - ffd_mask=None): |
295 | | - super().__init__(fixval,None,n_control_points,ffd_mask,None) |
| 289 | + self.triangles = triangles |
296 | 290 |
|
297 | | - self.triangles=triangles |
298 | 291 | def volume_inn(x): |
299 | | - return _volume(x,self.triangles) |
| 292 | + return _volume(x, self.triangles) |
300 | 293 |
|
301 | 294 | self.fun = volume_inn |
302 | | - self.fixval=fixval |
303 | | - self.fun_mask=np.array([[True, True, True]]) |
304 | | - |
305 | | -def _volume(x,triangles): |
| 295 | + self.fixval = fixval |
| 296 | + self.fun_mask = np.array([[True, True, True]]) |
| 297 | + |
| 298 | + |
| 299 | +def _volume(x, triangles): |
306 | 300 | x = x.reshape(-1, 3) |
307 | 301 | mesh = x[triangles] |
308 | 302 | return np.array([np.sum(np.linalg.det(mesh))]) |
309 | 303 |
|
| 304 | + |
0 commit comments