void NonlinearMatrixSolver<Scalar>::solve_linear_system() { // store the previous solution to previous_sln_vector. memcpy(this->previous_sln_vector, this->sln_vector, sizeof(Scalar)*this->problem_size); // Solve, if the solver is iterative, give him the initial guess. this->linear_matrix_solver->solve(this->use_initial_guess_for_iterative_solvers ? this->sln_vector : nullptr); // 1. store the solution. double solution_change_norm = this->update_solution_return_change_norm(this->linear_matrix_solver->get_sln_vector()); // 2. store the solution change. this->get_parameter_value(this->p_solution_change_norms).push_back(solution_change_norm); // 3. store the solution norm. this->get_parameter_value(this->p_solution_norms).push_back(get_l2_norm(this->sln_vector, this->problem_size)); }
bool NonlinearMatrixSolver<Scalar>::do_initial_step_return_finished() { // Store the initial norm. this->get_parameter_value(this->p_solution_norms).push_back(get_l2_norm(this->sln_vector, this->problem_size)); // Assemble the system. if (this->jacobian_reusable && this->constant_jacobian) { this->linear_matrix_solver->set_reuse_scheme(HERMES_REUSE_MATRIX_STRUCTURE_COMPLETELY); this->assemble_residual(false); this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(false); } else { this->linear_matrix_solver->set_reuse_scheme(HERMES_CREATE_STRUCTURE_FROM_SCRATCH); this->assemble(false, false); this->jacobian_reusable = true; this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(true); } // Get the residual norm and act upon it. double residual_norm = this->calculate_residual_norm(); this->info("\n\tNonlinearSolver: initial residual norm: %g", residual_norm); this->get_parameter_value(this->p_residual_norms).push_back(residual_norm); this->solve_linear_system(); if (this->handle_convergence_state_return_finished(this->get_convergence_state())) return true; if (this->on_initial_step_end() == false) { this->info("\tNonlinearSolver: aborted."); this->finalize_solving(); return true; } return false; }
int main() { // Create space, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); info("ndof = %d", Space::get_num_dofs(space)); // Initialize the weak formulation. WeakForm wf(4); wf.add_matrix_form(0, 0, jacobian_1_1); wf.add_matrix_form(0, 2, jacobian_1_3); wf.add_matrix_form(0, 3, jacobian_1_4); wf.add_matrix_form(1, 1, jacobian_2_2); wf.add_matrix_form(1, 2, jacobian_2_3); wf.add_matrix_form(1, 3, jacobian_2_4); wf.add_matrix_form(2, 0, jacobian_3_1); wf.add_matrix_form(2, 1, jacobian_3_2); wf.add_matrix_form(2, 2, jacobian_3_3); wf.add_matrix_form(3, 0, jacobian_4_1); wf.add_matrix_form(3, 1, jacobian_4_2); wf.add_matrix_form(3, 3, jacobian_4_4); wf.add_vector_form(0, residual_1); wf.add_vector_form(1, residual_2); wf.add_vector_form(2, residual_3); wf.add_vector_form(3, residual_4); wf.add_matrix_form_surf(0, 0, jacobian_surf_right_U_Re, BOUNDARY_RIGHT); wf.add_matrix_form_surf(0, 2, jacobian_surf_right_U_Im, BOUNDARY_RIGHT); wf.add_matrix_form_surf(1, 1, jacobian_surf_right_I_Re, BOUNDARY_RIGHT); wf.add_matrix_form_surf(1, 3, jacobian_surf_right_I_Im, BOUNDARY_RIGHT); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); // Set zero initial condition. double *coeff_vec = new double[Space::get_num_dofs(space)]; set_zero(coeff_vec, Space::get_num_dofs(space)); // 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); int it = 1; while (1) { // 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(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 && 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 < Space::get_num_dofs(space); 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 < Space::get_num_dofs(space); 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."); it++; } // Plot the solution. Linearizer l(space); l.plot_solution("solution.gp"); info("Done."); return 0; }
void compute_trajectory(Space *space, DiscreteProblem *dp) { info("alpha = (%g, %g, %g, %g), zeta = (%g, %g, %g, %g)", alpha_ctrl[0], alpha_ctrl[1], alpha_ctrl[2], alpha_ctrl[3], zeta_ctrl[0], zeta_ctrl[1], zeta_ctrl[2], zeta_ctrl[3]); // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(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(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 && 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); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete [] coeff_vec; }
int main() { // Create space. // Transform input data to the format used by the "Space" constructor. SpaceData *md = new SpaceData(verbose); Space* space = new Space(md->N_macroel, md->interfaces, md->poly_orders, md->material_markers, md->subdivisions, N_GRP, N_SLN); delete md; // Enumerate basis functions, info for user. int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Plot the space. space->plot("space.gp"); // Initial approximation of the dominant eigenvalue. double K_EFF = 1.0; // Initial approximation of the dominant eigenvector. double init_val = 1.0; for (int g = 0; g < N_GRP; g++) { set_vertex_dofs_constant(space, init_val, g); space->set_bc_right_dirichlet(g, flux_right_surf[g]); } // Initialize the weak formulation. WeakForm wf(2); wf.add_matrix_form(0, 0, jacobian_fuel_0_0, NULL, fuel); wf.add_matrix_form(0, 0, jacobian_water_0_0, NULL, water); wf.add_matrix_form(0, 1, jacobian_fuel_0_1, NULL, fuel); wf.add_matrix_form(0, 1, jacobian_water_0_1, NULL, water); wf.add_matrix_form(1, 0, jacobian_fuel_1_0, NULL, fuel); wf.add_matrix_form(1, 0, jacobian_water_1_0, NULL, water); wf.add_matrix_form(1, 1, jacobian_fuel_1_1, NULL, fuel); wf.add_matrix_form(1, 1, jacobian_water_1_1, NULL, water); wf.add_vector_form(0, residual_fuel_0, NULL, fuel); wf.add_vector_form(0, residual_water_0, NULL, water); wf.add_vector_form(1, residual_fuel_1, NULL, fuel); wf.add_vector_form(1, residual_water_1, NULL, water); wf.add_vector_form_surf(0, residual_surf_left_0, BOUNDARY_LEFT); wf.add_vector_form_surf(1, residual_surf_left_1, BOUNDARY_LEFT); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); Linearizer l(space); char solution_file[32]; // Source iteration int i; int current_solution = 0, previous_solution = 1; double K_EFF_old; for (i = 0; i < Max_SI; i++) { // Plot the critical (i.e. steady-state) flux in the actual iteration. sprintf(solution_file, "solution_%d.gp", i); l.plot_solution(solution_file); // Store the previous solution (used at the right-hand side). for (int g = 0; g < N_GRP; g++) copy_dofs(current_solution, previous_solution, space, g); // 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 = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(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(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 && 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); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete [] coeff_vec; // Update the eigenvalue. K_EFF_old = K_EFF; K_EFF = calc_total_reaction_rate(space, nSf, 0., 40.); // Convergence test. if (fabs(K_EFF - K_EFF_old)/K_EFF < TOL_SI) break; // Normalize total neutron flux to one fission neutron. multiply_dofs_with_constant(space, 1./K_EFF, current_solution); if (verbose) info("K_EFF_%d = %.8f", i+1, K_EFF); } // Print the converged eigenvalue. info("K_EFF = %.8f, err= %.8f%%", K_EFF, 100*(K_EFF-1)); // Plot the converged critical neutron flux. sprintf(solution_file, "solution.gp"); l.plot_solution(solution_file); // Comparison with analytical results (see the reference above). double flux[N_GRP], J[N_GRP], R; get_solution_at_point(space, 0.0, flux, J); R = flux[0]/flux[1]; info("phi_fast/phi_therm at x=0 : %.4f, err = %.2f%%", R, 100*(R-2.5332)/2.5332); get_solution_at_point(space, 40.0, flux, J); R = flux[0]/flux[1]; info("phi_fast/phi_therm at x=40 : %.4f, err = %.2f%%", R, 100*(R-1.5162)/1.5162); info("Done."); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("square.mesh", &mesh); // Initial mesh refinements. for(int i = 0; i < INIT_GLOB_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary(1, INIT_BDY_REF_NUM); // Create an H1 space with default shapeset. H1Space space(&mesh, bc_types, essential_bc_values, P_INIT); int ndof = Space::get_num_dofs(&space); info("ndof = %d.", ndof); // Solution for the previous time level. Solution u_prev_time; // Initialize the weak formulation. WeakForm wf; if (TIME_INTEGRATION == 1) { wf.add_matrix_form(jac_euler, jac_ord, HERMES_UNSYM, HERMES_ANY, &u_prev_time); wf.add_vector_form(res_euler, res_ord, HERMES_ANY, &u_prev_time); } else { wf.add_matrix_form(jac_cranic, jac_ord, HERMES_UNSYM, HERMES_ANY, &u_prev_time); wf.add_vector_form(res_cranic, res_ord, HERMES_ANY, &u_prev_time); } // Project the function init_cond() on the FE space // to obtain initial coefficient vector for the Newton's method. scalar* coeff_vec = new scalar[Space::get_num_dofs(&space)]; info("Projecting initial condition to obtain initial vector for the Newton's method."); OGProjection::project_global(&space, init_cond, coeff_vec, matrix_solver); Solution::vector_to_solution(coeff_vec, &space, &u_prev_time); // Initialize views. ScalarView sview("Solution", 0, 0, 500, 400); OrderView oview("Mesh", 520, 0, 450, 400); oview.show(&space); sview.show(&u_prev_time); // Time stepping loop: double current_time = 0.0; int t_step = 1; do { info("---- Time step %d, t = %g s.", t_step, current_time); t_step++; // Initialize the FE problem. bool is_linear = false; DiscreteProblem dp(&wf, &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); // Perform Newton's iteration. int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(&space); // Assemble the Jacobian matrix and residual vector. dp.assemble(coeff_vec, matrix, rhs, false); // 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)); // 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), res_l2_norm); // If l2 norm of the residual vector is within tolerance, or the maximum number // of iteration has been reached, then quit. if (res_l2_norm < NEWTON_TOL || it > NEWTON_MAX_ITER) break; // 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 (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); it++; } // Translate the resulting coefficient vector into the Solution sln. Solution::vector_to_solution(coeff_vec, &space, &u_prev_time); // Cleanup. delete matrix; delete rhs; delete solver; // Update time. current_time += TAU; // Show the new time level solution. char title[100]; sprintf(title, "Solution, t = %g", current_time); sview.set_title(title); sview.show(&u_prev_time); } while (current_time < T_FINAL); delete [] coeff_vec; // Wait for all views to be closed. View::wait(); return 0; }
bool rk_time_step(double current_time, double time_step, ButcherTable* const bt, scalar* coeff_vec, scalar* err_vec, DiscreteProblem* dp, MatrixSolverType matrix_solver, bool verbose, bool is_linear, double newton_tol, int newton_max_iter, double newton_damping_coeff, double newton_max_allowed_residual_norm) { // Check for not implemented features. if (matrix_solver != SOLVER_UMFPACK) error("Sorry, rk_time_step() still only works with UMFpack."); if (dp->get_weak_formulation()->get_neq() > 1) error("Sorry, rk_time_step() does not work with systems yet."); // Get number of stages from the Butcher's table. int num_stages = bt->get_size(); // Check whether the user provided a second B-row if he wants // err_vec. if(err_vec != NULL) { double b2_coeff_sum = 0; for (int i=0; i < num_stages; i++) b2_coeff_sum += fabs(bt->get_B2(i)); if (b2_coeff_sum < 1e-10) error("err_vec != NULL but the B2 row in the Butcher's table is zero in rk_time_step()."); } // Matrix for the time derivative part of the equation (left-hand side). UMFPackMatrix* matrix_left = new UMFPackMatrix(); // Matrix and vector for the rest (right-hand side). UMFPackMatrix* matrix_right = new UMFPackMatrix(); UMFPackVector* vector_right = new UMFPackVector(); // Create matrix solver. Solver* solver = create_linear_solver(matrix_solver, matrix_right, vector_right); // Get original space, mesh, and ndof. dp->get_space(0); Mesh* mesh = dp->get_space(0)->get_mesh(); int ndof = dp->get_space(0)->get_num_dofs(); // Create spaces for stage solutions. This is necessary // to define a num_stages x num_stages block weak formulation. Hermes::vector<Space*> stage_spaces; stage_spaces.push_back(dp->get_space(0)); for (int i = 1; i < num_stages; i++) { stage_spaces.push_back(dp->get_space(0)->dup(mesh)); } Space::assign_dofs(stage_spaces); // Create a multistage weak formulation. WeakForm stage_wf_left; // For the matrix M (size ndof times ndof). WeakForm stage_wf_right(num_stages); // For the rest of equation (written on the right), // size num_stages*ndof times num_stages*ndof. create_stage_wf(current_time, time_step, bt, dp, &stage_wf_left, &stage_wf_right); // Initialize discrete problems for the assembling of the // matrix M and the stage Jacobian matrix and residual. DiscreteProblem stage_dp_left(&stage_wf_left, dp->get_space(0)); DiscreteProblem stage_dp_right(&stage_wf_right, stage_spaces); // Vector K_vector of length num_stages * ndof. will represent // the 'k_i' vectors in the usual R-K notation. scalar* K_vector = new scalar[num_stages*ndof]; memset(K_vector, 0, num_stages * ndof * sizeof(scalar)); // Vector u_prev_vec will represent y_n + h \sum_{j=1}^s a_{ij}k_i // in the usual R-K notation. scalar* u_prev_vec = new scalar[num_stages*ndof]; // Vector for the left part of the residual. scalar* vector_left = new scalar[num_stages*ndof]; // Prepare residuals of stage solutions. Hermes::vector<Solution*> residuals; Hermes::vector<bool> add_dir_lift; for (int i = 0; i < num_stages; i++) { residuals.push_back(new Solution(mesh)); add_dir_lift.push_back(false); } // Assemble the block-diagonal mass matrix M of size ndof times ndof. // The corresponding part of the global residual vector is obtained // just by multiplication. stage_dp_left.assemble(matrix_left); // The Newton's loop. double residual_norm; int it = 1; while (true) { // Prepare vector Y_n + h\sum_{j=1}^s a_{ij} K_j. for (int i = 0; i < num_stages; i++) { // block row for (int idx = 0; idx < ndof; idx++) { scalar increment = 0; for (int j = 0; j < num_stages; j++) { increment += bt->get_A(i, j) * K_vector[j*ndof + idx]; } u_prev_vec[i*ndof + idx] = coeff_vec[idx] + time_step * increment; } } multiply_as_diagonal_block_matrix(matrix_left, num_stages, K_vector, vector_left); // Assemble the block Jacobian matrix of the stationary residual F // Diagonal blocks are created even if empty, so that matrix_left // can be added later. bool rhs_only = false; bool force_diagonal_blocks = true; stage_dp_right.assemble(u_prev_vec, matrix_right, vector_right, rhs_only, force_diagonal_blocks); matrix_right->add_to_diagonal_blocks(num_stages, matrix_left); vector_right->add_vector(vector_left); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). vector_right->change_sign(); // Measure the residual norm. if (HERMES_RESIDUAL_AS_VECTOR_RK) { // Calculate the l2-norm of residual vector. residual_norm = get_l2_norm(vector_right); } else { // Translate residual vector into residual functions. Solution::vector_to_solutions(vector_right, stage_dp_right.get_spaces(), residuals, add_dir_lift); residual_norm = calc_norms(residuals); } // Info for the user. if (verbose) info("---- Newton iter %d, ndof %d, residual norm %g", it, ndof, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > newton_max_allowed_residual_norm) { if (verbose) { info("Current residual norm: %g", residual_norm); info("Maximum allowed residual norm: %g", newton_max_allowed_residual_norm); info("Newton solve not successful, returning false."); } return false; } // If residual norm is within tolerance, or the maximum number // of iteration has been reached, or the problem is linear, then quit. if ((residual_norm < newton_tol || it > newton_max_iter) && it > 1) break; // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < num_stages*ndof; i++) { K_vector[i] += newton_damping_coeff * solver->get_solution()[i]; } // If the problem is linear, quit. if (is_linear) { if (verbose) { info("Terminating Newton's loop as problem is linear."); } break; } // Increase iteration counter. it++; } // If max number of iterations was exceeded, fail. if (it >= newton_max_iter) { if (verbose) info("Maximum allowed number of Newton iterations exceeded, returning false."); return false; } // Calculate the vector \sum_{j=1}^s b_j k_j. Vector* rk_increment_vector = create_vector(matrix_solver); rk_increment_vector->alloc(ndof); for (int i = 0; i < ndof; i++) { rk_increment_vector->set(i, 0); for (int j = 0; j < num_stages; j++) { rk_increment_vector->add(i, bt->get_B(j) * K_vector[j*ndof + i]); } } // Calculate Y^{n+1} = Y^n + h \sum_{j=1}^s b_j k_j. for (int i = 0; i < ndof; i++) coeff_vec[i] += time_step * rk_increment_vector->get(i); // If err_vec is not NULL, use the second B-row in the Butcher's // table to calculate the second approximation Y_{n+1}. Then // subtract the original one from it, and return this as an // error vector err_vec. if (err_vec != NULL) { for (int i = 0; i < ndof; i++) { rk_increment_vector->set(i, 0); for (int j = 0; j < num_stages; j++) { rk_increment_vector->add(i, bt->get_B2(j) * K_vector[j*ndof + i]); } } for (int i = 0; i < ndof; i++) err_vec[i] = time_step * rk_increment_vector->get(i); for (int i = 0; i < ndof; i++) err_vec[i] = err_vec[i] - coeff_vec[i]; } // Clean up. delete matrix_left; delete matrix_right; delete vector_right; delete solver; delete rk_increment_vector; // Delete stage spaces, but not the first (original) one. for (int i = 1; i < num_stages; i++) delete stage_spaces[i]; // Delete all residuals. for (int i = 0; i < num_stages; i++) delete residuals[i]; // TODO: Delete stage_wf, in particular its external solutions // stage_time_sol[i], i = 0, 1, ..., num_stages-1. // Delete stage_vec and u_prev_vec. delete [] K_vector; delete [] u_prev_vec; // debug delete [] vector_left; return true; }
int main() { // Create space. // Transform input data to the format used by the "Space" constructor. SpaceData *md = new SpaceData(); Space* space = new Space(md->N_macroel, md->interfaces, md->poly_orders, md->material_markers, md->subdivisions, N_GRP, N_SLN); delete md; // Enumerate basis functions, info for user. int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Plot the space. space->plot("space.gp"); for (int g = 0; g < N_GRP; g++) { space->set_bc_left_dirichlet(g, flux_left_surf[g]); space->set_bc_right_dirichlet(g, flux_right_surf[g]); } // Initialize the weak formulation. WeakForm wf(2); wf.add_matrix_form(0, 0, jacobian_mat1_0_0, NULL, mat1); wf.add_matrix_form(0, 0, jacobian_mat2_0_0, NULL, mat2); wf.add_matrix_form(0, 0, jacobian_mat3_0_0, NULL, mat3); wf.add_matrix_form(0, 1, jacobian_mat1_0_1, NULL, mat1); wf.add_matrix_form(0, 1, jacobian_mat2_0_1, NULL, mat2); wf.add_matrix_form(0, 1, jacobian_mat3_0_1, NULL, mat3); wf.add_matrix_form(1, 0, jacobian_mat1_1_0, NULL, mat1); wf.add_matrix_form(1, 0, jacobian_mat2_1_0, NULL, mat2); wf.add_matrix_form(1, 0, jacobian_mat3_1_0, NULL, mat3); wf.add_matrix_form(1, 1, jacobian_mat1_1_1, NULL, mat1); wf.add_matrix_form(1, 1, jacobian_mat2_1_1, NULL, mat2); wf.add_matrix_form(1, 1, jacobian_mat3_1_1, NULL, mat3); wf.add_vector_form(0, residual_mat1_0, NULL, mat1); wf.add_vector_form(0, residual_mat2_0, NULL, mat2); wf.add_vector_form(0, residual_mat3_0, NULL, mat3); wf.add_vector_form(1, residual_mat1_1, NULL, mat1); wf.add_vector_form(1, residual_mat2_1, NULL, mat2); wf.add_vector_form(1, residual_mat3_1, NULL, mat3); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(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(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 && 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); it++; } // Plot the solution. Linearizer l(space); l.plot_solution("solution.gp"); info("Done."); return 0; }
int main() { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Create space, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); 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 = new DiscreteProblem(&wf, space, is_linear); // Set zero initial condition. double *coeff_vec = new double[ndof]; set_zero(coeff_vec, ndof); // 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); int it = 1; bool success = false; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(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(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 && 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(!(success = 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."); it++; } info("Total running time: %g s", cpu_time.accumulated()); // Test variable. info("ndof = %d.", Space::get_num_dofs(space)); if (success) { info("Success!"); return ERROR_SUCCESS; } else { info("Failure!"); return ERROR_FAILURE; } }
int main() { // Three macroelements are defined above via the interfaces[] array. // poly_orders[]... initial poly degrees of macroelements. // material_markers[]... material markers of macroelements. // subdivisions[]... equidistant subdivision of macroelements. int poly_orders[N_MAT] = {P_init_inner, P_init_outer, P_init_reflector }; int material_markers[N_MAT] = {Marker_inner, Marker_outer, Marker_reflector }; int subdivisions[N_MAT] = {N_subdiv_inner, N_subdiv_outer, N_subdiv_reflector }; // Create space. Space* space = new Space(N_MAT, interfaces, poly_orders, material_markers, subdivisions, N_GRP, N_SLN); // Enumerate basis functions, info for user. info("N_dof = %d", Space::get_num_dofs(space)); // Initial approximation: u = 1. double K_EFF_old; double init_val = 1.0; set_vertex_dofs_constant(space, init_val, 0); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(jacobian_vol_inner, NULL, Marker_inner); wf.add_matrix_form(jacobian_vol_outer, NULL, Marker_outer); wf.add_matrix_form(jacobian_vol_reflector, NULL, Marker_reflector); wf.add_vector_form(residual_vol_inner, NULL, Marker_inner); wf.add_vector_form(residual_vol_outer, NULL, Marker_outer); wf.add_vector_form(residual_vol_reflector, NULL, Marker_reflector); wf.add_vector_form_surf(residual_surf_left, BOUNDARY_LEFT); wf.add_matrix_form_surf(jacobian_surf_right, BOUNDARY_RIGHT); wf.add_vector_form_surf(residual_surf_right, BOUNDARY_RIGHT); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); // Source iteration (power method). for (int i = 0; i < Max_SI; i++) { // Obtain fission source. int current_solution = 0, previous_solution = 1; copy_dofs(current_solution, previous_solution, space); // 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 = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(space); // 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), 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 && 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); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete [] coeff_vec; // Update the eigenvalue. K_EFF_old = K_EFF; K_EFF = calc_fission_yield(space); info("K_EFF_%d = %f", i, K_EFF); if (fabs(K_EFF - K_EFF_old)/K_EFF < TOL_SI) break; } // Plot the critical (i.e. steady-state) neutron flux. Linearizer l(space); l.plot_solution("solution.gp"); // Normalize so that the absolute neutron flux generates 320 Watts of energy // (note that, using the symmetry condition at the origin, we've solved for // flux only in the right half of the reactor). normalize_to_power(space, 320/2.); // Plot the solution and space. l.plot_solution("solution_320W.gp"); space->plot("space.gp"); info("K_EFF = %f", K_EFF); info("Done."); return 0; }
bool rk_time_step(double current_time, double time_step, ButcherTable* const bt, Solution* sln_time_prev, Solution* sln_time_new, Solution* error_fn, DiscreteProblem* dp, MatrixSolverType matrix_solver, bool verbose, bool is_linear, double newton_tol, int newton_max_iter, double newton_damping_coeff, double newton_max_allowed_residual_norm) { // Check for not implemented features. if (matrix_solver != SOLVER_UMFPACK) error("Sorry, rk_time_step() still only works with UMFpack."); if (dp->get_weak_formulation()->get_neq() > 1) error("Sorry, rk_time_step() does not work with systems yet."); // Get number of stages from the Butcher's table. int num_stages = bt->get_size(); // Check whether the user provided a nonzero B2-row if he wants temporal error estimation. if(error_fn != NULL) if (bt->is_embedded() == false) { error("rk_time_step(): R-K method must be embedded if temporal error estimate is requested."); } // Matrix for the time derivative part of the equation (left-hand side). UMFPackMatrix* matrix_left = new UMFPackMatrix(); // Matrix and vector for the rest (right-hand side). UMFPackMatrix* matrix_right = new UMFPackMatrix(); UMFPackVector* vector_right = new UMFPackVector(); // Create matrix solver. Solver* solver = create_linear_solver(matrix_solver, matrix_right, vector_right); // Get space, mesh, and ndof for the stage solutions in the R-K method (K_i vectors). Space* K_space = dp->get_space(0); Mesh* K_mesh = K_space->get_mesh(); int ndof = K_space->get_num_dofs(); // Create spaces for stage solutions K_i. This is necessary // to define a num_stages x num_stages block weak formulation. Hermes::vector<Space*> stage_spaces; stage_spaces.push_back(K_space); for (int i = 1; i < num_stages; i++) { stage_spaces.push_back(K_space->dup(K_mesh)); } Space::assign_dofs(stage_spaces); // Create a multistage weak formulation. WeakForm stage_wf_left; // For the matrix M (size ndof times ndof). WeakForm stage_wf_right(num_stages); // For the rest of equation (written on the right), // size num_stages*ndof times num_stages*ndof. Solution** stage_time_sol = new Solution*[num_stages]; // This array will be filled by artificially created // solutions to represent stage times. create_stage_wf(current_time, time_step, bt, dp, &stage_wf_left, &stage_wf_right, stage_time_sol); // Initialize discrete problems for the assembling of the // matrix M and the stage Jacobian matrix and residual. DiscreteProblem stage_dp_left(&stage_wf_left, K_space); DiscreteProblem stage_dp_right(&stage_wf_right, stage_spaces); // Vector K_vector of length num_stages * ndof. will represent // the 'K_i' vectors in the usual R-K notation. scalar* K_vector = new scalar[num_stages*ndof]; memset(K_vector, 0, num_stages * ndof * sizeof(scalar)); // Vector u_ext_vec will represent h \sum_{j=1}^s a_{ij} K_i. scalar* u_ext_vec = new scalar[num_stages*ndof]; // Vector for the left part of the residual. scalar* vector_left = new scalar[num_stages*ndof]; // Prepare residuals of stage solutions. Hermes::vector<Solution*> residuals; Hermes::vector<bool> add_dir_lift; for (int i = 0; i < num_stages; i++) { residuals.push_back(new Solution(K_mesh)); add_dir_lift.push_back(false); } // Assemble the block-diagonal mass matrix M of size ndof times ndof. // The corresponding part of the global residual vector is obtained // just by multiplication. stage_dp_left.assemble(matrix_left); // The Newton's loop. double residual_norm; int it = 1; while (true) { // Prepare vector h\sum_{j=1}^s a_{ij} K_j. for (int i = 0; i < num_stages; i++) { // block row for (int idx = 0; idx < ndof; idx++) { scalar increment = 0; for (int j = 0; j < num_stages; j++) { increment += bt->get_A(i, j) * K_vector[j*ndof + idx]; } u_ext_vec[i*ndof + idx] = time_step * increment; } } multiply_as_diagonal_block_matrix(matrix_left, num_stages, K_vector, vector_left); // Assemble the block Jacobian matrix of the stationary residual F // Diagonal blocks are created even if empty, so that matrix_left // can be added later. bool rhs_only = false; bool force_diagonal_blocks = true; stage_dp_right.assemble(u_ext_vec, matrix_right, vector_right, rhs_only, force_diagonal_blocks, false); // false = do not add Dirichlet lift while // converting u_ext_vec into Solutions. matrix_right->add_to_diagonal_blocks(num_stages, matrix_left); vector_right->add_vector(vector_left); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). vector_right->change_sign(); // Measure the residual norm. if (HERMES_RESIDUAL_AS_VECTOR_RK) { // Calculate the l2-norm of residual vector. residual_norm = get_l2_norm(vector_right); } else { // Translate residual vector into residual functions. Solution::vector_to_solutions(vector_right, stage_dp_right.get_spaces(), residuals, add_dir_lift); residual_norm = calc_norms(residuals); } // Info for the user. if (verbose) info("---- Newton iter %d, ndof %d, residual norm %g", it, ndof, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > newton_max_allowed_residual_norm) { if (verbose) { info("Current residual norm: %g", residual_norm); info("Maximum allowed residual norm: %g", newton_max_allowed_residual_norm); info("Newton solve not successful, returning false."); } return false; } // If residual norm is within tolerance, or the maximum number // of iteration has been reached, or the problem is linear, then quit. if ((residual_norm < newton_tol || it > newton_max_iter) && it > 1) break; // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaK^{n+1} to K^n. for (int i = 0; i < num_stages*ndof; i++) { K_vector[i] += newton_damping_coeff * solver->get_solution()[i]; } // If the problem is linear, quit. if (is_linear) { if (verbose) { info("Terminating Newton's loop as problem is linear."); } break; } // Increase iteration counter. it++; } // If max number of iterations was exceeded, fail. if (it >= newton_max_iter) { if (verbose) info("Maximum allowed number of Newton iterations exceeded, returning false."); return false; } // Project previous time level solution on the stage space, // to be able to add them together. The result of the projection // will be stored in the vector coeff_vec. // FIXME - this projection is slow and it is not needed when the // spaces are the same (if spatial adaptivity does not take place). scalar* coeff_vec = new scalar[ndof]; OGProjection::project_global(K_space, sln_time_prev, coeff_vec, matrix_solver); // Calculate new time level solution in the stage space (u_{n+1} = u_n + h \sum_{j=1}^s b_j k_j). for (int i = 0; i < ndof; i++) { for (int j = 0; j < num_stages; j++) { coeff_vec[i] += time_step * bt->get_B(j) * K_vector[j*ndof + i]; } } Solution::vector_to_solution(coeff_vec, K_space, sln_time_new); // If error_fn is not NULL, use the B2-row in the Butcher's // table to calculate the temporal error estimate. if (error_fn != NULL) { for (int i = 0; i < ndof; i++) { coeff_vec[i] = 0; for (int j = 0; j < num_stages; j++) { coeff_vec[i] += (bt->get_B(j) - bt->get_B2(j)) * K_vector[j*ndof + i]; } coeff_vec[i] *= time_step; } Solution::vector_to_solution(coeff_vec, K_space, error_fn, false); } // Clean up. delete matrix_left; delete matrix_right; delete vector_right; delete solver; // Delete stage spaces, but not the first (original) one. for (int i = 1; i < num_stages; i++) delete stage_spaces[i]; // Delete all residuals. for (int i = 0; i < num_stages; i++) delete residuals[i]; // Delete artificial Solutions with stage times. for (int i = 0; i < num_stages; i++) delete stage_time_sol[i]; delete [] stage_time_sol; // Clean up. delete [] K_vector; delete [] u_ext_vec; delete [] coeff_vec; delete [] vector_left; return true; }
double NonlinearMatrixSolver<Scalar>::calculate_residual_norm() { return get_l2_norm(this->get_residual()); }
void NonlinearMatrixSolver<Scalar>::solve(Scalar* coeff_vec) { // Initialization. this->init_solving(coeff_vec); #pragma region parameter_setup // Initialize parameters. unsigned int successful_steps_damping = 0; unsigned int successful_steps_jacobian = 0; std::vector<bool> iterations_with_recalculated_jacobian; std::vector<double> residual_norms; std::vector<double> solution_norms; std::vector<double> solution_change_norms; std::vector<double> damping_factors; bool residual_norm_drop; unsigned int iteration = 1; // Initial damping factor. damping_factors.push_back(this->manual_damping ? manual_damping_factor : initial_auto_damping_factor); // Link parameters. this->set_parameter_value(this->p_residual_norms, &residual_norms); this->set_parameter_value(this->p_solution_norms, &solution_norms); this->set_parameter_value(this->p_solution_change_norms, &solution_change_norms); this->set_parameter_value(this->p_successful_steps_damping, &successful_steps_damping); this->set_parameter_value(this->p_successful_steps_jacobian, &successful_steps_jacobian); this->set_parameter_value(this->p_residual_norm_drop, &residual_norm_drop); this->set_parameter_value(this->p_damping_factors, &damping_factors); this->set_parameter_value(this->p_iterations_with_recalculated_jacobian, &iterations_with_recalculated_jacobian); this->set_parameter_value(this->p_iteration, &iteration); #pragma endregion // Does the initial step & checks the convergence & deallocates. if (this->do_initial_step_return_finished()) return; // Main Nonlinear loop while (true) { // Handle the event of step beginning. if (!this->on_step_begin()) { this->info("\tNonlinearSolver: aborted."); this->finalize_solving(); return; } #pragma region damping_factor_loop this->info("\n\tNonlinearSolver: Damping factor handling:"); // Loop searching for the damping factor. do { // Assemble just the residual. this->assemble_residual(false); // Current residual norm. this->get_parameter_value(this->p_residual_norms).push_back(this->calculate_residual_norm()); // Test convergence - if in this loop we found a solution. this->info("\tNonlinearSolver: Convergence test..."); if (this->handle_convergence_state_return_finished(this->get_convergence_state())) return; // Inspect the damping factor. this->info("\tNonlinearSolver: Probing the damping factor..."); try { // Calculate damping factor, and return whether or not was this a successful step. residual_norm_drop = this->calculate_damping_factor(successful_steps_damping); } catch (Exceptions::NonlinearException& e) { this->finalize_solving(); throw e; return; } if (!residual_norm_drop) { // Delete the previous residual and solution norm. residual_norms.pop_back(); solution_norms.pop_back(); // Adjust the previous solution change norm. solution_change_norms.back() /= this->auto_damping_ratio; // Try with the different damping factor. // Important thing here is the factor used that must be calculated from the current one and the previous one. // This results in the following relation (since the damping factor is only updated one way). for (int i = 0; i < this->problem_size; i++) this->sln_vector[i] = this->previous_sln_vector[i] + (this->sln_vector[i] - this->previous_sln_vector[i]) / this->auto_damping_ratio; // Add new_ solution norm. solution_norms.push_back(get_l2_norm(this->sln_vector, this->problem_size)); } } while (!residual_norm_drop); #pragma endregion // Damping factor was updated, handle the event. this->on_damping_factor_updated(); #pragma region jacobian_reusage_loop this->info("\n\tNonlinearSolver: Jacobian handling:"); // Loop until jacobian is not reusable anymore. // The whole loop is skipped if the jacobian is not suitable for being reused at all. while (this->jacobian_reusable && (this->constant_jacobian || force_reuse_jacobian_values(successful_steps_jacobian))) { this->residual_back->set_vector(this->get_residual()); // Info & handle the situation as necessary. this->info("\tNonlinearSolver: Reusing Jacobian."); this->on_reused_jacobian_step_begin(); // Solve the system. this->linear_matrix_solver->set_reuse_scheme(HERMES_REUSE_MATRIX_STRUCTURE_COMPLETELY); this->solve_linear_system(); // Assemble next residual for both reusage and convergence test. this->assemble_residual(false); // Current residual norm. this->get_parameter_value(this->p_residual_norms).push_back(this->calculate_residual_norm()); // Test whether it was okay to reuse the jacobian. if (!this->jacobian_reused_okay(successful_steps_jacobian)) { this->warn("\tNonlinearSolver: Reused Jacobian disapproved."); this->get_parameter_value(this->p_residual_norms).pop_back(); this->get_parameter_value(this->p_solution_norms).pop_back(); this->get_parameter_value(this->p_solution_change_norms).pop_back(); memcpy(this->sln_vector, this->previous_sln_vector, sizeof(Scalar)*this->problem_size); this->get_residual()->set_vector(residual_back); break; } // Increase the iteration count. this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(false); this->get_parameter_value(this->p_iteration)++; // Output successful reuse info. this->step_info(); // Handle the event of end of a step. this->on_reused_jacobian_step_end(); if (!this->on_step_end()) { this->info("\tNonlinearSolver: aborted."); this->finalize_solving(); return; } // Test convergence - if in this iteration we found a solution. if (this->handle_convergence_state_return_finished(this->get_convergence_state())) return; } #pragma endregion // Reassemble the jacobian once not reusable anymore. this->info("\tNonlinearSolver: Re-calculating Jacobian."); // Set factorization scheme. this->assemble_jacobian(true); this->linear_matrix_solver->set_reuse_scheme(HERMES_CREATE_STRUCTURE_FROM_SCRATCH); // Solve the system, state that the jacobian is reusable should it be desirable. this->solve_linear_system(); this->jacobian_reusable = true; // Increase the iteration count. this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(true); this->get_parameter_value(this->p_iteration)++; // Output info. this->step_info(); // Handle the event of end of a step. if (!this->on_step_end()) { this->info("\tNonlinearSolver: aborted."); this->finalize_solving(); return; } // Test convergence - if in this iteration we found a solution. if (this->handle_convergence_state_return_finished(this->get_convergence_state())) return; } }
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); 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(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; // 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(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(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 >= 1) 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"); // Test variable. bool success = true; info("ndof = %d.", Space::get_num_dofs(space)); if (Space::get_num_dofs(space) > 35) success = false; if (success) { info("Success!"); return ERROR_SUCCESS; } else { info("Failure!"); return ERROR_FAILURE; } }
int main() { // Create space. // Transform input data to the format used by the "Space" constructor. SpaceData *md = new SpaceData(); // Boundary conditions. Hermes::vector<BCSpec *>DIR_BC_LEFT; Hermes::vector<BCSpec *>DIR_BC_RIGHT; for (int g = 0; g < N_GRP; g++) { DIR_BC_LEFT.push_back(new BCSpec(g,flux_left_surf[g])); DIR_BC_RIGHT.push_back(new BCSpec(g,flux_right_surf[g])); } Space* space = new Space(md->N_macroel, md->interfaces, md->poly_orders, md->material_markers, md->subdivisions, DIR_BC_LEFT, DIR_BC_RIGHT, N_GRP, N_SLN); delete md; // Enumerate basis functions, info for user. int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Plot the space. // Initialize the weak formulation. WeakForm wf(2); wf.add_matrix_form(0, 0, jacobian_mat1_0_0, NULL, mat1); wf.add_matrix_form(0, 0, jacobian_mat2_0_0, NULL, mat2); wf.add_matrix_form(0, 0, jacobian_mat3_0_0, NULL, mat3); wf.add_matrix_form(0, 1, jacobian_mat1_0_1, NULL, mat1); wf.add_matrix_form(0, 1, jacobian_mat2_0_1, NULL, mat2); wf.add_matrix_form(0, 1, jacobian_mat3_0_1, NULL, mat3); wf.add_matrix_form(1, 0, jacobian_mat1_1_0, NULL, mat1); wf.add_matrix_form(1, 0, jacobian_mat2_1_0, NULL, mat2); wf.add_matrix_form(1, 0, jacobian_mat3_1_0, NULL, mat3); wf.add_matrix_form(1, 1, jacobian_mat1_1_1, NULL, mat1); wf.add_matrix_form(1, 1, jacobian_mat2_1_1, NULL, mat2); wf.add_matrix_form(1, 1, jacobian_mat3_1_1, NULL, mat3); wf.add_vector_form(0, residual_mat1_0, NULL, mat1); wf.add_vector_form(0, residual_mat2_0, NULL, mat2); wf.add_vector_form(0, residual_mat3_0, NULL, mat3); wf.add_vector_form(1, residual_mat1_1, NULL, mat1); wf.add_vector_form(1, residual_mat2_1, NULL, mat2); wf.add_vector_form(1, residual_mat3_1, NULL, mat3); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp->assemble(coeff_vec, matrix, rhs); #include "../../../hermes_common/solver/umfpack_solver.h" CSCMatrix *mm = static_cast<CSCMatrix*>(matrix); UMFPackVector *mv = static_cast<UMFPackVector*>(rhs); FILE *fp = fopen("data.m", "wt"); mm->dump(fp, "A"); mv->dump(fp, "b"); fclose(fp); // 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), 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 && 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); it++; } // Plot the solution. Linearizer l(space); l.plot_solution("solution.gp"); // Cleanup. for(unsigned i = 0; i < DIR_BC_LEFT.size(); i++) delete DIR_BC_LEFT[i]; DIR_BC_LEFT.clear(); for(unsigned i = 0; i < DIR_BC_RIGHT.size(); i++) delete DIR_BC_RIGHT[i]; DIR_BC_RIGHT.clear(); delete matrix; delete rhs; delete solver; delete[] coeff_vec; delete dp; delete space; info("Done."); return 0; }
int main() { // Create space, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(jacobian_vol); wf.add_vector_form(residual_vol); wf.add_vector_form_surf(0, residual_surf_right, BOUNDARY_RIGHT); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(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(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 && 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); it++; } // Plot the solution. Linearizer l(space); l.plot_solution("solution.gp"); // Plot the resulting space. space->plot("space.gp"); info("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; } }
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; }
int main() { // Create space, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); 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. DiscreteProblem *dp = new DiscreteProblem(&wf, space); // Allocate coefficient vector. double *coeff_vec = new double[ndof]; memset(coeff_vec, 0, ndof*sizeof(double)); // 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); // Time stepping loop. double current_time = 0.0; while (current_time < T_FINAL) { // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. get_coeff_vector(space, coeff_vec); int it = 1; while (true) { // 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(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 && 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); it++; } // Plot the solution. Linearizer l(space); char filename[100]; sprintf(filename, "solution_%g.gp", current_time); l.plot_solution(filename); info("Solution %s written.", filename); current_time += TAU; } // Plot the resulting space. space->plot("space.gp"); // Cleaning delete dp; delete rhs; delete solver; delete[] coeff_vec; delete space; delete matrix; info("Done."); return 0; }