int main() { // Create coarse mesh, set Dirichlet BC, enumerate // basis functions Mesh *mesh = new Mesh(A, B, N_elem, P_init, N_eq); mesh->set_bc_left_dirichlet(0, Val_dir_left); mesh->set_bc_right_dirichlet(0, Val_dir_right); mesh->assign_dofs(); // Create discrete problem on coarse mesh DiscreteProblem *dp = new DiscreteProblem(); dp->add_matrix_form(0, 0, jacobian); dp->add_vector_form(0, residual); // Convergence graph wrt. the number of degrees of freedom GnuplotGraph graph; graph.set_log_y(); graph.set_captions("Convergence History", "Degrees of Freedom", "Error"); graph.add_row("exact error [%]", "k", "-", "o"); graph.add_row("max FTR error", "k", "--"); // Main adaptivity loop int adapt_iterations = 1; double ftr_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. ElemPtr2 ref_ftr_pairs[MAX_ELEM_NUM]; // To store element pairs from the // FTR solution. Decides how // elements will be hp-refined. for (int i=0; i < MAX_ELEM_NUM; i++) { ref_ftr_pairs[i][0] = new Element(); ref_ftr_pairs[i][1] = new Element(); } while(1) { printf("============ Adaptivity step %d ============\n", adapt_iterations); printf("N_dof = %d\n", mesh->get_n_dof()); // Newton's loop on coarse mesh newton(dp, mesh, NULL, NEWTON_TOL_COARSE, NEWTON_MAXITER); // For every element perform its fast trial refinement (FTR), // calculate the norm of the difference between the FTR // solution and the coarse mesh solution, and store the // error in the ftr_errors[] array. int n_elem = mesh->get_n_active_elem(); for (int i=0; i < n_elem; i++) { printf("=== Starting FTR of Elem [%d]\n", i); // Replicate coarse mesh including solution. Mesh *mesh_ref_local = mesh->replicate(); // Perform FTR of element 'i' mesh_ref_local->reference_refinement(i, 1); printf("Elem [%d]: fine mesh created (%d DOF).\n", i, mesh_ref_local->assign_dofs()); // Newton's loop on the FTR mesh newton(dp, mesh_ref_local, NULL, NEWTON_TOL_REF, NEWTON_MAXITER); // Print FTR solution (enumerated) Linearizer *lxx = new Linearizer(mesh_ref_local); char out_filename[255]; sprintf(out_filename, "solution_ref_%d.gp", i); lxx->plot_solution(out_filename); delete lxx; // Calculate norm of the difference between the coarse mesh // and FTR solutions. // NOTE: later we want to look at the difference in some quantity // of interest rather than error in global norm. double err_est_array[MAX_ELEM_NUM]; ftr_errors[i] = calc_error_estimate(NORM, mesh, mesh_ref_local, err_est_array); //printf("Elem [%d]: absolute error (est) = %g\n", i, ftr_errors[i]); // Copy the reference element pair for element 'i' // into the ref_ftr_pairs[i][] array Iterator *I = new Iterator(mesh); Iterator *I_ref = new Iterator(mesh_ref_local); Element *e, *e_ref; while (1) { e = I->next_active_element(); e_ref = I_ref->next_active_element(); if (e->id == i) { e_ref->copy_into(ref_ftr_pairs[e->id][0]); // coarse element 'e' was split in space if (e->level != e_ref->level) { e_ref = I_ref->next_active_element(); e_ref->copy_into(ref_ftr_pairs[e->id][1]); } break; } } delete I; delete I_ref; delete mesh_ref_local; } // If exact solution available, also calculate exact error if (EXACT_SOL_PROVIDED) { // Calculate element errors wrt. exact solution double err_exact_total = calc_error_exact(NORM, mesh, exact_sol); // Calculate the norm of the exact solution // (using a fine subdivision and high-order quadrature) int subdivision = 500; // heuristic parameter int order = 20; // heuristic parameter double exact_sol_norm = calc_solution_norm(NORM, exact_sol, N_eq, A, B, subdivision, order); // Calculate an estimate of the global relative error double err_exact_rel = err_exact_total/exact_sol_norm; //printf("Relative error (exact) = %g %%\n", 100.*err_exact_rel); graph.add_values(0, mesh->get_n_dof(), 100 * err_exact_rel); } // Calculate max FTR error double max_ftr_error = 0; for (int i=0; i < mesh->get_n_active_elem(); i++) { if (ftr_errors[i] > max_ftr_error) max_ftr_error = ftr_errors[i]; } printf("Max FTR error = %g\n", max_ftr_error); // Add entry to DOF convergence graph graph.add_values(1, mesh->get_n_dof(), max_ftr_error); // Decide whether the max. FTR error is sufficiently small if(max_ftr_error < TOL_ERR_FTR) break; // debug if (adapt_iterations >= 1) break; // Returns updated coarse mesh with the last solution on it. adapt(NORM, ADAPT_TYPE, THRESHOLD, ftr_errors, mesh, ref_ftr_pairs); adapt_iterations++; } // Plot meshes, results, and errors adapt_plotting(mesh, ref_ftr_pairs, NORM, EXACT_SOL_PROVIDED, exact_sol); // Save convergence graph graph.save("conv_dof.gp"); printf("Done.\n"); return 1; }
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); double elem_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. ElemPtr2 ref_elem_pairs[MAX_ELEM_NUM]; // To store element pairs from the // FTR solution. Decides how // elements will be hp-refined. for (int i=0; i < MAX_ELEM_NUM; i++) { ref_elem_pairs[i][0] = new Element(); ref_elem_pairs[i][1] = new Element(); } // DOF and CPU convergence graphs. SimpleGraph graph_dof_exact, graph_cpu_exact; // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // 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(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; // For every element perform its fast trial refinement (FTR), // calculate the norm of the difference between the FTR // solution and the coarse space solution, and store the // error in the elem_errors[] array. int n_elem = space->get_n_active_elem(); for (int i=0; i < n_elem; i++) { info("=== Starting FTR of Elem [%d].", i); // Replicate coarse space including solution. Space *space_ref_local = space->replicate(); // Perform FTR of element 'i' space_ref_local->reference_refinement(i, 1); info("Elem [%d]: fine space created (%d DOF).", i, space_ref_local->assign_dofs()); // Initialize the FE problem. bool is_linear = false; DiscreteProblem* dp = new DiscreteProblem(&wf, space_ref_local, 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 FTR space. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space_ref_local)]; get_coeff_vector(space_ref_local, coeff_vec); memset(coeff_vec, 0, Space::get_num_dofs(space_ref_local)*sizeof(double)); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(space_ref_local); // Assemble the Jacobian matrix and residual vector. dp->assemble(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(space_ref_local), 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, space_ref_local); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete dp; delete [] coeff_vec; // Print FTR solution (enumerated). Linearizer *lxx = new Linearizer(space_ref_local); char out_filename[255]; sprintf(out_filename, "solution_ref_%d.gp", i); lxx->plot_solution(out_filename); delete lxx; // Calculate norm of the difference between the coarse space // and FTR solutions. // NOTE: later we want to look at the difference in some quantity // of interest rather than error in global norm. double err_est_array[MAX_ELEM_NUM]; elem_errors[i] = calc_err_est(NORM, space, space_ref_local, err_est_array) * 100; info("Elem [%d]: absolute error (est) = %g%%", i, elem_errors[i]); // Copy the reference element pair for element 'i'. // into the ref_elem_pairs[i][] array Iterator *I = new Iterator(space); Iterator *I_ref = new Iterator(space_ref_local); Element *e, *e_ref; while (1) { e = I->next_active_element(); e_ref = I_ref->next_active_element(); if (e->id == i) { e_ref->copy_into(ref_elem_pairs[e->id][0]); // coarse element 'e' was split in space. if (e->level != e_ref->level) { e_ref = I_ref->next_active_element(); e_ref->copy_into(ref_elem_pairs[e->id][1]); } break; } } delete I; delete I_ref; delete space_ref_local; } // 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); } // Calculate max FTR error. double max_ftr_error = 0; for (int i=0; i < space->get_n_active_elem(); i++) { if (elem_errors[i] > max_ftr_error) max_ftr_error = elem_errors[i]; } info("Max FTR error = %g%%.", max_ftr_error); // Decide whether the max. FTR error is sufficiently small. if(max_ftr_error < TOL_ERR_FTR) break; // debug //if (as == 4) break; // Returns updated coarse space with the last solution on it. adapt(NORM, ADAPT_TYPE, THRESHOLD, elem_errors, space, ref_elem_pairs); // Plot spaces, results, and errors. adapt_plotting(space, ref_elem_pairs, NORM, EXACT_SOL_PROVIDED, exact_sol); as++; } while (done == false); info("Total running time: %g s", cpu_time.accumulated()); // Save convergence graphs. graph_dof_exact.save("conv_dof_exact.dat"); graph_cpu_exact.save("conv_cpu_exact.dat"); return 0; }
int main() { // Create coarse mesh, set Dirichlet BC, enumerate // basis functions Mesh *mesh = new Mesh(A, B, N_elem, P_init, N_eq); mesh->set_bc_left_dirichlet(0, Val_dir_left); mesh->set_bc_right_dirichlet(0, Val_dir_right); mesh->assign_dofs(); // Create discrete problem on coarse mesh DiscreteProblem *dp = new DiscreteProblem(); dp->add_matrix_form(0, 0, jacobian); dp->add_vector_form(0, residual); // Convergence graph wrt. the number of degrees of freedom // (goal-oriented adaptivity) GnuplotGraph graph_ftr; graph_ftr.set_log_y(); graph_ftr.set_captions("Convergence History", "Degrees of Freedom", "QOI error"); graph_ftr.add_row("QOI error - FTR (exact)", "k", "-", "o"); graph_ftr.add_row("QOI error - FTR (est)", "k", "--"); // Main adaptivity loop int adapt_iterations = 1; double ftr_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. ElemPtr2 ref_ftr_pairs[MAX_ELEM_NUM]; // To store element pairs from the // FTR solution. Decides how // elements will be hp-refined. for (int i=0; i < MAX_ELEM_NUM; i++) { ref_ftr_pairs[i][0] = new Element(); ref_ftr_pairs[i][1] = new Element(); } while(1) { printf("============ Adaptivity step %d ============\n", adapt_iterations); printf("N_dof = %d\n", mesh->get_n_dof()); // Newton's loop on coarse mesh int success; if(JFNK == 0) { newton(dp, mesh, NULL, NEWTON_TOL_COARSE, NEWTON_MAXITER); } else { jfnk_cg(dp, mesh, MATRIX_SOLVER_TOL, MATRIX_SOLVER_MAXITER, JFNK_EPSILON, NEWTON_TOL_COARSE, NEWTON_MAXITER); } // For every element perform its fast trial refinement (FTR), // calculate the norm of the difference between the FTR // solution and the coarse mesh solution, and store the // error in the ftr_errors[] array. int n_elem = mesh->get_n_active_elem(); double max_qoi_err_est = 0; for (int i=0; i < n_elem; i++) { printf("=== Starting FTR of Elem [%d]\n", i); // Replicate coarse mesh including solution. Mesh *mesh_ref_local = mesh->replicate(); // Perform FTR of element 'i' mesh_ref_local->reference_refinement(i, 1); printf("Elem [%d]: fine mesh created (%d DOF).\n", i, mesh_ref_local->assign_dofs()); // Newton's loop on the FTR mesh if(JFNK == 0) { newton(dp, mesh_ref_local, NULL, NEWTON_TOL_COARSE, NEWTON_MAXITER); } else { jfnk_cg(dp, mesh_ref_local, MATRIX_SOLVER_TOL, MATRIX_SOLVER_MAXITER, JFNK_EPSILON, NEWTON_TOL_REF, NEWTON_MAXITER); } // Print FTR solution (enumerated) Linearizer *lxx = new Linearizer(mesh_ref_local); char out_filename[255]; sprintf(out_filename, "solution_ref_%d.gp", i); lxx->plot_solution(out_filename); delete lxx; // Calculate FTR errors for refinement purposes if (GOAL_ORIENTED == 1) { // Use quantity of interest. double qoi_est = quantity_of_interest(mesh, X_QOI); double qoi_ref_est = quantity_of_interest(mesh_ref_local, 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_error_estimate(NORM, mesh, mesh_ref_local, err_est_array); } // 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(mesh, X_QOI); double qoi_ref_est = quantity_of_interest(mesh_ref_local, X_QOI); double err_est = fabs(qoi_ref_est - qoi_est); if (err_est > max_qoi_err_est) max_qoi_err_est = err_est; } // Copy the reference element pair for element 'i' // into the ref_ftr_pairs[i][] array Iterator *I = new Iterator(mesh); Iterator *I_ref = new Iterator(mesh_ref_local); Element *e, *e_ref; while (1) { e = I->next_active_element(); e_ref = I_ref->next_active_element(); if (e->id == i) { e_ref->copy_into(ref_ftr_pairs[e->id][0]); // coarse element 'e' was split in space if (e->level != e_ref->level) { e_ref = I_ref->next_active_element(); e_ref->copy_into(ref_ftr_pairs[e->id][1]); } break; } } delete I; delete I_ref; delete mesh_ref_local; } // Add entries to convergence graphs if (EXACT_SOL_PROVIDED) { double qoi_est = quantity_of_interest(mesh, 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); // plotting error in quantity of interest wrt. exact value graph_ftr.add_values(0, mesh->get_n_dof(), err_qoi_exact); } graph_ftr.add_values(1, mesh->get_n_dof(), 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; // debug if (adapt_iterations == 3) break; // Returns updated coarse mesh with the last solution on it. adapt(NORM, ADAPT_TYPE, THRESHOLD, ftr_errors, mesh, ref_ftr_pairs); adapt_iterations++; } // Plot meshes, results, and errors adapt_plotting(mesh, ref_ftr_pairs, NORM, EXACT_SOL_PROVIDED, exact_sol); // Save convergence graph graph_ftr.save("conv_dof.gp"); printf("Done.\n"); return 1; }