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. info("N_dof = %d", Space::get_num_dofs(space)); // Plot the space. space->plot("space.gp"); for (int g = 0; g < N_GRP; 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, 1, jacobian_fuel_0_1, NULL, fuel); wf.add_matrix_form(1, 0, jacobian_fuel_1_0, NULL, fuel); wf.add_matrix_form(1, 1, jacobian_fuel_1_1, NULL, fuel); wf.add_vector_form(0, residual_fuel_0, NULL, fuel); wf.add_vector_form(1, residual_fuel_1, NULL, fuel); 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); // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space)]; solution_to_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_norm = 0; for(int i=0; i<ndof; i++) res_norm += rhs->get(i)*rhs->get(i); res_norm = sqrt(res_norm); // Info for user. info("---- Newton iter %d, residual norm: %.15f", it, res_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_norm < NEWTON_TOL && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i<ndof; i++) rhs->set(i, -rhs->get(i)); // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += solver->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. vector_to_solution(coeff_vec, space); it++; } // Plot the solution. Linearizer l(space); l.plot_solution("solution.gp"); // Calculate flux integral for comparison with the reference value. double I = calc_integrated_flux(space, 1, 60., 80.); double Iref = 134.9238787715397; info("I = %.13f, err = %.13f%%", I, 100.*(I - Iref)/Iref ); info("Done."); return 1; }
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; }