diff --git a/pygem/params.py b/pygem/params.py index 92e9812..61586f3 100644 --- a/pygem/params.py +++ b/pygem/params.py @@ -1,5 +1,6 @@ """ -Utilities for reading and writing parameters files to perform the desired geometrical morphing. +Utilities for reading and writing parameters files to perform the desired +geometrical morphing. """ try: import configparser as configparser @@ -17,11 +18,11 @@ class FFDParameters(object): """ - Class that handles the Free Form Deformation parameters in terms of FFD bounding box and - weight of the FFD control points. + Class that handles the Free Form Deformation parameters in terms of FFD + bounding box and weight of the FFD control points. - :param list n_control_points: number of control points in the x, y, and z direction. - If not provided it is set to [2, 2, 2]. + :param list n_control_points: number of control points in the x, y, and z + direction. If not provided it is set to [2, 2, 2]. :cvar float length_box_x: length of the FFD bounding box in the x direction (local coordinate system). @@ -30,34 +31,43 @@ class FFDParameters(object): :cvar float length_box_z: length of the FFD bounding box in the z direction (local coordinate system). - :cvar numpy.ndarray origin_box: a 3-by-1 vector of float numbers representing the x, y and z - coordinates of the origin of the FFD bounding box. - - :cvar float rot_angle_x: rotation angle around x axis of the FFD bounding box. - :cvar float rot_angle_y: rotation angle around y axis of the FFD bounding box. - :cvar float rot_angle_z: rotation angle around z axis of the FFD bounding box. - - :cvar list n_control_points: list of 3 int representing the number of control points in the - x, y, and z direction. - - :cvar numpy.ndarray array_mu_x: collects the displacements (weights) along x, - normalized with the box lenght x. - :cvar numpy.ndarray array_mu_y: collects the displacements (weights) along y, - normalized with the box lenght y. - :cvar numpy.ndarray array_mu_z: collects the displacements (weights) along z, - normalized with the box lenght z. - - :cvar numpy.ndarray psi_mapping: map from the pysical domain to the reference domain. - :cvar numpy.ndarray inv_psi_mapping: map from the reference domain to the physical domain. - - :cvar numpy.ndarray rotation_matrix: rotation matrix (according to rot_angle_x, - rot_angle_y, rot_angle_z). - - :cvar numpy.ndarray position_vertex_0: position of the first vertex of the FFD bounding box. - It is always equal to the member `origin_box`. - :cvar numpy.ndarray position_vertex_1: position of the second vertex of the FFD bounding box. - :cvar numpy.ndarray position_vertex_2: position of the third vertex of the FFD bounding box. - :cvar numpy.ndarray position_vertex_3: position of the fourth vertex of the FFD bounding box. + :cvar numpy.ndarray origin_box: a 3-by-1 vector of float numbers + representing the x, y and z coordinates of the origin of the FFD + bounding box. + + :cvar float rot_angle_x: rotation angle around x axis of the FFD bounding + box. + :cvar float rot_angle_y: rotation angle around y axis of the FFD bounding + box. + :cvar float rot_angle_z: rotation angle around z axis of the FFD bounding + box. + + :cvar list n_control_points: list of 3 int representing the number of + control points in the x, y, and z direction. + + :cvar numpy.ndarray array_mu_x: collects the displacements (weights) along + x, normalized with the box lenght x. + :cvar numpy.ndarray array_mu_y: collects the displacements (weights) along + y, normalized with the box lenght y. + :cvar numpy.ndarray array_mu_z: collects the displacements (weights) along + z, normalized with the box lenght z. + + :cvar numpy.ndarray psi_mapping: map from the pysical domain to the + reference domain. + :cvar numpy.ndarray inv_psi_mapping: map from the reference domain to the + physical domain. + + :cvar numpy.ndarray rotation_matrix: rotation matrix (according to + rot_angle_x, rot_angle_y, rot_angle_z). + + :cvar numpy.ndarray position_vertex_0: position of the first vertex of the + FFD bounding box. It is always equal to the member `origin_box`. + :cvar numpy.ndarray position_vertex_1: position of the second vertex of the + FFD bounding box. + :cvar numpy.ndarray position_vertex_2: position of the third vertex of the + FFD bounding box. + :cvar numpy.ndarray position_vertex_3: position of the fourth vertex of the + FFD bounding box. :Example: from file @@ -82,38 +92,32 @@ class FFDParameters(object): >>> params3.build_bounding_box(shape) .. note:: - Four vertex (non coplanar) are sufficient to uniquely identify a parallelepiped. - If the four vertex are coplanar, an assert is thrown when affine_points_fit is used. + Four vertex (non coplanar) are sufficient to uniquely identify a + parallelepiped. + If the four vertex are coplanar, an assert is thrown when + affine_points_fit is used. """ def __init__(self, n_control_points=None): self.conversion_unit = 1. - self.lenght_box_x = 1. - self.lenght_box_y = 1. - self.lenght_box_z = 1. - + self.lenght_box = np.array([1., 1., 1.]) self.origin_box = np.array([0., 0., 0.]) - - self.rot_angle_x = 0. - self.rot_angle_y = 0. - self.rot_angle_z = 0. + self.rot_angle = np.array([0., 0., 0.]) if n_control_points is None: n_control_points = [2, 2, 2] - self.n_control_points = n_control_points + self.n_control_points = np.array(n_control_points) + - self.array_mu_x = np.zeros((self.n_control_points[0], self.n_control_points[1], \ - self.n_control_points[2])) - self.array_mu_y = np.zeros((self.n_control_points[0], self.n_control_points[1], \ - self.n_control_points[2])) - self.array_mu_z = np.zeros((self.n_control_points[0], self.n_control_points[1], \ - self.n_control_points[2])) + self.array_mu_x = np.zeros(self.n_control_points) + self.array_mu_y = np.zeros(self.n_control_points) + self.array_mu_z = np.zeros(self.n_control_points) - self.psi_mapping = np.diag([1./self.lenght_box_x, 1./self.lenght_box_y, 1./self.lenght_box_z]) - self.inv_psi_mapping = np.diag([self.lenght_box_x, self.lenght_box_y, self.lenght_box_z]) + self.psi_mapping = np.diag(1. / self.lenght_box) + self.inv_psi_mapping = np.diag(self.lenght_box) - self.rotation_matrix = np.eye(3) + self.rotation_matrix = np.eye(3) self.position_vertex_0 = self.origin_box self.position_vertex_1 = np.array([1., 0., 0.]) self.position_vertex_2 = np.array([0., 1., 0.]) @@ -129,7 +133,8 @@ def read_parameters(self, filename='parameters.prm'): if not isinstance(filename, str): raise TypeError("filename must be a string") - # Checks if the parameters file exists. If not it writes the default class into filename. + # Checks if the parameters file exists. If not it writes the default + # class into filename. if not os.path.isfile(filename): self.write_parameters(filename) return @@ -141,194 +146,193 @@ def read_parameters(self, filename='parameters.prm'): self.n_control_points[1] = config.getint('Box info', 'n control points y') self.n_control_points[2] = config.getint('Box info', 'n control points z') - self.lenght_box_x = config.getfloat('Box info', 'box lenght x') - self.lenght_box_y = config.getfloat('Box info', 'box lenght y') - self.lenght_box_z = config.getfloat('Box info', 'box lenght z') + self.lenght_box[0] = config.getfloat('Box info', 'box lenght x') + self.lenght_box[1] = config.getfloat('Box info', 'box lenght y') + self.lenght_box[2] = config.getfloat('Box info', 'box lenght z') - origin_box_x = config.getfloat('Box info', 'box origin x') - origin_box_y = config.getfloat('Box info', 'box origin y') - origin_box_z = config.getfloat('Box info', 'box origin z') - self.origin_box = np.array([origin_box_x, origin_box_y, origin_box_z]) + self.origin_box[0] = config.getfloat('Box info', 'box origin x') + self.origin_box[1] = config.getfloat('Box info', 'box origin y') + self.origin_box[2] = config.getfloat('Box info', 'box origin z') - self.rot_angle_x = config.getfloat('Box info', 'rotation angle x') - self.rot_angle_y = config.getfloat('Box info', 'rotation angle y') - self.rot_angle_z = config.getfloat('Box info', 'rotation angle z') + self.rot_angle[0] = config.getfloat('Box info', 'rotation angle x') + self.rot_angle[1] = config.getfloat('Box info', 'rotation angle y') + self.rot_angle[2] = config.getfloat('Box info', 'rotation angle z') - self.array_mu_x = np.zeros((self.n_control_points[0], self.n_control_points[1], \ - self.n_control_points[2])) - mux = config.get('Parameters weights', 'parameter x') - lines = mux.split('\n') - for line in lines: - values = line.split() - self.array_mu_x[int(values[0])][int(values[1])][int(values[2])] = float(values[3]) + self.array_mu_x = np.zeros(self.n_control_points) + self.array_mu_y = np.zeros(self.n_control_points) + self.array_mu_z = np.zeros(self.n_control_points) - self.array_mu_y = np.zeros((self.n_control_points[0], self.n_control_points[1], \ - self.n_control_points[2])) + mux = config.get('Parameters weights', 'parameter x') muy = config.get('Parameters weights', 'parameter y') - lines = muy.split('\n') - for line in lines: + muz = config.get('Parameters weights', 'parameter z') + + for line in mux.split('\n'): + values = np.array(line.split()) + self.array_mu_x[tuple(map(int, values[0:3]))] = float(values[3]) + + for line in muy.split('\n'): values = line.split() - self.array_mu_y[int(values[0])][int(values[1])][int(values[2])] = float(values[3]) + self.array_mu_y[tuple(map(int, values[0:3]))] = float(values[3]) - self.array_mu_z = np.zeros((self.n_control_points[0], self.n_control_points[1], \ - self.n_control_points[2])) - muz = config.get('Parameters weights', 'parameter z') - lines = muz.split('\n') - for line in lines: + for line in muz.split('\n'): values = line.split() - self.array_mu_z[int(values[0])][int(values[1])][int(values[2])] = float(values[3]) + self.array_mu_z[tuple(map(int, values[0:3]))] = float(values[3]) - self.rotation_matrix = at.angles2matrix(self.rot_angle_z * np.pi/180, \ - self.rot_angle_y * np.pi/180, self.rot_angle_x * np.pi/180) + self.rotation_matrix = at.angles2matrix( + self.rot_angle[2] * np.pi / 180, + self.rot_angle[1] * np.pi / 180, + self.rot_angle[0] * np.pi / 180 + ) self.position_vertex_0 = self.origin_box self.position_vertex_1 = self.position_vertex_0 + \ - np.dot(self.rotation_matrix, [self.lenght_box_x, 0, 0]) + np.dot(self.rotation_matrix, [self.lenght_box[0], 0, 0]) self.position_vertex_2 = self.position_vertex_0 + \ - np.dot(self.rotation_matrix, [0, self.lenght_box_y, 0]) + np.dot(self.rotation_matrix, [0, self.lenght_box[1], 0]) self.position_vertex_3 = self.position_vertex_0 + \ - np.dot(self.rotation_matrix, [0, 0, self.lenght_box_z]) + np.dot(self.rotation_matrix, [0, 0, self.lenght_box[2]]) - self.psi_mapping = np.diag([1./self.lenght_box_x, 1./self.lenght_box_y, 1./self.lenght_box_z]) - self.inv_psi_mapping = np.diag([self.lenght_box_x, self.lenght_box_y, self.lenght_box_z]) + self.psi_mapping = np.diag(1. / self.lenght_box) + self.inv_psi_mapping = np.diag(self.lenght_box) def write_parameters(self, filename='parameters.prm'): """ - This method writes a parameters file (.prm) called `filename` and fills it with all - the parameters class members. + This method writes a parameters file (.prm) called `filename` and fills + it with all the parameters class members. :param string filename: parameters file to be written out. """ if not isinstance(filename, str): raise TypeError("filename must be a string") - with open(filename, 'w') as output_file: - output_file.write('\n[Box info]\n') - output_file.write('# This section collects all the properties of the FFD bounding box.\n') - - output_file.write('\n# n control points indicates the number of control points in each direction (x, y, z).\n') - output_file.write('# For example, to create a 2 x 3 x 2 grid, use the following: n control points: 2, 3, 2\n') - output_file.write('n control points x: ' + str(self.n_control_points[0]) + '\n') - output_file.write('n control points y: ' + str(self.n_control_points[1]) + '\n') - output_file.write('n control points z: ' + str(self.n_control_points[2]) + '\n') - - output_file.write('\n# box lenght indicates the length of the FFD bounding box along the three canonical directions (x, y, z).\n') - output_file.write('# It uses the local coordinate system.\n') - output_file.write('# For example to create a 2 x 1.5 x 3 meters box use the following: lenght box: 2.0, 1.5, 3.0\n') - output_file.write('box lenght x: ' + str(self.lenght_box_x) + '\n') - output_file.write('box lenght y: ' + str(self.lenght_box_y) + '\n') - output_file.write('box lenght z: ' + str(self.lenght_box_z) + '\n') - - output_file.write('\n# box origin indicates the x, y, and z coordinates of the origin of the FFD bounding box. That is center of\n') - output_file.write('# rotation of the bounding box. It corresponds to the point coordinates with position [0][0][0].\n') - output_file.write('# See section "Parameters weights" for more details.\n') - output_file.write('# For example, if the origin is equal to 0., 0., 0., use the following: origin box: 0., 0., 0.\n') - output_file.write('box origin x: ' + str(self.origin_box[0]) + '\n') - output_file.write('box origin y: ' + str(self.origin_box[1]) + '\n') - output_file.write('box origin z: ' + str(self.origin_box[2]) + '\n') - - output_file.write('\n# rotation angle indicates the rotation angle around the x, y, and z axis of the FFD bounding box in degrees.\n') - output_file.write('# The rotation is done with respect to the box origin.\n') - output_file.write('# For example, to rotate the box by 2 deg along the z direction, use the following: rotation angle: 0., 0., 2.\n') - output_file.write('rotation angle x: ' + str(self.rot_angle_x) + '\n') - output_file.write('rotation angle y: ' + str(self.rot_angle_y) + '\n') - output_file.write('rotation angle z: ' + str(self.rot_angle_z) + '\n') - - output_file.write('\n\n[Parameters weights]\n') - output_file.write('# This section describes the weights of the FFD control points.\n') - output_file.write('# We adopt the following convention:\n') - output_file.write('# For example with a 2x2x2 grid of control points we have to fill a 2x2x2 matrix of weights.\n') - output_file.write('# If a weight is equal to zero you can discard the line since the default is zero.\n') - output_file.write('#\n') - output_file.write('# | x index | y index | z index | weight |\n') - output_file.write('# --------------------------------------\n') - output_file.write('# | 0 | 0 | 0 | 1.0 |\n') - output_file.write('# | 0 | 1 | 1 | 0.0 | --> you can erase this line without effects\n') - output_file.write('# | 0 | 1 | 0 | -2.1 |\n') - output_file.write('# | 0 | 0 | 1 | 3.4 |\n') - - output_file.write('\n# parameter x collects the displacements along x, normalized with the box lenght x.') - output_file.write('\nparameter x:') - offset = 1 - for i in range(0, self.n_control_points[0]): - for j in range(0, self.n_control_points[1]): - for k in range(0, self.n_control_points[2]): - output_file.write(offset * ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + \ - ' ' + str(self.array_mu_x[i][j][k]) + '\n') - offset = 13 - - output_file.write('\n# parameter y collects the displacements along y, normalized with the box lenght y.') - output_file.write('\nparameter y:') - offset = 1 - for i in range(0, self.n_control_points[0]): - for j in range(0, self.n_control_points[1]): - for k in range(0, self.n_control_points[2]): - output_file.write(offset * ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + \ - ' ' + str(self.array_mu_y[i][j][k]) + '\n') - offset = 13 - - output_file.write('\n# parameter z collects the displacements along z, normalized with the box lenght z.') - output_file.write('\nparameter z:') - offset = 1 - for i in range(0, self.n_control_points[0]): - for j in range(0, self.n_control_points[1]): - for k in range(0, self.n_control_points[2]): - output_file.write(offset * ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + \ - ' ' + str(self.array_mu_z[i][j][k]) + '\n') - offset = 13 - - - def print_info(self): + output_string = "" + output_string += '\n[Box info]\n' + output_string += '# This section collects all the properties of the' + output_string += ' FFD bounding box.\n' + + output_string += '\n# n control points indicates the number of control' + output_string += ' points in each direction (x, y, z).\n' + output_string += '# For example, to create a 2 x 3 x 2 grid, use the' + output_string += ' following: n control points: 2, 3, 2\n' + output_string += 'n control points x: ' + str(self.n_control_points[0]) + '\n' + output_string += 'n control points y: ' + str(self.n_control_points[1]) + '\n' + output_string += 'n control points z: ' + str(self.n_control_points[2]) + '\n' + + output_string += '\n# box lenght indicates the length of the FFD bounding box along the three canonical directions (x, y, z).\n' + output_string += '# It uses the local coordinate system.\n' + output_string += '# For example to create a 2 x 1.5 x 3 meters box use the following: lenght box: 2.0, 1.5, 3.0\n' + output_string += 'box lenght x: ' + str(self.lenght_box[0]) + '\n' + output_string += 'box lenght y: ' + str(self.lenght_box[1]) + '\n' + output_string += 'box lenght z: ' + str(self.lenght_box[2]) + '\n' + + output_string += '\n# box origin indicates the x, y, and z coordinates of the origin of the FFD bounding box. That is center of\n' + output_string += '# rotation of the bounding box. It corresponds to the point coordinates with position [0][0][0].\n' + output_string += '# See section "Parameters weights" for more details.\n' + output_string += '# For example, if the origin is equal to 0., 0., 0., use the following: origin box: 0., 0., 0.\n' + output_string += 'box origin x: ' + str(self.origin_box[0]) + '\n' + output_string += 'box origin y: ' + str(self.origin_box[1]) + '\n' + output_string += 'box origin z: ' + str(self.origin_box[2]) + '\n' + + output_string += '\n# rotation angle indicates the rotation angle around the x, y, and z axis of the FFD bounding box in degrees.\n' + output_string += '# The rotation is done with respect to the box origin.\n' + output_string += '# For example, to rotate the box by 2 deg along the z direction, use the following: rotation angle: 0., 0., 2.\n' + output_string += 'rotation angle x: ' + str(self.rot_angle[0]) + '\n' + output_string += 'rotation angle y: ' + str(self.rot_angle[1]) + '\n' + output_string += 'rotation angle z: ' + str(self.rot_angle[2]) + '\n' + + output_string += '\n\n[Parameters weights]\n' + output_string += '# This section describes the weights of the FFD control points.\n' + output_string += '# We adopt the following convention:\n' + output_string += '# For example with a 2x2x2 grid of control points we have to fill a 2x2x2 matrix of weights.\n' + output_string += '# If a weight is equal to zero you can discard the line since the default is zero.\n' + output_string += '#\n' + output_string += '# | x index | y index | z index | weight |\n' + output_string += '# --------------------------------------\n' + output_string += '# | 0 | 0 | 0 | 1.0 |\n' + output_string += '# | 0 | 1 | 1 | 0.0 | --> you can erase this line without effects\n' + output_string += '# | 0 | 1 | 0 | -2.1 |\n' + output_string += '# | 0 | 0 | 1 | 3.4 |\n' + + output_string += '\n# parameter x collects the displacements along x, normalized with the box lenght x.' + output_string += '\nparameter x:' + offset = 1 + for i in range(0, self.n_control_points[0]): + for j in range(0, self.n_control_points[1]): + for k in range(0, self.n_control_points[2]): + output_string += offset * ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + \ + ' ' + str(self.array_mu_x[i][j][k]) + '\n' + offset = 13 + + output_string += '\n# parameter y collects the displacements along y, normalized with the box lenght y.' + output_string += '\nparameter y:' + offset = 1 + for i in range(0, self.n_control_points[0]): + for j in range(0, self.n_control_points[1]): + for k in range(0, self.n_control_points[2]): + output_string += offset * ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + \ + ' ' + str(self.array_mu_y[i][j][k]) + '\n' + offset = 13 + + output_string += '\n# parameter z collects the displacements along z, normalized with the box lenght z.' + output_string += '\nparameter z:' + offset = 1 + for i in range(0, self.n_control_points[0]): + for j in range(0, self.n_control_points[1]): + for k in range(0, self.n_control_points[2]): + output_string += offset * ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + \ + ' ' + str(self.array_mu_z[i][j][k]) + '\n' + offset = 13 + + with open(filename, 'w') as f: + f.write(output_string) + + + def __str__(self): """ - This method prints all the FFD parameters on the screen. Its purpose is for debugging. + This method prints all the FFD parameters on the screen. Its purpose is + for debugging. """ - print('conversion_unit = ' + str(self.conversion_unit) + '\n') - print('(lenght_box_x, lenght_box_y, lenght_box_z) = (' + str(self.lenght_box_x) + \ - ', ' + str(self.lenght_box_y) + ', ' + str(self.lenght_box_z) + ')') - print('origin_box = ' + str(self.origin_box)) - print('n_control_points = ' + str(self.n_control_points)) - print('(rot_angle_x, rot_angle_y, rot_angle_z) = (' + str(self.rot_angle_x) + \ - ', ' + str(self.rot_angle_y) + ', ' + str(self.rot_angle_z) + ')') - print('\narray_mu_x =') - print(self.array_mu_x) - print('\narray_mu_y =') - print(self.array_mu_y) - print('\narray_mu_z =') - print(self.array_mu_z) - print('\npsi_mapping =') - print(self.psi_mapping) - print('\ninv_psi_mapping =') - print(self.inv_psi_mapping) - print('\nrotation_matrix =') - print(self.rotation_matrix) - print('\nposition_vertex_0 =') - print(self.position_vertex_0) - print('\nposition_vertex_1 =') - print(self.position_vertex_1) - print('\nposition_vertex_2 =') - print(self.position_vertex_2) - print('\nposition_vertex_3 =') - print(self.position_vertex_3) + string = "" + string += 'conversion_unit = {}\n'.format(self.conversion_unit) + string += 'n_control_points = {}\n\n'.format(self.n_control_points) + string += 'lenght_box = {}\n'.format(self.lenght_box) + string += 'origin_box = {}\n'.format(self.origin_box) + string += 'rot_angle = {}\n'.format(self.rot_angle) + string += '\narray_mu_x =\n{}\n'.format(self.array_mu_x) + string += '\narray_mu_y =\n{}\n'.format(self.array_mu_y) + string += '\narray_mu_z =\n{}\n'.format(self.array_mu_z) + string += '\npsi_mapping = \n{}\n'.format(self.psi_mapping) + string += '\nrotation_matrix = \n{}\n'.format(self.rotation_matrix) + string += '\nposition_vertex_0 = {}\n'.format(self.position_vertex_0) + string += 'position_vertex_1 = {}\n'.format(self.position_vertex_1) + string += 'position_vertex_2 = {}\n'.format(self.position_vertex_2) + string += 'position_vertex_3 = {}\n'.format(self.position_vertex_3) + return string def build_bounding_box(self, shape, tol=1e-6, triangulate=False, triangulate_tol=1e-1): """ - Builds a bounding box around the given shape. ALl parameters (with the exception of array_mu_x/y/z) - are set to match the computed box. + Builds a bounding box around the given shape. ALl parameters (with the + exception of array_mu_x/y/z) are set to match the computed box. - :param TopoDS_Shape shape: or a subclass such as TopoDS_Face - the shape to compute the bounding box from + :param TopoDS_Shape shape: or a subclass such as TopoDS_Face the shape + to compute the bounding box from :param float tol: tolerance of the computed bounding box - :param bool triangulate: Should shape be triangulated before the boudning box is created. + :param bool triangulate: Should shape be triangulated before the + boudning box is created. - If ``True`` only the dimensions of the bb will take into account every part of the shape (also not *visible*) + If ``True`` only the dimensions of the bb will take into account + every part of the shape (also not *visible*) If ``False`` only the *visible* part is taken into account - *Explanation:* every UV-Surface has to be rectangular. When a solid is created surfaces are trimmed. - the trimmed part, however, is still saved inside a file. It is just *invisible* when drawn in a program + *Explanation:* every UV-Surface has to be rectangular. When a solid + is created surfaces are trimmed. the trimmed part, however, is + still saved inside a file. It is just *invisible* when drawn in a + program - :param float triangulate_tol: tolerance of triangulation (size of created triangles) + :param float triangulate_tol: tolerance of triangulation (size of + created triangles) """ min_xyz, max_xyz = self._calculate_bb_dimension(shape, tol, triangulate, triangulate_tol) self.origin_box = min_xyz @@ -491,8 +495,9 @@ def read_parameters(self, filename='parameters_rbf.prm'): def write_parameters(self, filename='parameters_rbf.prm'): """ - This method writes a parameters file (.prm) called `filename` and fills it with all - the parameters class members. Default value is parameters_rbf.prm. + This method writes a parameters file (.prm) called `filename` and fills + it with all the parameters class members. Default value is + parameters_rbf.prm. :param string filename: parameters file to be written out. """ @@ -539,14 +544,16 @@ def write_parameters(self, filename='parameters_rbf.prm'): offset = 25 - def print_info(self): + def __str__(self): """ - This method prints all the RBF parameters on the screen. Its purpose is for debugging. + This method prints all the RBF parameters on the screen. Its purpose is + for debugging. """ - print('basis function = ' + str(self.basis)) - print('radius = ' + str(self.radius)) - print('n_control_points = ' + str(self.n_control_points)) - print('\noriginal_control_points =') - print(self.original_control_points) - print('\ndeformed_control_points =') - print(self.deformed_control_points) + string = '' + string += 'basis function = {}\n'.format(self.basis) + string += 'radius = {}\n'.format(self.radius) + string += '\noriginal control points =\n' + string += '{}\n'.format(self.original_control_points) + string += '\ndeformed control points =\n' + string += '{}\n'.format(self.deformed_control_points) + return string diff --git a/pygem/utils.py b/pygem/utils.py index f01c9f6..b568822 100644 --- a/pygem/utils.py +++ b/pygem/utils.py @@ -8,15 +8,16 @@ def write_bounding_box(parameters, outfile, write_deformed=True): """ - Method that writes a vtk file containing the FFD lattice. This method - allows to visualize where the FFD control points are located before the geometrical morphing. - If the `write_deformed` flag is set to True the method writes out the deformed lattice, otherwise - it writes one the original undeformed lattice. + Method that writes a vtk file containing the FFD lattice. This method allows + to visualize where the FFD control points are located before the geometrical + morphing. If the `write_deformed` flag is set to True the method writes out + the deformed lattice, otherwise it writes one the original undeformed + lattice. :param FFDParameters parameters: parameters of the Free Form Deformation. :param string outfile: name of the output file. - :param bool write_deformed: flag to write the original or modified FFD control lattice. - The default is set to True. + :param bool write_deformed: flag to write the original or modified FFD + control lattice. The default is set to True. :Example: @@ -29,13 +30,13 @@ def write_bounding_box(parameters, outfile, write_deformed=True): >>> ut.write_bounding_box(params, 'tests/test_datasets/box_test_sphere.vtk') """ aux_x = np.linspace( - 0, parameters.lenght_box_x, parameters.n_control_points[0] + 0, parameters.lenght_box[0], parameters.n_control_points[0] ) aux_y = np.linspace( - 0, parameters.lenght_box_y, parameters.n_control_points[1] + 0, parameters.lenght_box[1], parameters.n_control_points[1] ) aux_z = np.linspace( - 0, parameters.lenght_box_z, parameters.n_control_points[2] + 0, parameters.lenght_box[2], parameters.n_control_points[2] ) lattice_y_coords, lattice_x_coords, lattice_z_coords = np.meshgrid( aux_y, aux_x, aux_z @@ -43,9 +44,9 @@ def write_bounding_box(parameters, outfile, write_deformed=True): if write_deformed: box_points = np.array([ \ - lattice_x_coords.ravel() + parameters.array_mu_x.ravel() * parameters.lenght_box_x, \ - lattice_y_coords.ravel() + parameters.array_mu_y.ravel() * parameters.lenght_box_y, \ - lattice_z_coords.ravel() + parameters.array_mu_z.ravel() * parameters.lenght_box_z]) + lattice_x_coords.ravel() + parameters.array_mu_x.ravel() * parameters.lenght_box[0], \ + lattice_y_coords.ravel() + parameters.array_mu_y.ravel() * parameters.lenght_box[1], \ + lattice_z_coords.ravel() + parameters.array_mu_z.ravel() * parameters.lenght_box[2]]) else: box_points = np.array([lattice_x_coords.ravel(), lattice_y_coords.ravel(), \ lattice_z_coords.ravel()]) diff --git a/tests/test_ffdparams.py b/tests/test_ffdparams.py index 11559c5..57adc1d 100644 --- a/tests/test_ffdparams.py +++ b/tests/test_ffdparams.py @@ -13,39 +13,23 @@ class TestFFDParameters(TestCase): def test_class_members_default_n_control_points(self): params = ffdp.FFDParameters() - assert params.n_control_points == [2, 2, 2] + assert np.array_equal(params.n_control_points, [2, 2, 2]) def test_class_members_default_conversion_unit(self): params = ffdp.FFDParameters() assert params.conversion_unit == 1. - def test_class_members_default_lenght_box_x(self): + def test_class_members_default_lenght_box(self): params = ffdp.FFDParameters() - assert params.lenght_box_x == 1. - - def test_class_members_default_lenght_box_y(self): - params = ffdp.FFDParameters() - assert params.lenght_box_y == 1. - - def test_class_members_default_lenght_box_z(self): - params = ffdp.FFDParameters() - assert params.lenght_box_z == 1. + assert np.array_equal(params.lenght_box, np.ones(3)) def test_class_members_default_origin_box(self): params = ffdp.FFDParameters() - np.testing.assert_array_almost_equal(params.origin_box, np.zeros(3)) - - def test_class_members_default_rot_angle_x(self): - params = ffdp.FFDParameters() - assert params.rot_angle_x == 0 - - def test_class_members_default_rot_angle_y(self): - params = ffdp.FFDParameters() - assert params.rot_angle_y == 0 + assert np.array_equal(params.origin_box, np.zeros(3)) - def test_class_members_default_rot_angle_z(self): + def test_class_members_default_rot_angle(self): params = ffdp.FFDParameters() - assert params.rot_angle_z == 0 + assert np.array_equal(params.rot_angle, np.zeros(3)) def test_class_members_default_array_mu_x(self): params = ffdp.FFDParameters() @@ -107,7 +91,7 @@ def test_class_members_default_position_vertex_3(self): def test_class_members_generic_n_control_points(self): params = ffdp.FFDParameters([2, 3, 5]) - assert params.n_control_points == [2, 3, 5] + assert np.array_equal(params.n_control_points, [2, 3, 5]) def test_class_members_generic_array_mu_x(self): params = ffdp.FFDParameters([2, 3, 5]) @@ -135,22 +119,12 @@ def test_read_parameters_conversion_unit(self): def test_read_parameters_n_control_points(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.n_control_points == [3, 2, 2] + assert np.array_equal(params.n_control_points, [3, 2, 2]) def test_read_parameters_lenght_box_x(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.lenght_box_x == 45.0 - - def test_read_parameters_lenght_box_y(self): - params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) - params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.lenght_box_y == 90.0 - - def test_read_parameters_lenght_box_z(self): - params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) - params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.lenght_box_z == 90.0 + assert np.array_equal(params.lenght_box, [45.0, 90.0, 90.0]) def test_read_parameters_origin_box(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) @@ -163,17 +137,7 @@ def test_read_parameters_origin_box(self): def test_read_parameters_rot_angle_x(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.rot_angle_x == 20.3 - - def test_read_parameters_rot_angle_y(self): - params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) - params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.rot_angle_y == 11.0 - - def test_read_parameters_rot_angle_z(self): - params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) - params.read_parameters('tests/test_datasets/parameters_sphere.prm') - assert params.rot_angle_z == 0. + assert np.array_equal(params.rot_angle, [20.3, 11.0, 0.]) def test_read_parameters_array_mu_x(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) @@ -181,6 +145,7 @@ def test_read_parameters_array_mu_x(self): array_mu_x_exact = np.array( [0.2, 0., 0., 0., 0.5, 0., 0., 0., 1., 0., 0., 0.] ).reshape((3, 2, 2)) + print(params.array_mu_x) np.testing.assert_array_almost_equal( params.array_mu_x, array_mu_x_exact ) @@ -225,8 +190,10 @@ def test_read_parameters_rotation_matrix(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) params.read_parameters('tests/test_datasets/parameters_sphere.prm') rotation_matrix_exact = np.array([ - 0.98162718, 0., 0.190809, 0.06619844, 0.93788893, -0.34056147, -0.17895765, 0.34693565, 0.92065727 - ]).reshape((3, 3)) + [ 0.98162718, 0. , 0.190809 ], + [ 0.06619844, 0.93788893, -0.34056147], + [-0.17895765, 0.34693565, 0.92065727] + ]) np.testing.assert_array_almost_equal( params.rotation_matrix, rotation_matrix_exact ) @@ -329,7 +296,7 @@ def test_write_parameters(self): def test_print_info(self): params = ffdp.FFDParameters(n_control_points=[3, 2, 2]) - params.print_info() + print(params) def test_build_bounding_box(self): origin = np.array([0., 0., 0.]) diff --git a/tests/test_rbfparams.py b/tests/test_rbfparams.py index 882f191..ade6a8f 100644 --- a/tests/test_rbfparams.py +++ b/tests/test_rbfparams.py @@ -131,4 +131,4 @@ def test_write_parameters(self): def test_print_info(self): params = rbfp.RBFParameters() - params.print_info() + print(params)