int main(int argc, char **args) { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Load the mesh. Mesh mesh; ExodusIIReader mloader; mloader.load("maxwell.mesh", &mesh); // Perform initial mesh refinement. for (int i=0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(H3D_H3D_H3D_REFT_HEX_XYZ); // Create an Hcurl space with default shapeset. HcurlSpace space(&mesh, bc_types, essential_bc_values, Ord3(P_INIT_X, P_INIT_Y, P_INIT_Z)); // Initialize weak formulation. WeakForm wf; wf.add_matrix_form(biform<double, scalar>, biform<Ord, Ord>, HERMES_SYM); wf.add_vector_form(liform<double, scalar>, liform<Ord, Ord>); // DOF and CPU convergence graphs. SimpleGraph graph_dof_est, graph_cpu_est; // Adaptivity loop. int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(&space, 1); // Initialize discrete problem. bool is_linear = true; DiscreteProblem dp(&wf, ref_space, is_linear); // 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 reference problem. info("Assembling on reference mesh (ndof: %d).", Space::get_num_dofs(ref_space)); dp.assemble(matrix, rhs); // Time measurement. cpu_time.tick(); // Solve the linear system on reference mesh. If successful, obtain the solution. info("Solving on reference mesh."); Solution ref_sln(ref_space->get_mesh()); if(solver->solve()) Solution::vector_to_solution(solver->get_solution(), ref_space, &ref_sln); else error ("Matrix solver failed.\n"); // Time measurement. cpu_time.tick(); // Project the reference solution on the coarse mesh. Solution sln(space.get_mesh()); info("Projecting reference solution on coarse mesh."); OGProjection::project_global(&space, &ref_sln, &sln, matrix_solver, HERMES_HCURL_NORM); // Time measurement. cpu_time.tick(); // Output solution and mesh with polynomial orders. if (solution_output) { out_fn_vtk(&sln, "sln", as); out_orders_vtk(&space, "order", as); } // Skip the visualization time. cpu_time.tick(HERMES_SKIP); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt *adaptivity = new Adapt(&space, HERMES_HCURL_NORM); bool solutions_for_adapt = true; double err_est_rel = adaptivity->calc_err_est(&sln, &ref_sln, solutions_for_adapt) * 100; // Add entry to DOF and CPU convergence graphs. graph_dof_est.add_values(Space::get_num_dofs(&space), err_est_rel); graph_dof_est.save("conv_dof_est.dat"); graph_cpu_est.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu_est.save("conv_cpu_est.dat"); // Clean up. delete ref_space->get_mesh(); delete ref_space; delete matrix; delete rhs; delete solver; delete adaptivity; // Increase the counter of performed adaptivity steps. as++; done = true; } while (!done); return 0; }
int main() { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Create coarse mesh, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); // Enumerate basis functions, info for user. int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(jacobian); wf.add_vector_form(residual); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp_coarse = new DiscreteProblem(&wf, space, is_linear); if(JFNK == 0) { // Newton's loop on coarse mesh. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec_coarse = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec_coarse); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix_coarse = create_matrix(matrix_solver); Vector* rhs_coarse = create_vector(matrix_solver); Solver* solver_coarse = create_linear_solver(matrix_solver, matrix_coarse, rhs_coarse); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof_coarse = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp_coarse->assemble(coeff_vec_coarse, matrix_coarse, rhs_coarse); // Calculate the l2-norm of residual vector. double res_l2_norm = get_l2_norm(rhs_coarse); // Info for user. info("---- Newton iter %d, ndof %d, res. l2 norm %g", it, Space::get_num_dofs(space), res_l2_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_l2_norm < NEWTON_TOL_COARSE && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i = 0; i < ndof_coarse; i++) rhs_coarse->set(i, -rhs_coarse->get(i)); // Solve the linear system. if(!solver_coarse->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof_coarse; i++) coeff_vec_coarse[i] += solver_coarse->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. set_coeff_vector(coeff_vec_coarse, space); it++; } // Cleanup. delete matrix_coarse; delete rhs_coarse; delete solver_coarse; delete [] coeff_vec_coarse; } else jfnk_cg(dp_coarse, space, MATRIX_SOLVER_TOL, MATRIX_SOLVER_MAXITER, JFNK_EPSILON, NEWTON_TOL_COARSE, NEWTON_MAX_ITER, matrix_solver); // Cleanup. delete dp_coarse; // DOF and CPU convergence graphs. SimpleGraph graph_dof_est, graph_cpu_est; SimpleGraph graph_dof_exact, graph_cpu_exact; // Adaptivity loop: int as = 1; double ftr_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(space); // Initialize the FE problem. bool is_linear = false; DiscreteProblem* dp = new DiscreteProblem(&wf, ref_space, is_linear); if(JFNK == 0) { // 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); // Newton's loop on the fine mesh. info("Solving on fine mesh:"); // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(ref_space)]; get_coeff_vector(ref_space, coeff_vec); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(ref_space); // Assemble the Jacobian matrix and residual vector. dp->assemble(coeff_vec, matrix, rhs); // Calculate the l2-norm of residual vector. double res_l2_norm = get_l2_norm(rhs); // Info for user. info("---- Newton iter %d, ndof %d, res. l2 norm %g", it, Space::get_num_dofs(ref_space), res_l2_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_l2_norm < NEWTON_TOL_REF && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i = 0; i < ndof; i++) rhs->set(i, -rhs->get(i)); // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += solver->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. set_coeff_vector(coeff_vec, ref_space); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete [] coeff_vec; } else jfnk_cg(dp, ref_space, MATRIX_SOLVER_TOL, MATRIX_SOLVER_MAXITER, JFNK_EPSILON, NEWTON_TOL_COARSE, NEWTON_MAX_ITER, matrix_solver); // Cleanup. delete dp; // Starting with second adaptivity step, obtain new coarse // mesh solution via projecting the fine mesh solution. if(as > 1) { info("Projecting the fine mesh solution onto the coarse mesh."); // Project the fine mesh solution (defined on space_ref) onto the coarse mesh (defined on space). OGProjection::project_global(space, ref_space, matrix_solver); } double max_qoi_err_est = 0; for (int i=0; i < space->get_n_active_elem(); i++) { if (GOAL_ORIENTED == 1) { // Use quantity of interest. double qoi_est = quantity_of_interest(space, X_QOI); double qoi_ref_est = quantity_of_interest(ref_space, X_QOI); ftr_errors[i] = fabs(qoi_ref_est - qoi_est); } else { // Use global norm double err_est_array[MAX_ELEM_NUM]; ftr_errors[i] = calc_err_est(NORM, space, ref_space, err_est_array); } // Info for user. info("Elem [%d]: absolute error (est) = %g%%", i, ftr_errors[i]); // Time measurement. cpu_time.tick(); // Calculating maximum of QOI FTR error for plotting purposes if (GOAL_ORIENTED == 1) { if (ftr_errors[i] > max_qoi_err_est) max_qoi_err_est = ftr_errors[i]; } else { double qoi_est = quantity_of_interest(space, X_QOI); double qoi_ref_est = quantity_of_interest(ref_space, X_QOI); double err_est = fabs(qoi_ref_est - qoi_est); if (err_est > max_qoi_err_est) max_qoi_err_est = err_est; } } // Add entries to convergence graphs. if (EXACT_SOL_PROVIDED) { double qoi_est = quantity_of_interest(space, X_QOI); double u[MAX_EQN_NUM], dudx[MAX_EQN_NUM]; exact_sol(X_QOI, u, dudx); double err_qoi_exact = fabs(u[0] - qoi_est); // Info for user. info("Relative error (exact) = %g %%", err_qoi_exact); // Add entry to DOF and CPU convergence graphs. graph_dof_exact.add_values(Space::get_num_dofs(space), err_qoi_exact); graph_cpu_exact.add_values(cpu_time.accumulated(), err_qoi_exact); } // Add entry to DOF and CPU convergence graphs. graph_dof_est.add_values(Space::get_num_dofs(space), max_qoi_err_est); graph_cpu_est.add_values(cpu_time.accumulated(), max_qoi_err_est); // Decide whether the max. FTR error in the quantity of interest // is sufficiently small. if(max_qoi_err_est < TOL_ERR_QOI) break; // Returns updated coarse and fine meshes, with the last // coarse and fine mesh solutions on them, respectively. // The coefficient vectors and numbers of degrees of freedom // on both meshes are also updated. adapt(NORM, ADAPT_TYPE, THRESHOLD, ftr_errors, space, ref_space); as++; // Plot meshes, results, and errors. adapt_plotting(space, ref_space, NORM, EXACT_SOL_PROVIDED, exact_sol); // Cleanup. delete ref_space; } while (done == false); info("Total running time: %g s", cpu_time.accumulated()); // Save convergence graphs. graph_dof_est.save("conv_dof_est.dat"); graph_cpu_est.save("conv_cpu_est.dat"); graph_dof_exact.save("conv_dof_exact.dat"); graph_cpu_exact.save("conv_cpu_exact.dat"); // Test variable. bool success = true; info("ndof = %d.", Space::get_num_dofs(space)); if (Space::get_num_dofs(space) > 150) success = false; if (success) { info("Success!"); return ERROR_SUCCESS; } else { info("Failure!"); return ERROR_FAILURE; } }
// Sets some constants, performs uniform mesh refinement // and calculates reference solution. This needs to get // done prior to adaptivity. bool ModuleBasicAdapt::prepare_for_adaptivity() { // Perform basic sanity checks, create mesh, perform // uniform refinements, create space, register weak forms. bool mesh_ok = this->create_space_and_forms(); if (!mesh_ok) return false; this->ndof_coarse = Space::get_num_dofs(this->space); if (this->ndof_coarse <= 0) return false; // Initialize refinement selector. this->ref_selector = new H1ProjBasedSelector(this->cand_list, this->conv_exp, H2DRS_DEFAULT_ORDER); this->ref_selector->set_error_weights(this->adaptivity_weight_1, this->adaptivity_weight_2, this->adaptivity_weight_3); // Construct globally refined reference mesh and setup reference space. this->space_ref = (H1Space*)construct_refined_space(this->space); this->ndof_fine = Space::get_num_dofs(this->space_ref); // Initialize the FE problem on reference mesh. bool is_linear = true; DiscreteProblem dp(this->wf, this->space_ref, is_linear); // Set up the solver, matrix, and rhs according to the solver selection. info("Initializing matrix solver, matrix, and rhs vector."); SparseMatrix* matrix = create_matrix(this->matrix_solver); Vector* rhs = create_vector(this->matrix_solver); Solver* solver = create_linear_solver(this->matrix_solver, matrix, rhs); // Begin assembly time measurement. TimePeriod cpu_time_assembly; cpu_time_assembly.tick(); // Assemble the stiffness matrix and right-hand side vector. info("Assembling matrix and vector on reference mesh."); dp.assemble(matrix, rhs); // End assembly time measurement. this->assembly_time = cpu_time_assembly.accumulated(); this->assembly_time_total += this->assembly_time; // Begin solver time measurement. TimePeriod cpu_time_solver; cpu_time_solver.tick(); // Solve the linear system and if successful, obtain the solution. info("Solving on reference mesh."); if(solver->solve()) Solution::vector_to_solution(solver->get_solution(), this->space_ref, this->sln_ref); else { info("Matrix solver failed.\n"); return false; } // End solver time measurement. cpu_time_solver.tick(); this->solver_time = cpu_time_solver.accumulated(); this->solver_time_total += this->solver_time; // Clean up. info("Deleting matrix solver, matrix and rhs vector."); delete solver; delete matrix; delete rhs; return true; }
int main() { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Create coarse mesh, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); info("N_dof = %d.", Space::get_num_dofs(space)); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(jacobian); wf.add_vector_form(residual); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp_coarse = new DiscreteProblem(&wf, space, is_linear); // Newton's loop on coarse mesh. // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(space); // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec_coarse = new double[Space::get_num_dofs(space)]; solution_to_vector(space, coeff_vec_coarse); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix_coarse = create_matrix(matrix_solver); Vector* rhs_coarse = create_vector(matrix_solver); Solver* solver_coarse = create_linear_solver(matrix_solver, matrix_coarse, rhs_coarse); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof_coarse = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp_coarse->assemble(matrix_coarse, rhs_coarse); // Calculate the l2-norm of residual vector. double res_norm = 0; for(int i=0; i<ndof_coarse; i++) res_norm += rhs_coarse->get(i)*rhs_coarse->get(i); res_norm = sqrt(res_norm); // Info for user. info("---- Newton iter %d, residual norm: %.15f", it, res_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_norm < NEWTON_TOL_COARSE && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i<ndof_coarse; i++) rhs_coarse->set(i, -rhs_coarse->get(i)); // Solve the linear system. if(!solver_coarse->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof_coarse; i++) coeff_vec_coarse[i] += solver_coarse->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. vector_to_solution(coeff_vec_coarse, space); it++; } // Cleanup. delete matrix_coarse; delete rhs_coarse; delete solver_coarse; delete dp_coarse; delete [] coeff_vec_coarse; // DOF and CPU convergence graphs. SimpleGraph graph_dof_est, graph_cpu_est; SimpleGraph graph_dof_exact, graph_cpu_exact; // Main adaptivity loop. int as = 1; while(1) { info("============ Adaptivity step %d ============", as); // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(space); // Initialize the FE problem. bool is_linear = false; DiscreteProblem* dp = new DiscreteProblem(&wf, ref_space, is_linear); // 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); // Newton's loop on fine mesh. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(ref_space)]; solution_to_vector(ref_space, coeff_vec); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(ref_space); // Assemble the Jacobian matrix and residual vector. dp->assemble(matrix, rhs); // Calculate the l2-norm of residual vector. double res_norm = 0; for(int i=0; i<ndof; i++) res_norm += rhs->get(i)*rhs->get(i); res_norm = sqrt(res_norm); // Info for user. info("---- Newton iter %d, residual norm: %.15f", it, res_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_norm < NEWTON_TOL_REF && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i<ndof; i++) rhs->set(i, -rhs->get(i)); // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += solver->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. vector_to_solution(coeff_vec, ref_space); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete dp; delete [] coeff_vec; // Starting with second adaptivity step, obtain new coarse // space solution via Newton's method. Initial condition is // the last coarse mesh solution. if (as > 1) { //Info for user. info("Solving on coarse mesh"); // Initialize the FE problem. bool is_linear = false; DiscreteProblem* dp_coarse = new DiscreteProblem(&wf, space, is_linear); // Newton's loop on coarse mesh. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec_coarse = new double[Space::get_num_dofs(space)]; solution_to_vector(space, coeff_vec_coarse); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix_coarse = create_matrix(matrix_solver); Vector* rhs_coarse = create_vector(matrix_solver); Solver* solver_coarse = create_linear_solver(matrix_solver, matrix_coarse, rhs_coarse); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof_coarse = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp_coarse->assemble(matrix_coarse, rhs_coarse); // Calculate the l2-norm of residual vector. double res_norm = 0; for(int i=0; i<ndof_coarse; i++) res_norm += rhs_coarse->get(i)*rhs_coarse->get(i); res_norm = sqrt(res_norm); // Info for user. info("---- Newton iter %d, residual norm: %.15f", it, res_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_norm < NEWTON_TOL_COARSE && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i<ndof_coarse; i++) rhs_coarse->set(i, -rhs_coarse->get(i)); // Solve the linear system. if(!solver_coarse->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof_coarse; i++) coeff_vec_coarse[i] += solver_coarse->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. vector_to_solution(coeff_vec_coarse, space); it++; } // Cleanup. delete matrix_coarse; delete rhs_coarse; delete solver_coarse; delete dp_coarse; delete [] coeff_vec_coarse; } // In the next step, estimate element errors based on // the difference between the fine mesh and coarse mesh solutions. double err_est_array[MAX_ELEM_NUM]; double err_est_rel = calc_err_est(NORM, space, ref_space, err_est_array) * 100; // Info for user. info("Relative error (est) = %g %%", err_est_rel); // Time measurement. cpu_time.tick(); // If exact solution available, also calculate exact error. if (EXACT_SOL_PROVIDED) { // Calculate element errors wrt. exact solution. double err_exact_rel = calc_err_exact(NORM, space, exact_sol, NEQ, A, B) * 100; // Info for user. info("Relative error (exact) = %g %%", err_exact_rel); // Add entry to DOF and CPU convergence graphs. graph_dof_exact.add_values(Space::get_num_dofs(space), err_exact_rel); graph_cpu_exact.add_values(cpu_time.accumulated(), err_exact_rel); } // Add entry to DOF and CPU convergence graphs. graph_dof_est.add_values(Space::get_num_dofs(space), err_est_rel); graph_cpu_est.add_values(cpu_time.accumulated(), err_est_rel); // Decide whether the relative error is sufficiently small. if(err_est_rel < TOL_ERR_REL) break; // Returns updated coarse and fine meshes, with the last // coarse and fine mesh solutions on them, respectively. // The coefficient vectors and numbers of degrees of freedom // on both meshes are also updated. adapt(NORM, ADAPT_TYPE, THRESHOLD, err_est_array, space, ref_space); as++; // Plot meshes, results, and errors. adapt_plotting(space, ref_space, NORM, EXACT_SOL_PROVIDED, exact_sol); // Cleanup. delete ref_space; } // Save convergence graphs. graph_dof_est.save("conv_dof_est.dat"); graph_cpu_est.save("conv_cpu_est.dat"); graph_dof_exact.save("conv_dof_exact.dat"); graph_cpu_exact.save("conv_cpu_exact.dat"); int success_test = 1; info("N_dof = %d.", Space::get_num_dofs(space)); if (Space::get_num_dofs(space) > 40) success_test = 0; if (success_test) { info("Success!"); return ERROR_SUCCESS; } else { info("Failure!"); return ERROR_FAILURE; } }
int main() { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Create coarse mesh, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); // Enumerate basis functions, info for user. int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(jacobian); wf.add_vector_form(residual); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp_coarse = new DiscreteProblem(&wf, space, is_linear); // Newton's loop on coarse mesh. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec_coarse = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec_coarse); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix_coarse = create_matrix(matrix_solver); Vector* rhs_coarse = create_vector(matrix_solver); Solver* solver_coarse = create_linear_solver(matrix_solver, matrix_coarse, rhs_coarse); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof_coarse = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp_coarse->assemble(coeff_vec_coarse, matrix_coarse, rhs_coarse); // Calculate the l2-norm of residual vector. double res_l2_norm = get_l2_norm(rhs_coarse); // Info for user. info("---- Newton iter %d, ndof %d, res. l2 norm %g", it, Space::get_num_dofs(space), res_l2_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_l2_norm < NEWTON_TOL_COARSE && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i < ndof_coarse; i++) rhs_coarse->set(i, -rhs_coarse->get(i)); // Solve the linear system. if(!solver_coarse->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof_coarse; i++) coeff_vec_coarse[i] += solver_coarse->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. set_coeff_vector(coeff_vec_coarse, space); it++; } // Cleanup. delete matrix_coarse; delete rhs_coarse; delete solver_coarse; delete [] coeff_vec_coarse; delete dp_coarse; // DOF and CPU convergence graphs. SimpleGraph graph_dof_est, graph_cpu_est; SimpleGraph graph_dof_exact, graph_cpu_exact; // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(space); // Initialize the FE problem. bool is_linear = false; DiscreteProblem* dp = new DiscreteProblem(&wf, ref_space, is_linear); // 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); // Newton's loop on the fine mesh. info("Solving on fine mesh:"); // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(ref_space)]; get_coeff_vector(ref_space, coeff_vec); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(ref_space); // Assemble the Jacobian matrix and residual vector. dp->assemble(coeff_vec, matrix, rhs); // Calculate the l2-norm of residual vector. double res_l2_norm = get_l2_norm(rhs); // Info for user. info("---- Newton iter %d, ndof %d, res. l2 norm %g", it, Space::get_num_dofs(ref_space), res_l2_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_l2_norm < NEWTON_TOL_REF && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i = 0; i < ndof; i++) rhs->set(i, -rhs->get(i)); // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += solver->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. set_coeff_vector(coeff_vec, ref_space); it++; } // Starting with second adaptivity step, obtain new coarse // mesh solution via projecting the fine mesh solution. if(as > 1) { info("Projecting the fine mesh solution onto the coarse mesh."); // Project the fine mesh solution (defined on space_ref) onto the coarse mesh (defined on space). OGProjection::project_global(space, ref_space, matrix_solver); } // Calculate element errors and total error estimate. info("Calculating error estimate."); double err_est_array[MAX_ELEM_NUM]; double err_est_rel = calc_err_est(NORM, space, ref_space, err_est_array) * 100; // Report results. info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", Space::get_num_dofs(space), Space::get_num_dofs(ref_space), err_est_rel); // Time measurement. cpu_time.tick(); // If exact solution available, also calculate exact error. if (EXACT_SOL_PROVIDED) { // Calculate element errors wrt. exact solution. double err_exact_rel = calc_err_exact(NORM, space, exact_sol, NEQ, A, B) * 100; // Info for user. info("Relative error (exact) = %g %%", err_exact_rel); // Add entry to DOF and CPU convergence graphs. graph_dof_exact.add_values(Space::get_num_dofs(space), err_exact_rel); graph_cpu_exact.add_values(cpu_time.accumulated(), err_exact_rel); } // Add entry to DOF and CPU convergence graphs. graph_dof_est.add_values(Space::get_num_dofs(space), err_est_rel); graph_cpu_est.add_values(cpu_time.accumulated(), err_est_rel); // If err_est_rel too large, adapt the mesh. if (err_est_rel < NEWTON_TOL_REF) done = true; else { info("Adapting the coarse mesh."); adapt(NORM, ADAPT_TYPE, THRESHOLD, err_est_array, space, ref_space); } as++; // Plot meshes, results, and errors. adapt_plotting(space, ref_space, NORM, EXACT_SOL_PROVIDED, exact_sol); // Cleanup. delete solver; delete matrix; delete rhs; delete ref_space; delete dp; delete [] coeff_vec; } while (done == false); info("Total running time: %g s", cpu_time.accumulated()); // Save convergence graphs. graph_dof_est.save("conv_dof_est.dat"); graph_cpu_est.save("conv_cpu_est.dat"); graph_dof_exact.save("conv_dof_exact.dat"); graph_cpu_exact.save("conv_cpu_exact.dat"); return 0; }