Skip to content

Commit 469de0d

Browse files
committed
reflection method for FFD lattice
1 parent 3676a3a commit 469de0d

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

pygem/params/ffdparams.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class FFDParameters(object):
6666
Four vertex (non coplanar) are sufficient to uniquely identify a
6767
parallelepiped.
6868
If the four vertex are coplanar, an assert is thrown when
69-
`affine_points_fit is used.
69+
`affine_points_fit` is used.
7070
7171
"""
7272

@@ -127,6 +127,64 @@ def position_vertices(self):
127127
self.rotation_matrix.dot(np.diag(self.lenght_box)).T
128128
])
129129

130+
131+
def reflect(self, axis=0):
132+
"""
133+
Reflect the lattice of control points along the direction defined
134+
by `axis`. In particular the origin point of the lattice is preserved.
135+
So, for instance, the reflection along x, is made with respect to the
136+
face of the lattice in the yz plane that is opposite to the origin.
137+
Same for the other directions. Only the weights (mu) along the chosen
138+
axis are reflected, while the others are preserved. The symmetry plane
139+
can not present deformations along the chosen axis.
140+
After the refletcion there will be 2n-1 control points along `axis`,
141+
witha doubled box length.
142+
143+
:param int axis: axis along which the reflection is performed.
144+
Default is 0. Possible values are 0, 1, or 2, corresponding
145+
to x, y, and z respectively.
146+
"""
147+
# check axis value
148+
if axis not in (0, 1, 2):
149+
raise ValueError("The axis has to be 0, 1, or 2. " + \
150+
"Current value {}.".format(axis))
151+
152+
# check that the plane of symmetry is undeformed
153+
if (axis == 0 and np.sum(self.array_mu_x[-1, :, :]) != 0) or \
154+
(axis == 1 and np.sum(self.array_mu_y[:, -1, :]) != 0) or \
155+
(axis == 2 and np.sum(self.array_mu_z[:, :, -1]) != 0):
156+
raise RuntimeError("If you want to reflect the FFD " + \
157+
"bounding box along axis {} ".format(axis) + \
158+
"you can not diplace the control points in the " + \
159+
"symmetry plane along that axis.")
160+
161+
# double the control points in the given axis minus 1 (the symmetry plane)
162+
self.n_control_points[axis] = 2 * self.n_control_points[axis] - 1
163+
# double the box length
164+
self.lenght_box[axis] *= 2
165+
166+
# we have to reflect the dispacements only along the correct axis
167+
reflection = np.ones(3)
168+
reflection[axis] = -1
169+
170+
# we need to select all the indeces but the ones in the plane of symmetry
171+
indeces = [slice(None), slice(None), slice(None)] # = [:, :, :]
172+
indeces[axis] = slice(1, None) # = [1:]
173+
indeces = tuple(indeces)
174+
175+
# we append along the given axis all the displacements reflected
176+
# and in the reverse order
177+
self.array_mu_x = np.append(self.array_mu_x,
178+
reflection[0] * np.flip(self.array_mu_x, axis)[indeces],
179+
axis=axis)
180+
self.array_mu_y = np.append(self.array_mu_y,
181+
reflection[1] * np.flip(self.array_mu_y, axis)[indeces],
182+
axis=axis)
183+
self.array_mu_z = np.append(self.array_mu_z,
184+
reflection[2] * np.flip(self.array_mu_z, axis)[indeces],
185+
axis=axis)
186+
187+
130188
def read_parameters(self, filename='parameters.prm'):
131189
"""
132190
Reads in the parameters file and fill the self structure.

0 commit comments

Comments
 (0)