diff --git a/pygem/filehandler.py b/pygem/filehandler.py index 3b6c6ce..63c1175 100644 --- a/pygem/filehandler.py +++ b/pygem/filehandler.py @@ -50,8 +50,8 @@ def _check_extension(self, filename): if file_ext not in self.extensions: raise ValueError( 'The input file does not have the proper extension. \ - It is {0!s}, instead of {1!s}.' - .format(file_ext, self.extensions)) + It is {0!s}, instead of {1!s}.'.format(file_ext, + self.extensions)) @staticmethod def _check_filename_type(filename): diff --git a/pygem/freeform.py b/pygem/freeform.py index 55686b7..4321b03 100644 --- a/pygem/freeform.py +++ b/pygem/freeform.py @@ -98,13 +98,13 @@ def perform(self): self.original_mesh_points - translation, transformation) # select mesh points inside bounding box - mesh_points = reference_frame_mesh_points[( - reference_frame_mesh_points[:, 0] >= 0.) & ( - reference_frame_mesh_points[:, 0] <= 1.) & ( - reference_frame_mesh_points[:, 1] >= 0.) & ( - reference_frame_mesh_points[:, 1] <= 1.) & ( - reference_frame_mesh_points[:, 2] >= 0.) & ( - reference_frame_mesh_points[:, 2] <= 1.)] + mesh_points = reference_frame_mesh_points[ + (reference_frame_mesh_points[:, 0] >= 0.) + & (reference_frame_mesh_points[:, 0] <= 1.) & + (reference_frame_mesh_points[:, 1] >= 0.) & + (reference_frame_mesh_points[:, 1] <= 1.) & + (reference_frame_mesh_points[:, 2] >= 0.) & + (reference_frame_mesh_points[:, 2] <= 1.)] (n_rows_mesh, n_cols_mesh) = mesh_points.shape # Initialization. In order to exploit the contiguity in memory the @@ -156,12 +156,13 @@ def perform(self): # merge non-shifted mesh points with shifted ones self.modified_mesh_points = np.copy(self.original_mesh_points) - self.modified_mesh_points[(reference_frame_mesh_points[:, 0] >= 0.) & ( - reference_frame_mesh_points[:, 0] <= 1. - ) & (reference_frame_mesh_points[:, 1] >= 0.) & ( - reference_frame_mesh_points[:, 1] <= 1.) & ( - reference_frame_mesh_points[:, 2] >= 0.) & ( - reference_frame_mesh_points[:, 2] <= 1.)] = new_mesh_points + self.modified_mesh_points[(reference_frame_mesh_points[:, 0] >= 0.) + & (reference_frame_mesh_points[:, 0] <= 1.) & + (reference_frame_mesh_points[:, 1] >= 0.) & + (reference_frame_mesh_points[:, 1] <= 1.) & + (reference_frame_mesh_points[:, 2] >= 0.) & + (reference_frame_mesh_points[:, 2] <= + 1.)] = new_mesh_points @staticmethod def _transform_points(original_points, transformation): diff --git a/pygem/nurbshandler.py b/pygem/nurbshandler.py index 24909b7..9329276 100644 --- a/pygem/nurbshandler.py +++ b/pygem/nurbshandler.py @@ -79,9 +79,9 @@ def load_shape_from_file(self, filename): Not implemented, it has to be implemented in subclasses. """ - raise NotImplementedError('Subclass must implement abstract method ' + - self.__class__.__name__ + - '.load_shape_from_file') + raise NotImplementedError( + 'Subclass must implement abstract method ' + + self.__class__.__name__ + '.load_shape_from_file') def parse(self, filename): """ @@ -138,8 +138,8 @@ def parse(self, filename): # pushing the control points coordinates to the mesh_points array (used for FFD) mesh_points = np.append( mesh_points, control_polygon_coordinates, axis=0) - control_point_position.append(control_point_position[-1] + n_poles_u - * n_poles_v) + control_point_position.append( + control_point_position[-1] + n_poles_u * n_poles_v) n_faces += 1 faces_explorer.Next() @@ -299,8 +299,8 @@ def parse_face(topo_face): bspline_converter = BRepBuilderAPI_NurbsConvert(edge) bspline_converter.Perform(edge) bspline_tshape_edge = bspline_converter.Shape() - h_geom_edge = BRep_Tool_Curve(topods_Edge(bspline_tshape_edge))[ - 0] + h_geom_edge = BRep_Tool_Curve( + topods_Edge(bspline_tshape_edge))[0] h_bspline_edge = geomconvert_CurveToBSplineCurve(h_geom_edge) bspline_geom_edge = h_bspline_edge.GetObject() @@ -314,7 +314,9 @@ def parse_face(topo_face): for i in range(1, nb_poles + 1): ctrlpt = edge_ctrlpts.Value(i) ctrlpt_position = np.array( - [[ctrlpt.Coord(1), ctrlpt.Coord(2), ctrlpt.Coord(3)]]) + [[ctrlpt.Coord(1), + ctrlpt.Coord(2), + ctrlpt.Coord(3)]]) points_single_edge = np.append( points_single_edge, ctrlpt_position, axis=0) @@ -342,8 +344,10 @@ def parse_face(topo_face): for indice_u_direction in range(1, nb_u + 1): for indice_v_direction in range(1, nb_v + 1): ctrlpt = ctrlpts.Value(indice_u_direction, indice_v_direction) - ctrlpt_position = np.array([[ctrlpt.Coord(1), ctrlpt.Coord(2), - ctrlpt.Coord(3)]]) + ctrlpt_position = np.array( + [[ctrlpt.Coord(1), + ctrlpt.Coord(2), + ctrlpt.Coord(3)]]) mesh_points_face = np.append( mesh_points_face, ctrlpt_position, axis=0) @@ -548,8 +552,8 @@ def write_face(self, points_face, list_points_edge, topo_face, toledge): stol.SetTolerance(new_edge_toadd, toledge * 10.0) new_bspline_twire.Add(new_edge_toadd) else: - deformed_edge_revers = deformed_edges[np.abs( - deformed_edge_i) - 1] + deformed_edge_revers = deformed_edges[ + np.abs(deformed_edge_i) - 1] stol.SetTolerance(deformed_edge_revers, toledge) new_bspline_twire.Add(deformed_edge_revers) if new_bspline_twire.Error() != 0: diff --git a/pygem/params/ffdparams.py b/pygem/params/ffdparams.py index 0c43b18..457c3bf 100644 --- a/pygem/params/ffdparams.py +++ b/pygem/params/ffdparams.py @@ -123,8 +123,8 @@ def position_vertices(self): :rtype: numpy.ndarray """ return self.origin_box + np.vstack([ - np.zeros( - (1, 3)), self.rotation_matrix.dot(np.diag(self.lenght_box)).T + np.zeros((1, 3)), + self.rotation_matrix.dot(np.diag(self.lenght_box)).T ]) def read_parameters(self, filename='parameters.prm'): @@ -203,12 +203,12 @@ def write_parameters(self, filename='parameters.prm'): 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 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 ' output_string += 'bounding box along the three canonical directions ' @@ -282,8 +282,8 @@ def write_parameters(self, filename='parameters.prm'): 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' + j) + ' ' + str(k) + ' ' + str( + self.array_mu_x[i][j][k]) + '\n' offset = 13 output_string += '\n# parameter y collects the displacements along y, ' @@ -295,8 +295,8 @@ def write_parameters(self, filename='parameters.prm'): 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' + j) + ' ' + str(k) + ' ' + str( + self.array_mu_y[i][j][k]) + '\n' offset = 13 output_string += '\n# parameter z collects the displacements along z, ' @@ -308,8 +308,8 @@ def write_parameters(self, filename='parameters.prm'): 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' + j) + ' ' + str(k) + ' ' + str( + self.array_mu_z[i][j][k]) + '\n' offset = 13 with open(filename, 'w') as f: @@ -359,28 +359,29 @@ def save(self, filename, write_deformed=True): y = np.linspace(0, self.lenght_box[1], self.n_control_points[1]) z = np.linspace(0, self.lenght_box[2], self.n_control_points[2]) - lattice_y_coords, lattice_x_coords, lattice_z_coords = np.meshgrid(y, x, - z) + lattice_y_coords, lattice_x_coords, lattice_z_coords = np.meshgrid( + y, x, z) if write_deformed: box_points = np.array([ - lattice_x_coords.ravel() + self.array_mu_x.ravel() * - self.lenght_box[0], lattice_y_coords.ravel() + + lattice_x_coords.ravel() + + self.array_mu_x.ravel() * self.lenght_box[0], + lattice_y_coords.ravel() + self.array_mu_y.ravel() * self.lenght_box[1], - lattice_z_coords.ravel() + self.array_mu_z.ravel() * - self.lenght_box[2] + lattice_z_coords.ravel() + + self.array_mu_z.ravel() * self.lenght_box[2] ]) else: box_points = np.array([ - lattice_x_coords.ravel(), lattice_y_coords.ravel(), + lattice_x_coords.ravel(), + lattice_y_coords.ravel(), lattice_z_coords.ravel() ]) n_rows = box_points.shape[1] - box_points = np.dot( - self.rotation_matrix, - box_points) + np.transpose(np.tile(self.origin_box, (n_rows, 1))) + box_points = np.dot(self.rotation_matrix, box_points) + np.transpose( + np.tile(self.origin_box, (n_rows, 1))) points = vtk.vtkPoints() diff --git a/pygem/params/rbfparams.py b/pygem/params/rbfparams.py index 7267e70..63f25f2 100644 --- a/pygem/params/rbfparams.py +++ b/pygem/params/rbfparams.py @@ -88,7 +88,9 @@ def read_parameters(self, filename='parameters_rbf.prm'): for line, i in zip(lines, list(range(0, self.n_control_points))): values = line.split() self.original_control_points[i] = np.array( - [float(values[0]), float(values[1]), float(values[2])]) + [float(values[0]), + float(values[1]), + float(values[2])]) mod_points = config.get('Control points', 'deformed control points') lines = mod_points.split('\n') @@ -103,7 +105,9 @@ def read_parameters(self, filename='parameters_rbf.prm'): for line, i in zip(lines, list(range(0, self.n_control_points))): values = line.split() self.deformed_control_points[i] = np.array( - [float(values[0]), float(values[1]), float(values[2])]) + [float(values[0]), + float(values[1]), + float(values[2])]) def write_parameters(self, filename='parameters_rbf.prm'): """ @@ -116,55 +120,63 @@ def write_parameters(self, filename='parameters_rbf.prm'): if not isinstance(filename, str): raise TypeError("filename must be a string") - with open(filename, 'w') as output_file: - output_file.write('\n[Radial Basis Functions]\n') - output_file.write( - '# This section describes the radial basis functions shape.\n') - - output_file.write( - '\n# basis funtion is the name of the basis functions to use in the transformation. The functions\n') - output_file.write( - '# implemented so far are: gaussian_spline, multi_quadratic_biharmonic_spline,\n') - output_file.write( - '# inv_multi_quadratic_biharmonic_spline, thin_plate_spline, beckert_wendland_c2_basis, polyharmonic_spline.\n') - output_file.write( - '# For a comprehensive list with details see the class RBF.\n') - output_file.write('basis function: ' + str(self.basis) + '\n') - - output_file.write( - '\n# radius is the scaling parameter r that affects the shape of the basis functions. See the documentation\n') - output_file.write('# of the class RBF for details.\n') - output_file.write('radius: ' + str(self.radius) + '\n') - output_file.write( - '\n# The power parameter k for polyharmonic spline') - output_file.write('\n# See the documentation for details\n') - output_file.write('power: ' + str(self.power) + '\n') - - output_file.write('\n\n[Control points]\n') - output_file.write( - '# This section describes the RBF control points.\n') - - output_file.write( - '\n# original control points collects the coordinates of the interpolation control points before the deformation.\n') - output_file.write('original control points:') - offset = 1 - for i in range(0, self.n_control_points): - output_file.write(offset * ' ' + str( - self.original_control_points[i][0]) + ' ' + str( - self.original_control_points[i][1]) + ' ' + str( - self.original_control_points[i][2]) + '\n') - offset = 25 - - output_file.write( - '\n# deformed control points collects the coordinates of the interpolation control points after the deformation.\n') - output_file.write('deformed control points:') - offset = 1 - for i in range(0, self.n_control_points): - output_file.write(offset * ' ' + str( - self.deformed_control_points[i][0]) + ' ' + str( - self.deformed_control_points[i][1]) + ' ' + str( - self.deformed_control_points[i][2]) + '\n') - offset = 25 + output_string = "" + output_string += '\n[Radial Basis Functions]\n' + output_string += '# This section describes the radial basis functions' + output_string += ' shape.\n' + + output_string += '\n# basis funtion is the name of the basis functions' + output_string += ' to use in the transformation. The functions\n' + output_string += '# implemented so far are: gaussian_spline,' + output_string += ' multi_quadratic_biharmonic_spline,\n' + output_string += '# inv_multi_quadratic_biharmonic_spline,' + output_string += ' thin_plate_spline, beckert_wendland_c2_basis,' + output_string += ' polyharmonic_spline.\n' + output_string += '# For a comprehensive list with details see the' + output_string += ' class RBF.\n' + output_string += 'basis function: {}\n'.format(str(self.basis)) + + output_string += '\n# radius is the scaling parameter r that affects' + output_string += ' the shape of the basis functions. See the' + output_string += ' documentation\n' + output_string += '# of the class RBF for details.\n' + output_string += 'radius: {}\n'.format(str(self.radius)) + + output_string += '\n# The power parameter k for polyharmonic spline' + output_string += '\n# See the documentation for details\n' + output_string += 'power: {}\n'.format(self.power) + + output_string += '\n\n[Control points]\n' + output_string += '# This section describes the RBF control points.\n' + + output_string += '\n# original control points collects the coordinates' + output_string += ' of the interpolation control points before the' + output_string += ' deformation.\n' + + output_string += 'original control points:' + offset = 1 + for i in range(0, self.n_control_points): + output_string += offset * ' ' + str( + self.original_control_points[i][0]) + ' ' + str( + self.original_control_points[i][1]) + ' ' + str( + self.original_control_points[i][2]) + '\n' + offset = 25 + + output_string += '\n# deformed control points collects the coordinates' + output_string += ' of the interpolation control points after the' + output_string += ' deformation.\n' + + output_string += 'deformed control points:' + offset = 1 + for i in range(0, self.n_control_points): + output_string += offset * ' ' + str( + self.deformed_control_points[i][0]) + ' ' + str( + self.deformed_control_points[i][1]) + ' ' + str( + self.deformed_control_points[i][2]) + '\n' + offset = 25 + + with open(filename, 'w') as f: + f.write(output_string) def __str__(self): """ diff --git a/pygem/radial.py b/pygem/radial.py index 94b0e33..51718b1 100644 --- a/pygem/radial.py +++ b/pygem/radial.py @@ -108,14 +108,18 @@ def __init__(self, rbf_parameters, original_mesh_points): self.modified_mesh_points = None self.bases = { - 'gaussian_spline': self.gaussian_spline, + 'gaussian_spline': + self.gaussian_spline, 'multi_quadratic_biharmonic_spline': self.multi_quadratic_biharmonic_spline, 'inv_multi_quadratic_biharmonic_spline': self.inv_multi_quadratic_biharmonic_spline, - 'thin_plate_spline': self.thin_plate_spline, - 'beckert_wendland_c2_basis': self.beckert_wendland_c2_basis, - 'polyharmonic_spline': self.polyharmonic_spline + 'thin_plate_spline': + self.thin_plate_spline, + 'beckert_wendland_c2_basis': + self.beckert_wendland_c2_basis, + 'polyharmonic_spline': + self.polyharmonic_spline } # to make the str callable we have to use a dictionary with all the @@ -315,9 +319,12 @@ def _get_weights(self, X, Y): dim = X.shape[1] identity = np.ones((n_points, 1)) dist = self._distance_matrix(X, X) - H = np.bmat([[dist, identity, X], [identity.T, np.zeros( - (1, 1)), np.zeros((1, dim))], [X.T, np.zeros((dim, 1)), np.zeros( - (dim, dim))]]) + H = np.bmat([[dist, identity, + X], [identity.T, + np.zeros((1, 1)), + np.zeros((1, dim))], + [X.T, np.zeros((dim, 1)), + np.zeros((dim, dim))]]) rhs = np.bmat([[Y], [np.zeros((1, dim))], [np.zeros((dim, dim))]]) weights = np.linalg.solve(H, rhs) return weights diff --git a/pygem/stlhandler.py b/pygem/stlhandler.py index f574300..8d1ca97 100644 --- a/pygem/stlhandler.py +++ b/pygem/stlhandler.py @@ -137,10 +137,14 @@ def plot(self, plot_file=None, save_fig=False): axes.add_collection3d(tri) ## Get the limits of the axis and center the geometry - max_dim = np.array([np.max(vtx[:, :, 0]), np.max(vtx[:, :, 1]), - np.max(vtx[:, :, 2])]) - min_dim = np.array([np.min(vtx[:, :, 0]), np.min(vtx[:, :, 1]), - np.min(vtx[:, :, 2])]) + max_dim = np.array( + [np.max(vtx[:, :, 0]), + np.max(vtx[:, :, 1]), + np.max(vtx[:, :, 2])]) + min_dim = np.array( + [np.min(vtx[:, :, 0]), + np.min(vtx[:, :, 1]), + np.min(vtx[:, :, 2])]) max_lenght = np.max(max_dim - min_dim) axes.set_xlim(-.6 * max_lenght + (max_dim[0] + min_dim[0]) / 2, diff --git a/pygem/utils.py b/pygem/utils.py index ec55781..5df2314 100644 --- a/pygem/utils.py +++ b/pygem/utils.py @@ -41,23 +41,24 @@ 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[0], lattice_y_coords.ravel() + + 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] + 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_x_coords.ravel(), + lattice_y_coords.ravel(), lattice_z_coords.ravel() ]) n_rows = box_points.shape[1] - box_points = np.dot( - parameters.rotation_matrix, - box_points) + np.transpose(np.tile(parameters.origin_box, (n_rows, 1))) + box_points = np.dot(parameters.rotation_matrix, box_points) + np.transpose( + np.tile(parameters.origin_box, (n_rows, 1))) # step necessary to set the correct order to the box points for # vtkStructuredGrid. Data in vtkStructuredGrid are ordered with diff --git a/pygem/vtkhandler.py b/pygem/vtkhandler.py index e048eea..861ae8e 100644 --- a/pygem/vtkhandler.py +++ b/pygem/vtkhandler.py @@ -136,10 +136,14 @@ def plot(self, plot_file=None, save_fig=False): axes.add_collection3d(tri) ## Get the limits of the axis and center the geometry - max_dim = np.array([np.max(vtx[:, :, 0]), np.max(vtx[:, :, 1]), - np.max(vtx[:, :, 2])]) - min_dim = np.array([np.min(vtx[:, :, 0]), np.min(vtx[:, :, 1]), - np.min(vtx[:, :, 2])]) + max_dim = np.array( + [np.max(vtx[:, :, 0]), + np.max(vtx[:, :, 1]), + np.max(vtx[:, :, 2])]) + min_dim = np.array( + [np.min(vtx[:, :, 0]), + np.min(vtx[:, :, 1]), + np.min(vtx[:, :, 2])]) max_lenght = np.max(max_dim - min_dim) axes.set_xlim(-.6 * max_lenght + (max_dim[0] + min_dim[0]) / 2, diff --git a/tests/test_ffdparams.py b/tests/test_ffdparams.py index e69af53..ee2e1f9 100644 --- a/tests/test_ffdparams.py +++ b/tests/test_ffdparams.py @@ -33,18 +33,18 @@ def test_class_members_default_rot_angle(self): def test_class_members_default_array_mu_x(self): params = FFDParameters() - np.testing.assert_array_almost_equal(params.array_mu_x, np.zeros( - (2, 2, 2))) + np.testing.assert_array_almost_equal(params.array_mu_x, + np.zeros((2, 2, 2))) def test_class_members_default_array_mu_y(self): params = FFDParameters() - np.testing.assert_array_almost_equal(params.array_mu_y, np.zeros( - (2, 2, 2))) + np.testing.assert_array_almost_equal(params.array_mu_y, + np.zeros((2, 2, 2))) def test_class_members_default_array_mu_z(self): params = FFDParameters() - np.testing.assert_array_almost_equal(params.array_mu_z, np.zeros( - (2, 2, 2))) + np.testing.assert_array_almost_equal(params.array_mu_z, + np.zeros((2, 2, 2))) def test_class_members_default_psi_mapping(self): params = FFDParameters() @@ -73,18 +73,18 @@ def test_class_members_generic_n_control_points(self): def test_class_members_generic_array_mu_x(self): params = FFDParameters([2, 3, 5]) - np.testing.assert_array_almost_equal(params.array_mu_x, np.zeros( - (2, 3, 5))) + np.testing.assert_array_almost_equal(params.array_mu_x, + np.zeros((2, 3, 5))) def test_class_members_generic_array_mu_y(self): params = FFDParameters([2, 3, 5]) - np.testing.assert_array_almost_equal(params.array_mu_y, np.zeros( - (2, 3, 5))) + np.testing.assert_array_almost_equal(params.array_mu_y, + np.zeros((2, 3, 5))) def test_class_members_generic_array_mu_z(self): params = FFDParameters([2, 3, 5]) - np.testing.assert_array_almost_equal(params.array_mu_z, np.zeros( - (2, 3, 5))) + np.testing.assert_array_almost_equal(params.array_mu_z, + np.zeros((2, 3, 5))) def test_read_parameters_conversion_unit(self): params = FFDParameters(n_control_points=[3, 2, 2]) @@ -126,16 +126,18 @@ def test_read_parameters_array_mu_x(self): def test_read_parameters_array_mu_y(self): params = FFDParameters(n_control_points=[3, 2, 2]) params.read_parameters('tests/test_datasets/parameters_sphere.prm') - array_mu_y_exact = np.array([0., 0., 0.5555555555, 0., 0., 0., 0., 0., - -1., 0., 0., 0.]).reshape((3, 2, 2)) + array_mu_y_exact = np.array( + [0., 0., 0.5555555555, 0., 0., 0., 0., 0., -1., 0., 0., + 0.]).reshape((3, 2, 2)) np.testing.assert_array_almost_equal(params.array_mu_y, array_mu_y_exact) def test_read_parameters_array_mu_z(self): params = FFDParameters(n_control_points=[3, 2, 2]) params.read_parameters('tests/test_datasets/parameters_sphere.prm') - array_mu_z_exact = np.array([0., -0.2, 0., -0.45622985, 0., 0., 0., 0., - -1.22, 0., -1., 0.]).reshape((3, 2, 2)) + array_mu_z_exact = np.array( + [0., -0.2, 0., -0.45622985, 0., 0., 0., 0., -1.22, 0., -1., + 0.]).reshape((3, 2, 2)) np.testing.assert_array_almost_equal(params.array_mu_z, array_mu_z_exact)