// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CalculateTriangleGroupCurvatures::operator()() const
{
  int32_t err = 0;

  if (m_TriangleIds.size() == 0)
  {
    return;
  }

  // Instantiate a FindNRingNeighbors class to use during the loop
  FindNRingNeighbors::Pointer nRingNeighborAlg = FindNRingNeighbors::New();

  int32_t* faceLabels = m_SurfaceMeshFaceLabels->getPointer(0);

  int32_t* fl = faceLabels + m_TriangleIds[0] * 2;
  int32_t feature0 = 0;
  int32_t feature1 = 0;
  if (fl[0] < fl[1])
  {
    feature0 = fl[0];
    feature1 = fl[1];
  }
  else
  {
    feature0 = fl[1];
    feature1 = fl[0];
  }

  bool computeGaussian = (m_GaussianCurvature.get() != NULL);
  bool computeMean = (m_MeanCurvature.get() != NULL);
  bool computeDirection = (m_PrincipleDirection1.get() != NULL);

  std::vector<int64_t>::size_type tCount = m_TriangleIds.size();
  // For each triangle in the group
  for(std::vector<int64_t>::size_type i = 0; i < tCount; ++i)
  {
    if (m_ParentFilter->getCancel() == true) { return; }
    int64_t triId = m_TriangleIds[i];
    nRingNeighborAlg->setTriangleId(triId);
    nRingNeighborAlg->setRegionId0(feature0);
    nRingNeighborAlg->setRegionId1(feature1);
    nRingNeighborAlg->setRing(m_NRing);
    err = nRingNeighborAlg->generate(m_TrianglesPtr, faceLabels);
    Q_ASSERT(err >= 0);

    UniqueFaceIds_t triPatch = nRingNeighborAlg->getNRingTriangles();
    Q_ASSERT(triPatch.size() > 1);

    DataArray<double>::Pointer patchCentroids = extractPatchData(triId, triPatch, m_SurfaceMeshTriangleCentroids->getPointer(0), QString("_INTERNAL_USE_ONLY_Patch_Centroids"));
    DataArray<double>::Pointer patchNormals = extractPatchData(triId, triPatch, m_SurfaceMeshFaceNormals->getPointer(0), QString("_INTERNAL_USE_ONLY_Patch_Normals"));

    // Translate the patch to the 0,0,0 origin
    double sub[3] = {patchCentroids->getComponent(0, 0), patchCentroids->getComponent(0, 1), patchCentroids->getComponent(0, 2)};
    subtractVector3d(patchCentroids, sub);

    double np[3] = {patchNormals->getComponent(0, 0), patchNormals->getComponent(0, 1), patchNormals->getComponent(0, 2) };

    double seedCentroid[3] = {patchCentroids->getComponent(0, 0), patchCentroids->getComponent(0, 1), patchCentroids->getComponent(0, 2) };
    double firstCentroid[3] = {patchCentroids->getComponent(1, 0), patchCentroids->getComponent(1, 1), patchCentroids->getComponent(1, 2) };

    double temp[3] = {firstCentroid[0] - seedCentroid[0], firstCentroid[1] - seedCentroid[1], firstCentroid[2] - seedCentroid[2]};
    double vp[3] = {0.0, 0.0, 0.0};

    // Cross Product of np and temp
    MatrixMath::Normalize3x1(np);
    MatrixMath::CrossProduct(np, temp, vp);
    MatrixMath::Normalize3x1(vp);

    // get the third orthogonal vector
    double up[3] = {0.0, 0.0, 0.0};
    MatrixMath::CrossProduct(vp, np, up);

    // this constitutes a rotation matrix to a local coordinate system
    double rot[3][3] = {{up[0], up[1], up[2]},
      {vp[0], vp[1], vp[2]},
      {np[0], np[1], np[2]}
    };
    double out[3] = { 0.0, 0.0, 0.0 };
    // Transform all centroids and normals to new coordinate system
    for (size_t m = 0; m < patchCentroids->getNumberOfTuples(); ++m)
    {
      ::memcpy(out, patchCentroids->getPointer(m * 3), 3 * sizeof(double));
      MatrixMath::Multiply3x3with3x1(rot, patchCentroids->getPointer(m * 3), out);
      ::memcpy(patchCentroids->getPointer(m * 3), out, 3 * sizeof(double));

      ::memcpy(out, patchNormals->getPointer(m * 3), 3 * sizeof(double));
      MatrixMath::Multiply3x3with3x1(rot, patchNormals->getPointer(m * 3), out);
      ::memcpy(patchNormals->getPointer(m * 3), out, 3 * sizeof(double));

      // We rotate the normals now but we dont use them yet. If we start using part 3 of Goldfeathers paper then we
      // will need the normals.
    }

    {
      // Solve the Least Squares fit
      static const uint32_t NO_NORMALS = 3;
      static const uint32_t USE_NORMALS = 7;
      uint32_t cols = NO_NORMALS;
      if (m_UseNormalsForCurveFitting == true) { cols = USE_NORMALS; }
      size_t rows = patchCentroids->getNumberOfTuples();
      Eigen::MatrixXd A(rows, cols);
      Eigen::VectorXd b(rows);
      double x = 0.0, y = 0.0, z = 0.0;
      for (size_t m = 0; m < rows; ++m)
      {
        x = patchCentroids->getComponent(m, 0);
        y = patchCentroids->getComponent(m, 1);
        z = patchCentroids->getComponent(m, 2);

        A(m) = 0.5 * x * x;  // 1/2 x^2
        A(m + rows) = x * y; // x*y
        A(m + rows * 2) = 0.5 * y * y; // 1/2 y^2
        if (m_UseNormalsForCurveFitting == true)
        {
          A(m + rows * 3) = x * x * x;
          A(m + rows * 4) = x * x * y;
          A(m + rows * 5) = x * y * y;
          A(m + rows * 6) = y * y * y;
        }
        b[m] = z; // The Z Values
      }

      Eigen::Matrix2d M;

      if (false == m_UseNormalsForCurveFitting)
      {
        typedef Eigen::Matrix<double, NO_NORMALS, 1> Vector3d;
        Vector3d sln1 = A.colPivHouseholderQr().solve(b);
        // Now that we have the A, B, C constants we can solve the Eigen value/vector problem
        // to get the principal curvatures and pricipal directions.
        M << sln1(0), sln1(1), sln1(1), sln1(2);
      }
      else
      {
        typedef Eigen::Matrix<double, USE_NORMALS, 1> Vector7d;
        Vector7d sln1 = A.colPivHouseholderQr().solve(b);
        // Now that we have the A, B, C, D, E, F & G constants we can solve the Eigen value/vector problem
        // to get the principal curvatures and pricipal directions.
        M << sln1(0), sln1(1), sln1(1), sln1(2);
      }

      Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(M);
      Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d>::RealVectorType eValues = eig.eigenvalues();
      Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d>::MatrixType eVectors = eig.eigenvectors();

      // Kappa1 >= Kappa2
      double kappa1 = eValues(0) * -1;// Kappa 1
      double kappa2 = eValues(1) * -1; //kappa 2
      Q_ASSERT(kappa1 >= kappa2);
      m_PrincipleCurvature1->setValue(triId, kappa1);
      m_PrincipleCurvature2->setValue(triId, kappa2);

      if (computeGaussian == true)
      {
        m_GaussianCurvature->setValue(triId, kappa1 * kappa2);
      }
      if (computeMean == true)
      {
        m_MeanCurvature->setValue(triId, (kappa1 + kappa2) / 2.0);
      }

      if (computeDirection == true)
      {
        Eigen::Matrix3d e_rot_T;
        e_rot_T.row(0) = Eigen::Vector3d(up[0], vp[0], np[0]);
        e_rot_T.row(1) = Eigen::Vector3d(up[1], vp[1], np[1]);
        e_rot_T.row(2) = Eigen::Vector3d(up[2], vp[2], np[2]);

        // Rotate our principal directions back into the original coordinate system
        Eigen::Vector3d dir1 ( eVectors.col(0)(0),  eVectors.col(0)(1), 0.0 );
        dir1 = e_rot_T * dir1;
        ::memcpy(m_PrincipleDirection1->getPointer(triId * 3), dir1.data(), 3 * sizeof(double) );

        Eigen::Vector3d dir2 ( eVectors.col(1)(0),  eVectors.col(1)(1), 0.0 );
        dir2 = e_rot_T * dir2;
        ::memcpy(m_PrincipleDirection2->getPointer(triId * 3), dir2.data(), 3 * sizeof(double) );
      }
    }
  } // End Loop over this triangle
}
Esempio n. 2
0
int main(int argc, char **args) {
	int res = ERR_SUCCESS;

#ifdef WITH_PETSC
	PetscInitialize(&argc, &args, (char *) PETSC_NULL, PETSC_NULL);
#endif
	set_verbose(false);

	if (argc < 2) error("Not enough parameters");

	H1ShapesetLobattoHex shapeset;

	printf("* Loading mesh '%s'\n", args[1]);
	Mesh mesh;
	Mesh3DReader mesh_loader;
	if (!mesh_loader.load(args[1], &mesh)) error("Loading mesh file '%s'\n", args[1]);

	printf("* Setup space #1\n");
	H1Space space1(&mesh, &shapeset);
	space1.set_bc_types(bc_types);

	order3_t o1(2, 2, 2);
	printf("  - Setting uniform order to (%d, %d, %d)\n", o1.x, o1.y, o1.z);
	space1.set_uniform_order(o1);

	printf("* Setup space #2\n");
	H1Space space2(&mesh, &shapeset);
	space2.set_bc_types(bc_types);

	order3_t o2(4, 4, 4);
	printf("  - Setting uniform order to (%d, %d, %d)\n", o2.x, o2.y, o2.z);
	space2.set_uniform_order(o2);

	int ndofs = 0;
	ndofs += space1.assign_dofs();
	ndofs += space2.assign_dofs(ndofs);
	printf("  - Number of DOFs: %d\n", ndofs);

	printf("* Calculating a solution\n");

#if defined WITH_UMFPACK
	UMFPackMatrix mat;
	UMFPackVector rhs;
	UMFPackLinearSolver solver(&mat, &rhs);
#elif defined WITH_PARDISO
	PardisoMatrix mat;
	PardisoVector rhs;
	PardisoLinearSolver solver(&mat, &rhs);
#elif defined WITH_PETSC
	PetscMatrix mat;
	PetscVector rhs;
	PetscLinearSolver solver(&mat, &rhs);
#elif defined WITH_MUMPS
	MumpsMatrix mat;
	MumpsVector rhs;
	MumpsSolver solver(&mat, &rhs);
#endif

	WeakForm wf(2);
	wf.add_matrix_form(0, 0, bilinear_form_1<double, scalar>, bilinear_form_1<ord_t, ord_t>, SYM);
	wf.add_vector_form(0, linear_form_1<double, scalar>, linear_form_1<ord_t, ord_t>);

	wf.add_matrix_form(1, 1, bilinear_form_2<double, scalar>, bilinear_form_2<ord_t, ord_t>, SYM);
	wf.add_vector_form(1, linear_form_2<double, scalar>, linear_form_2<ord_t, ord_t>);

	LinearProblem lp(&wf, Tuple<Space *>(&space1, &space2));

	// assemble stiffness matrix
	Timer assemble_timer("Assembling stiffness matrix");
	assemble_timer.start();
	lp.assemble(&mat, &rhs);
	assemble_timer.stop();

	// solve the stiffness matrix
	Timer solve_timer("Solving stiffness matrix");
	solve_timer.start();
	bool solved = solver.solve();
	solve_timer.stop();

	// output the measured values
	printf("%s: %s (%lf secs)\n", assemble_timer.get_name(), assemble_timer.get_human_time(), assemble_timer.get_seconds());
	printf("%s: %s (%lf secs)\n", solve_timer.get_name(), solve_timer.get_human_time(), solve_timer.get_seconds());

	if (solved) {
		// solution 1
		Solution sln1(&mesh);
		sln1.set_coeff_vector(&space1, solver.get_solution());

		ExactSolution esln1(&mesh, exact_sln_fn_1);
		// norm
		double h1_sln_norm1 = h1_norm(&sln1);
		double h1_err_norm1 = h1_error(&sln1, &esln1);

		printf(" - H1 solution norm:   % le\n", h1_sln_norm1);
		printf(" - H1 error norm:      % le\n", h1_err_norm1);

		double l2_sln_norm1 = l2_norm(&sln1);
		double l2_err_norm1 = l2_error(&sln1, &esln1);
		printf(" - L2 solution norm:   % le\n", l2_sln_norm1);
		printf(" - L2 error norm:      % le\n", l2_err_norm1);

		if (h1_err_norm1 > EPS || l2_err_norm1 > EPS) {
			// calculated solution is not enough precise
			res = ERR_FAILURE;
		}

		// solution 2
		Solution sln2(&mesh);
		sln2.set_coeff_vector(&space2, solver.get_solution());

		ExactSolution esln2(&mesh, exact_sln_fn_2);
		// norm
		double h1_sln_norm2 = h1_norm(&sln2);
		double h1_err_norm2 = h1_error(&sln2, &esln2);

		printf(" - H1 solution norm:   % le\n", h1_sln_norm2);
		printf(" - H1 error norm:      % le\n", h1_err_norm2);

		double l2_sln_norm2 = l2_norm(&sln2);
		double l2_err_norm2 = l2_error(&sln2, &esln2);
		printf(" - L2 solution norm:   % le\n", l2_sln_norm2);
		printf(" - L2 error norm:      % le\n", l2_err_norm2);

		if (h1_err_norm2 > EPS || l2_err_norm2 > EPS) {
			// calculated solution is not enough precise
			res = ERR_FAILURE;
		}

#ifdef OUTPUT_DIR
		// output
		const char *of_name = OUTPUT_DIR "/solution.pos";
		FILE *ofile = fopen(of_name, "w");
		if (ofile != NULL) {
			GmshOutputEngine output(ofile);
			output.out(&sln1, "Uh_1");
			output.out(&esln1, "U1");
			output.out(&sln2, "Uh_2");
			output.out(&esln2, "U2");

			fclose(ofile);
		}
		else {
			warning("Can not open '%s' for writing.", of_name);
		}
#endif
	}

#ifdef WITH_PETSC
	mat.free();
	rhs.free();
	PetscFinalize();
#endif

	TRACE_END;

	return res;
}
Esempio n. 3
0
int main(int argc, char **args) 
{
  // Test variable.
  int success_test = 1;

	if (argc < 2) error("Not enough parameters.");

  // Load the mesh.
	Mesh mesh;
  H3DReader mloader;
  if (!mloader.load(args[1], &mesh)) error("Loading mesh file '%s'.", args[1]);

  // Initialize the space 1.
	Ord3 o1(2, 2, 2);
	H1Space space1(&mesh, bc_types, NULL, o1);

	// Initialize the space 2.
	Ord3 o2(4, 4, 4);
	H1Space space2(&mesh, bc_types, NULL, o2);

	WeakForm wf(2);
	wf.add_matrix_form(0, 0, bilinear_form_1_1<double, scalar>, bilinear_form_1_1<Ord, Ord>, HERMES_SYM);
	wf.add_matrix_form(0, 1, bilinear_form_1_2<double, scalar>, bilinear_form_1_2<Ord, Ord>, HERMES_SYM);
	wf.add_vector_form(0, linear_form_1<double, scalar>, linear_form_1<Ord, Ord>);
	wf.add_matrix_form(1, 1, bilinear_form_2_2<double, scalar>, bilinear_form_2_2<Ord, Ord>, HERMES_SYM);
	wf.add_vector_form(1, linear_form_2<double, scalar>, linear_form_2<Ord, Ord>);

  // Initialize the FE problem.
  bool is_linear = true;
  DiscreteProblem dp(&wf, Tuple<Space *>(&space1, &space2), is_linear);

  // Initialize the solver in the case of SOLVER_PETSC or SOLVER_MUMPS.
  initialize_solution_environment(matrix_solver, argc, args);

  // Set up the solver, matrix, and rhs according to the solver selection.
  SparseMatrix* matrix = create_matrix(matrix_solver);
  Vector* rhs = create_vector(matrix_solver);
  Solver* solver = create_linear_solver(matrix_solver, matrix, rhs);

  // Initialize the preconditioner in the case of SOLVER_AZTECOO.
  if (matrix_solver == SOLVER_AZTECOO) 
  {
    ((AztecOOSolver*) solver)->set_solver(iterative_method);
    ((AztecOOSolver*) solver)->set_precond(preconditioner);
    // Using default iteration parameters (see solver/aztecoo.h).
  }

  // Assemble the linear problem.
  info("Assembling (ndof: %d).", Space::get_num_dofs(Tuple<Space *>(&space1, &space2)));
  dp.assemble(matrix, rhs);

  // Solve the linear system. If successful, obtain the solution.
  info("Solving.");
	Solution sln1(&mesh);
	Solution sln2(&mesh);
  if(solver->solve()) Solution::vector_to_solutions(solver->get_solution(), Tuple<Space *>(&space1, &space2), Tuple<Solution *>(&sln1, &sln2));
  else error ("Matrix solver failed.\n");

  ExactSolution ex_sln1(&mesh, exact_sln_fn_1);
  ExactSolution ex_sln2(&mesh, exact_sln_fn_2);

  // Calculate exact error.
  info("Calculating exact error.");
  Adapt *adaptivity = new Adapt(Tuple<Space *>(&space1, &space2), Tuple<ProjNormType>(HERMES_H1_NORM, HERMES_H1_NORM));
  bool solutions_for_adapt = false;
  double err_exact = adaptivity->calc_err_exact(Tuple<Solution *>(&sln1, &sln2), Tuple<Solution *>(&ex_sln1, &ex_sln2), solutions_for_adapt, HERMES_TOTAL_ERROR_ABS);

  if (err_exact > EPS)
		// Calculated solution is not precise enough.
		success_test = 0;

  // Clean up.
  delete matrix;
  delete rhs;
  delete solver;
  delete adaptivity;

  // Properly terminate the solver in the case of SOLVER_PETSC or SOLVER_MUMPS.
  finalize_solution_environment(matrix_solver);
  
  if (success_test) {
    info("Success!");
    return ERR_SUCCESS;
	}
	else {
    info("Failure!");
    return ERR_FAILURE;
	}
}
Esempio n. 4
0
int main(int argc, char **args)
{
	int res = ERR_SUCCESS;

#ifdef WITH_PETSC
	PetscInitialize(&argc, &args, (char *) PETSC_NULL, PETSC_NULL);
#endif

	if (argc < 2) error("Not enough parameters.");

	printf("* Loading mesh '%s'\n", args[1]);
	Mesh mesh1;
	H3DReader mesh_loader;
	if (!mesh_loader.load(args[1], &mesh1)) error("Loading mesh file '%s'\n", args[1]);

#if defined RHS2

	Ord3 order(P_INIT_X, P_INIT_Y, P_INIT_Z);
	printf("  - Setting uniform order to (%d, %d, %d)\n", order.x, order.y, order.z);
	
	// Create an H1 space with default shapeset.
	printf("* Setting the space up\n");
	H1Space space(&mesh1, bc_types, essential_bc_values, order);

	int ndofs = space.assign_dofs();
	printf("  - Number of DOFs: %d\n", ndofs);

	printf("* Calculating a solution\n");

	// duplicate the mesh
	Mesh mesh2;
	mesh2.copy(mesh1);
	// do some changes
	mesh2.refine_all_elements(H3D_H3D_H3D_REFT_HEX_XYZ);
	mesh2.refine_all_elements(H3D_H3D_H3D_REFT_HEX_XYZ);

	Solution fsln(&mesh2);
	fsln.set_const(-6.0);
#else
	// duplicate the mesh
	Mesh mesh2;
	mesh2.copy(mesh1);

	Mesh mesh3;
	mesh3.copy(mesh1);

	// change meshes
	mesh1.refine_all_elements(H3D_REFT_HEX_X);
	mesh2.refine_all_elements(H3D_REFT_HEX_Y);
	mesh3.refine_all_elements(H3D_REFT_HEX_Z);

	printf("* Setup spaces\n");
	Ord3 o1(2, 2, 2);
	printf("  - Setting uniform order to (%d, %d, %d)\n", o1.x, o1.y, o1.z);
	H1Space space1(&mesh1, bc_types_1, essential_bc_values_1, o1);

	Ord3 o2(2, 2, 2);
	printf("  - Setting uniform order to (%d, %d, %d)\n", o2.x, o2.y, o2.z);
	H1Space space2(&mesh2, bc_types_2, essential_bc_values_2, o2);

	Ord3 o3(1, 1, 1);
	printf("  - Setting uniform order to (%d, %d, %d)\n", o3.x, o3.y, o3.z);
	H1Space space3(&mesh3, bc_types_3, essential_bc_values_3, o3);

	int ndofs = 0;
	ndofs += space1.assign_dofs();
	ndofs += space2.assign_dofs(ndofs);
	ndofs += space3.assign_dofs(ndofs);
	printf("  - Number of DOFs: %d\n", ndofs);
#endif

#if defined WITH_UMFPACK
	MatrixSolverType matrix_solver = SOLVER_UMFPACK; 
#elif defined WITH_PETSC
	MatrixSolverType matrix_solver = SOLVER_PETSC; 
#elif defined WITH_MUMPS
	MatrixSolverType matrix_solver = SOLVER_MUMPS; 
#endif

#ifdef RHS2
	WeakForm wf;
	wf.add_matrix_form(bilinear_form<double, scalar>, bilinear_form<Ord, Ord>, HERMES_SYM);
	wf.add_vector_form(linear_form<double, scalar>, linear_form<Ord, Ord>, HERMES_ANY_INT, &fsln);

	// Initialize discrete problem.
	bool is_linear = true;
	DiscreteProblem dp(&wf, &space, is_linear);
#elif defined SYS3
	WeakForm wf(3);
	wf.add_matrix_form(0, 0, biform_1_1<double, scalar>, biform_1_1<Ord, Ord>, HERMES_SYM);
	wf.add_matrix_form(0, 1, biform_1_2<double, scalar>, biform_1_2<Ord, Ord>, HERMES_NONSYM);
	wf.add_vector_form(0, liform_1<double, scalar>, liform_1<Ord, Ord>);

	wf.add_matrix_form(1, 1, biform_2_2<double, scalar>, biform_2_2<Ord, Ord>, HERMES_SYM);
	wf.add_matrix_form(1, 2, biform_2_3<double, scalar>, biform_2_3<Ord, Ord>, HERMES_NONSYM);
	wf.add_vector_form(1, liform_2<double, scalar>, liform_2<Ord, Ord>);

	wf.add_matrix_form(2, 2, biform_3_3<double, scalar>, biform_3_3<Ord, Ord>, HERMES_SYM);

	// Initialize discrete problem.
	bool is_linear = true;
	DiscreteProblem dp(&wf, Hermes::vector<Space *>(&space1, &space2, &space3), is_linear);
#endif
	// Time measurement.
	TimePeriod cpu_time;
	cpu_time.tick();
  
	// Set up the solver, matrix, and rhs according to the solver selection.
	SparseMatrix* matrix = create_matrix(matrix_solver);
	Vector* rhs = create_vector(matrix_solver);
	Solver* solver = create_linear_solver(matrix_solver, matrix, rhs);

	// Initialize the preconditioner in the case of SOLVER_AZTECOO.
	if (matrix_solver == SOLVER_AZTECOO) 
	{
		((AztecOOSolver*) solver)->set_solver(iterative_method);
		((AztecOOSolver*) solver)->set_precond(preconditioner);
		// Using default iteration parameters (see solver/aztecoo.h).
	}

	// Assemble stiffness matrix and load vector.
	dp.assemble(matrix, rhs);

	// Solve the linear system. If successful, obtain the solution.
	info("Solving the linear problem.");
	bool solved = solver->solve();

	// Time measurement.
	cpu_time.tick();
	// Print timing information.
	info("Solution and mesh with polynomial orders saved. Total running time: %g s", cpu_time.accumulated());

	// Time measurement.
	TimePeriod sln_time;
	sln_time.tick();

	if (solved) {
#ifdef RHS2
		// Solve the linear system. If successful, obtain the solution.
		info("Solving the linear problem.");
                Solution sln(&mesh1);
		Solution::vector_to_solution(solver->get_solution(), &space, &sln);

		// Set exact solution.
		ExactSolution ex_sln(&mesh1, exact_solution);

		// Norm.
		double h1_sln_norm = h1_norm(&sln);
		double h1_err_norm = h1_error(&sln, &ex_sln);
		printf("  - H1 solution norm:   % le\n", h1_sln_norm);
		printf("  - H1 error norm:      % le\n", h1_err_norm);

		double l2_sln_norm = l2_norm(&sln);
		double l2_err_norm = l2_error(&sln, &ex_sln);
		printf("  - L2 solution norm:   % le\n", l2_sln_norm);
		printf("  - L2 error norm:      % le\n", l2_err_norm);

		if (h1_err_norm > EPS || l2_err_norm > EPS) {
			// Calculated solution is not enough precise.
			res = ERR_FAILURE;
		}
#elif defined SYS3
		// Solution 1.
		Solution sln1(&mesh1);
		Solution sln2(&mesh2);
		Solution sln3(&mesh3);

		Solution::vector_to_solution(solver->get_solution(), &space1, &sln1);
		Solution::vector_to_solution(solver->get_solution(), &space2, &sln2);
		Solution::vector_to_solution(solver->get_solution(), &space3, &sln3);

		ExactSolution esln1(&mesh1, exact_sln_fn_1);
		ExactSolution esln2(&mesh2, exact_sln_fn_2);
		ExactSolution esln3(&mesh3, exact_sln_fn_3);

		// Norm.
		double h1_err_norm1 = h1_error(&sln1, &esln1);
		double h1_err_norm2 = h1_error(&sln2, &esln2);
		double h1_err_norm3 = h1_error(&sln3, &esln3);

		double l2_err_norm1 = l2_error(&sln1, &esln1);
		double l2_err_norm2 = l2_error(&sln2, &esln2);
		double l2_err_norm3 = l2_error(&sln3, &esln3);

		printf("  - H1 error norm:      % le\n", h1_err_norm1);
		printf("  - L2 error norm:      % le\n", l2_err_norm1);
		if (h1_err_norm1 > EPS || l2_err_norm1 > EPS) {
			// Calculated solution is not enough precise.
			res = ERR_FAILURE;
		}

		printf("  - H1 error norm:      % le\n", h1_err_norm2);
		printf("  - L2 error norm:      % le\n", l2_err_norm2);
		if (h1_err_norm2 > EPS || l2_err_norm2 > EPS) {
			// Calculated solution is not enough precise.
			res = ERR_FAILURE;
		}

		printf("  - H1 error norm:      % le\n", h1_err_norm3);
		printf("  - L2 error norm:      % le\n", l2_err_norm3);
		if (h1_err_norm3 > EPS || l2_err_norm3 > EPS) {
			// Calculated solution is not enough precise.
			res = ERR_FAILURE;
		}
#endif

#ifdef RHS2
		out_fn_vtk(&sln, "solution");
#elif defined SYS3
		out_fn_vtk(&sln1, "sln1");
		out_fn_vtk(&sln2, "sln2");
		out_fn_vtk(&sln3, "sln3");
#endif
	}
	else
		res = ERR_FAILURE;

	// Print timing information.
	info("Solution and mesh with polynomial orders saved. Total running time: %g s", sln_time.accumulated());

	// Clean up.
	delete matrix;
	delete rhs;
	delete solver;

	return res;
}