35 #include <oomph-lib-config.h> 68 template<
typename MATRIX>
80 "No matrix was stored -- cannot re-solve",
81 OOMPH_CURRENT_FUNCTION,
82 OOMPH_EXCEPTION_LOCATION);
87 this->solve(Matrix_pt,rhs,result);
99 template<
typename MATRIX>
107 clock_t t_start = clock();
118 Matrix_pt=
new MATRIX;
124 Matrix_can_be_deleted=
true;
129 Jacobian_setup_time= t_end-t_start;
131 clock_t t_end = clock();
132 Jacobian_setup_time=double(t_end-t_start)/CLOCKS_PER_SEC;
137 oomph_info <<
"Time for setup of Jacobian [sec]: " 138 << Jacobian_setup_time << std::endl;
142 if (dynamic_cast<DistributableLinearAlgebraObject*>(Matrix_pt))
145 this->build_distribution(dynamic_cast<DistributableLinearAlgebraObject*>
146 (Matrix_pt)->distribution_pt());
155 if((result.
built()) &&
160 result.
build(this->distribution_pt(),0.0);
161 this->solve_helper(Matrix_pt,f,result);
166 this->solve_helper(Matrix_pt,f,result);
170 if (!Enable_resolve) clean_up_memory();
184 template<
typename MATRIX>
193 std::ostringstream error_message_stream;
195 <<
"The vectors rhs must be setup";
197 OOMPH_CURRENT_FUNCTION,
198 OOMPH_EXCEPTION_LOCATION);
202 if (matrix_pt->
nrow() != matrix_pt->
ncol())
204 std::ostringstream error_message_stream;
206 <<
"The matrix at matrix_pt must be square.";
208 OOMPH_CURRENT_FUNCTION,
209 OOMPH_EXCEPTION_LOCATION);
213 if (matrix_pt->
nrow() != rhs.
nrow())
215 std::ostringstream error_message_stream;
217 <<
"The matrix and the rhs vector must have the same number of rows.";
219 OOMPH_CURRENT_FUNCTION,
220 OOMPH_EXCEPTION_LOCATION);
227 if (dist_matrix_pt != 0)
231 std::ostringstream error_message_stream;
233 <<
"The matrix matrix_pt must have the same communicator as the vectors" 234 <<
" rhs and result must have the same communicator";
236 OOMPH_CURRENT_FUNCTION,
237 OOMPH_EXCEPTION_LOCATION);
246 std::ostringstream error_message_stream;
248 <<
"The matrix (matrix_pt) is not distributable and therefore the rhs" 249 <<
" vector must not be distributed";
251 OOMPH_CURRENT_FUNCTION,
252 OOMPH_EXCEPTION_LOCATION);
257 if (solution.
built())
261 std::ostringstream error_message_stream;
263 <<
"The solution vector distribution has been setup; it must have the " 264 <<
"same distribution as the rhs vector.";
266 OOMPH_CURRENT_FUNCTION,
267 OOMPH_EXCEPTION_LOCATION);
275 solution.
build(this->distribution_pt(),0.0);
285 unsigned nrow_local = this->nrow_local();
291 clock_t t_start = clock();
297 double residual_norm = residual.
norm();
298 double rhs_norm = residual_norm;
299 if (rhs_norm==0.0) rhs_norm=1.0;
306 double normalised_residual_norm=residual_norm/rhs_norm;
310 if (Doc_convergence_history)
312 if (!Output_file_stream.is_open())
315 << normalised_residual_norm << std::endl;
319 Output_file_stream << 0 <<
" " 320 << normalised_residual_norm << std::endl;
325 if (normalised_residual_norm<Tolerance)
329 oomph_info <<
"BiCGStab converged immediately" << std::endl;
335 Solution_time = t_end-t_start;
339 oomph_info <<
"Time for solve with BiCGStab [sec]: " 340 << Solution_time << std::endl;
349 if (Setup_preconditioner_before_solve)
354 preconditioner_pt()->setup(matrix_pt);
358 Preconditioner_setup_time = t_end_prec-t_start_prec;
362 oomph_info <<
"Time for setup of preconditioner [sec]: " 363 << Preconditioner_setup_time << std::endl;
371 oomph_info <<
"Setup of preconditioner is bypassed in resolve mode" 380 double rho,beta,dot_prod,dot_prod_tt,dot_prod_ts;
381 double s_norm,r_norm;
384 DoubleVector p(this->distribution_pt(),0.0),p_hat(this->distribution_pt(),0.0),
385 v(this->distribution_pt(),0.0),z(this->distribution_pt(),0.0),
t(this->distribution_pt(),0.0),
386 s(this->distribution_pt(),0.0);
389 for (
unsigned iter=1;iter<=
Max_iter;iter++)
392 rho = r_hat.
dot(residual);
397 oomph_info <<
"BiCGStab has broken down after " << iter
398 <<
" iterations" << std::endl;
399 oomph_info <<
"Returning with current normalised residual of " 400 << normalised_residual_norm << std::endl;
410 beta=(rho/rho_prev)*(alpha/omega);
411 for (
unsigned i=0;
i<nrow_local;
i++)
413 p[
i] = residual[
i] + beta*(p[
i]-omega*v[
i]);
418 preconditioner_pt()->preconditioner_solve(p,p_hat);
422 dot_prod = r_hat.
dot(v);
424 for (
unsigned i=0;
i<nrow_local;
i++)
426 s[
i]=residual[
i]-alpha*v[
i];
431 normalised_residual_norm=s_norm/rhs_norm;
435 if (Doc_convergence_history)
437 if (!Output_file_stream.is_open())
440 << normalised_residual_norm << std::endl;
444 Output_file_stream << double(iter-0.5) <<
" " 445 << normalised_residual_norm <<std::endl;
450 if (normalised_residual_norm<Tolerance)
452 for (
unsigned i=0;
i<nrow_local;
i++)
454 solution[
i]=x[
i]+alpha*p_hat[
i];
460 oomph_info <<
"BiCGStab converged. Normalised residual norm: " 461 << normalised_residual_norm << std::endl;
462 oomph_info <<
"Number of iterations to convergence: " 463 << iter << std::endl;
472 Solution_time = t_end-t_start;
476 oomph_info <<
"Time for solve with BiCGStab [sec]: " 477 << Solution_time << std::endl;
484 preconditioner_pt()->preconditioner_solve(s,z);
488 dot_prod_ts=
t.dot(s);
489 dot_prod_tt=
t.dot(
t);
490 omega=dot_prod_ts/dot_prod_tt;
491 for (
unsigned i=0;
i<nrow_local;
i++)
493 x[
i]+=alpha*p_hat[
i]+omega*z[
i];
494 residual[
i]=s[
i]-omega*
t[
i];
496 r_norm = residual.
norm();
500 normalised_residual_norm=r_norm/rhs_norm;
504 if (Doc_convergence_history)
506 if (!Output_file_stream.is_open())
509 << normalised_residual_norm << std::endl;
513 Output_file_stream << iter <<
" " 514 << normalised_residual_norm << std::endl;
519 if (normalised_residual_norm<Tolerance)
524 oomph_info <<
"BiCGStab converged. Normalised residual norm: " 525 << normalised_residual_norm << std::endl;
526 oomph_info <<
"Number of iterations to convergence: " 527 << iter << std::endl;
537 Solution_time = t_end-t_start;
541 oomph_info <<
"Time for solve with BiCGStab [sec]: " 542 << Solution_time << std::endl;
552 oomph_info <<
"BiCGStab breakdown with omega=0.0. " 553 <<
"Normalised residual norm: " 554 << normalised_residual_norm << std::endl;
555 oomph_info <<
"Number of iterations so far: " << iter << std::endl;
564 Solution_time = t_end-t_start;
568 oomph_info <<
"Time for solve with BiCGStab [sec]: " 569 << Solution_time << std::endl;
581 oomph_info <<
"BiCGStab did not converge to required tolerance! " 583 oomph_info <<
"Returning with normalised residual norm: " 584 << normalised_residual_norm << std::endl;
592 Solution_time = t_end-t_start;
596 oomph_info <<
"Time for solve with BiCGStab [sec]: " 597 << Solution_time << std::endl;
600 if(Throw_error_after_max_iter)
602 std::string err =
"Solver failed to converge and you requested an error";
603 err +=
" on convergence failures.";
605 OOMPH_CURRENT_FUNCTION);
624 template<
typename MATRIX>
633 std::ostringstream error_message_stream;
635 <<
"The vectors rhs must be setup";
637 OOMPH_CURRENT_FUNCTION,
638 OOMPH_EXCEPTION_LOCATION);
642 if (matrix_pt->
nrow() != matrix_pt->
ncol())
644 std::ostringstream error_message_stream;
646 <<
"The matrix at matrix_pt must be square.";
648 OOMPH_CURRENT_FUNCTION,
649 OOMPH_EXCEPTION_LOCATION);
653 if (matrix_pt->
nrow() != rhs.
nrow())
655 std::ostringstream error_message_stream;
657 <<
"The matrix and the rhs vector must have the same number of rows.";
659 OOMPH_CURRENT_FUNCTION,
660 OOMPH_EXCEPTION_LOCATION);
667 if (dist_matrix_pt != 0)
671 std::ostringstream error_message_stream;
673 <<
"The matrix matrix_pt must have the same communicator as the vectors" 674 <<
" rhs and result must have the same communicator";
676 OOMPH_CURRENT_FUNCTION,
677 OOMPH_EXCEPTION_LOCATION);
686 std::ostringstream error_message_stream;
688 <<
"The matrix (matrix_pt) is not distributable and therefore the rhs" 689 <<
" vector must not be distributed";
691 OOMPH_CURRENT_FUNCTION,
692 OOMPH_EXCEPTION_LOCATION);
697 if (solution.
built())
701 std::ostringstream error_message_stream;
703 <<
"The solution vector distribution has been setup; it must have the " 704 <<
"same distribution as the rhs vector.";
706 OOMPH_CURRENT_FUNCTION,
707 OOMPH_EXCEPTION_LOCATION);
715 solution.
build(this->distribution_pt(),0.0);
725 unsigned nrow_local = this->nrow_local();
728 unsigned counter = 0;
737 double residual_norm = residual.
norm();
738 double rhs_norm=residual_norm;
739 if (rhs_norm==0.0) rhs_norm=1.0;
742 double normalised_residual_norm=residual_norm/rhs_norm;
746 if (Doc_convergence_history)
748 if (!Output_file_stream.is_open())
751 << normalised_residual_norm <<std::endl;
755 Output_file_stream << 0 <<
" " 756 << normalised_residual_norm <<std::endl;
761 if (normalised_residual_norm<Tolerance)
765 oomph_info <<
"CG converged immediately" << std::endl;
771 Solution_time = t_end-t_start;
775 oomph_info <<
"Time for solve with CG [sec]: " 776 << Solution_time << std::endl;
786 if (Setup_preconditioner_before_solve)
791 preconditioner_pt()->setup(matrix_pt);
795 Preconditioner_setup_time = t_end_prec-t_start_prec;
799 oomph_info <<
"Time for setup of preconditioner [sec]: " 800 << Preconditioner_setup_time << std::endl;
808 oomph_info <<
"Setup of preconditioner is bypassed in resolve mode" 816 DoubleVector z(this->distribution_pt(),0.0), p(this->distribution_pt(),0.0),
817 jacobian_times_p(this->distribution_pt(),0.0);
820 double alpha,beta,rz;
824 while((normalised_residual_norm>Tolerance)&&(counter!=
Max_iter))
828 preconditioner_pt()->preconditioner_solve(residual,z);
841 for (
unsigned i=0;
i<nrow_local;
i++)
849 matrix_pt->
multiply(p,jacobian_times_p);
850 double pq = p.dot(jacobian_times_p);
855 for(
unsigned i=0;
i<nrow_local;
i++)
858 residual[
i]-=alpha*jacobian_times_p[
i];
863 residual_norm = residual.
norm();
866 normalised_residual_norm=residual_norm/rhs_norm;
871 if (Doc_convergence_history)
873 if (!Output_file_stream.is_open())
876 << normalised_residual_norm << std::endl;
880 Output_file_stream << counter <<
" " 881 << normalised_residual_norm << std::endl;
893 oomph_info <<
"CG did not converge to required tolerance! " << std::endl;
894 oomph_info <<
"Returning with normalised residual norm: " 895 << normalised_residual_norm << std::endl;
896 oomph_info <<
"after " << counter <<
" iterations." << std::endl;
904 oomph_info <<
"CG converged. Normalised residual norm: " 905 << normalised_residual_norm << std::endl;
906 oomph_info <<
"Number of iterations to convergence: " 907 << counter << std::endl;
914 Iterations = counter;
921 Solution_time = t_end-t_start;
925 oomph_info <<
"Time for solve with CG [sec]: " 926 << Solution_time << std::endl;
929 if((counter >=
Max_iter) && (Throw_error_after_max_iter))
931 std::string err =
"Solver failed to converge and you requested an error";
932 err +=
" on convergence failures.";
934 OOMPH_CURRENT_FUNCTION);
945 template<
typename MATRIX>
957 "No matrix was stored -- cannot re-solve",
958 OOMPH_CURRENT_FUNCTION,
959 OOMPH_EXCEPTION_LOCATION);
964 this->solve(Matrix_pt,rhs,result);
977 template<
typename MATRIX>
991 Matrix_pt=
new MATRIX;
996 Matrix_can_be_deleted=
true;
1000 Jacobian_setup_time= t_end-t_start;
1004 oomph_info <<
"Time for setup of Jacobian [sec]: " 1005 << Jacobian_setup_time << std::endl;
1009 if (dynamic_cast<DistributableLinearAlgebraObject*>(Matrix_pt))
1012 this->build_distribution(dynamic_cast<DistributableLinearAlgebraObject*>
1013 (Matrix_pt)->distribution_pt());
1024 result.
build(this->distribution_pt(),0.0);
1032 result.
build(this->distribution_pt(),0.0);
1033 this->solve_helper(Matrix_pt,f,result);
1038 this->solve_helper(Matrix_pt,f,result);
1042 if (!Enable_resolve) clean_up_memory();
1057 template<
typename MATRIX>
1061 const double& n_dof)
1065 if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt) != 0)
1067 if (dynamic_cast<DistributableLinearAlgebraObject*>
1070 std::ostringstream error_message_stream;
1071 error_message_stream <<
"The matrix must not be distributed.";
1073 OOMPH_CURRENT_FUNCTION,
1074 OOMPH_EXCEPTION_LOCATION);
1080 std::ostringstream error_message_stream;
1081 error_message_stream <<
"The rhs vector distribution must be setup.";
1083 OOMPH_CURRENT_FUNCTION,
1084 OOMPH_EXCEPTION_LOCATION);
1087 if(rhs.
nrow()!=n_dof)
1089 std::ostringstream error_message_stream;
1090 error_message_stream <<
"RHS does not have the same dimension as " 1091 <<
"the linear system";
1093 OOMPH_CURRENT_FUNCTION,
1094 OOMPH_EXCEPTION_LOCATION);
1099 std::ostringstream error_message_stream;
1100 error_message_stream <<
"The rhs vector must not be distributed.";
1102 OOMPH_CURRENT_FUNCTION,
1103 OOMPH_EXCEPTION_LOCATION);
1107 if (solution.
built())
1111 std::ostringstream error_message_stream;
1112 error_message_stream <<
"If the result distribution is setup then it " 1113 <<
"must be the same as the rhs distribution";
1115 OOMPH_CURRENT_FUNCTION,
1116 OOMPH_EXCEPTION_LOCATION);
1132 template<
typename MATRIX>
1140 unsigned n_dof=problem_pt->
ndof();
1160 Matrix_pt=
new MATRIX;
1169 Matrix_can_be_deleted=
true;
1178 oomph_info <<
"Time for setup of Jacobian [sec]: " 1183 this->solve_helper(Matrix_pt,f,result);
1193 template<
typename MATRIX>
1199 unsigned n_dof=rhs.
nrow();
1203 MATRIX* tmp_matrix_pt=
dynamic_cast<MATRIX*
>(matrix_pt);
1206 this->check_validity_of_solve_helper_inputs<MATRIX>(tmp_matrix_pt,rhs,
1215 if (!solution.distribution_pt()->built())
1230 solution.initialise(0.0);
1246 double norm_res=0.0;
1262 matrix_pt->
residual(x,rhs,current_residual);
1265 norm_res=current_residual.
norm();
1278 oomph_info << Iterations <<
" " << norm_res << std::endl;
1290 for (
unsigned iter_num=0;iter_num<
Max_iter;iter_num++)
1293 for(
unsigned i=0;
i<n_dof;
i++)
1295 double dummy=rhs[
i];
1296 for (
unsigned j=0;j<
i;j++)
1298 dummy-=(*(matrix_pt))(
i,j)*x[j];
1300 for (
unsigned j=(i+1);j<n_dof;j++)
1302 dummy-=(*(matrix_pt))(
i,j)*x[j];
1304 x[
i]=dummy/(*(matrix_pt))(
i,
i);
1314 matrix_pt->
residual(x,rhs,current_residual);
1317 norm_res=current_residual.
norm()/norm_f;
1325 oomph_info << Iterations <<
" " << norm_res << std::endl;
1348 oomph_info <<
"\nGS converged. Residual norm: " << norm_res
1349 <<
"\nNumber of iterations to convergence: " << Iterations
1350 <<
"\n" << std::endl;
1362 oomph_info <<
"Time for solve with GS [sec]: " 1370 std::string error_message=
"Solver failed to converge and you requested ";
1371 error_message+=
"an error on convergence failures.";
1373 OOMPH_EXCEPTION_LOCATION,
1374 OOMPH_CURRENT_FUNCTION);
1398 unsigned n_dof=problem_pt->
ndof();
1435 setup_helper(Matrix_pt);
1438 Matrix_can_be_deleted=
true;
1444 oomph_info <<
"Time for setup of Jacobian [sec]: " 1449 solve_helper(Matrix_pt,f,result);
1470 Matrix_can_be_deleted=
false;
1481 Index_of_diagonal_entries=Matrix_pt->get_index_of_diagonal_entries();
1486 bool is_matrix_sorted=
true;
1489 is_matrix_sorted=Matrix_pt->entries_are_sorted();
1492 if (!is_matrix_sorted)
1497 OOMPH_CURRENT_FUNCTION,
1498 OOMPH_EXCEPTION_LOCATION);
1513 unsigned n_dof=rhs.
nrow();
1520 this->check_validity_of_solve_helper_inputs<CRDoubleMatrix>(cr_matrix_pt,rhs,
1529 if (!solution.distribution_pt()->built())
1543 solution.initialise(0.0);
1559 double norm_res=0.0;
1575 matrix_pt->
residual(x,rhs,current_residual);
1578 norm_res=current_residual.
norm();
1589 oomph_info << Iterations <<
" " << norm_res << std::endl;
1612 const double* value_pt=tmp_matrix_pt->
value();
1613 const int* row_start_pt=tmp_matrix_pt->
row_start();
1614 const int* column_index_pt=tmp_matrix_pt->
column_index();
1621 for (
unsigned i=0;
i<n_dof;
i++)
1624 unsigned diag_index=Index_of_diagonal_entries[
i];
1626 if (
unsigned(*(column_index_pt+diag_index))!=
i)
1628 std::string err_strng=
"Gauss-Seidel cannot operate on a matrix with ";
1629 err_strng+=
"zero diagonal entries.";
1631 OOMPH_CURRENT_FUNCTION,
1632 OOMPH_EXCEPTION_LOCATION);
1646 for (
unsigned i=0;
i<n_dof;
i++)
1649 unsigned diag_index=Index_of_diagonal_entries[
i];
1652 unsigned row_i_start=*(row_start_pt+
i);
1659 if (
unsigned(*(column_index_pt+row_i_start))!=
i)
1662 unsigned column_index=0;
1665 for (
unsigned j=row_i_start;j<diag_index;j++)
1668 column_index=*(column_index_pt+j);
1671 constant_term[
i]-=(*(value_pt+j))*constant_term[column_index];
1676 constant_term[
i]/=*(value_pt+diag_index);
1683 for (
unsigned iter_num=0;iter_num<
Max_iter;iter_num++)
1700 unsigned upper_tri_start=0;
1704 unsigned next_row_start=0;
1712 for (
unsigned i=0;
i<n_dof-1;
i++)
1717 upper_tri_start=Index_of_diagonal_entries[
i]+1;
1720 next_row_start=*(row_start_pt+
i+1);
1723 unsigned column_index=0;
1726 for (
unsigned j=upper_tri_start;j<next_row_start;j++)
1729 column_index=*(column_index_pt+j);
1732 temp_vec[
i]+=(*(value_pt+j))*x[column_index];
1752 for (
unsigned i=0;
i<n_dof;
i++)
1755 unsigned diag_index=Index_of_diagonal_entries[
i];
1758 unsigned row_i_start=*(row_start_pt+
i);
1763 if (
unsigned(*(column_index_pt+row_i_start))!=
i)
1766 unsigned column_index=0;
1769 for (
unsigned j=row_i_start;j<diag_index;j++)
1772 column_index=*(column_index_pt+j);
1775 temp_vec[
i]-=(*(value_pt+j))*temp_vec[column_index];
1780 temp_vec[
i]/=*(value_pt+diag_index);
1806 matrix_pt->
residual(x,rhs,current_residual);
1809 norm_res=current_residual.
norm()/norm_f;
1818 << norm_res << std::endl;
1823 << norm_res << std::endl;
1842 oomph_info <<
"\nGS converged. Residual norm: " << norm_res
1843 <<
"\nNumber of iterations to convergence: " << Iterations
1844 <<
"\n" << std::endl;
1858 oomph_info <<
"Time for solve with Gauss-Seidel [sec]: " 1866 std::string error_message=
"Solver failed to converge and you requested ";
1867 error_message+=
"an error on convergence failures.";
1869 OOMPH_EXCEPTION_LOCATION,
1870 OOMPH_CURRENT_FUNCTION);
1885 template<
typename MATRIX>
1894 unsigned n_dof=problem_pt->
ndof();
1914 Matrix_pt=
new MATRIX;
1923 extract_diagonal_entries(Matrix_pt);
1926 Matrix_can_be_deleted=
true;
1935 oomph_info <<
"Time for setup of Jacobian [sec]: " 1940 solve_helper(Matrix_pt,f,result);
1950 template<
typename MATRIX>
1956 unsigned n_dof=rhs.
nrow();
1960 MATRIX* tmp_matrix_pt=
dynamic_cast<MATRIX*
>(matrix_pt);
1963 this->check_validity_of_solve_helper_inputs<MATRIX>(tmp_matrix_pt,rhs,
1972 if (!solution.distribution_pt()->built())
1987 solution.initialise(0.0);
2002 for(
unsigned i=0;
i<n_dof;
i++)
2005 constant_term[
i]=Omega*Matrix_diagonal[
i]*rhs[
i];
2014 double norm_res=0.0;
2030 matrix_pt->
residual(x,rhs,local_residual);
2033 norm_res=local_residual.
norm();
2044 oomph_info << Iterations <<
" " << norm_res << std::endl;
2059 for (
unsigned iter_num=0;iter_num<
Max_iter;iter_num++)
2066 for (
unsigned idof=0;idof<n_dof;idof++)
2070 temp_vec[idof]*=Omega*Matrix_diagonal[idof];
2084 matrix_pt->
residual(x,rhs,local_residual);
2087 norm_res=local_residual.
norm()/norm_f;
2096 << norm_res << std::endl;
2101 << norm_res << std::endl;
2120 oomph_info <<
"\nDamped Jacobi converged. Residual norm: " << norm_res
2121 <<
"\nNumber of iterations to convergence: " << Iterations
2122 <<
"\n" << std::endl;
2134 oomph_info <<
"Time for solve with damped Jacobi [sec]: " 2142 std::string error_message=
"Solver failed to converge and you requested ";
2143 error_message+=
"an error on convergence failures.";
2145 OOMPH_EXCEPTION_LOCATION,
2146 OOMPH_CURRENT_FUNCTION);
2161 template<
typename MATRIX>
2171 throw OomphLibError(
"No matrix was stored -- cannot re-solve",
2172 OOMPH_CURRENT_FUNCTION,
2173 OOMPH_EXCEPTION_LOCATION);
2178 this->
solve(Matrix_pt,rhs,result);
2190 template<
typename MATRIX>
2195 unsigned n_dof = problem_pt->
ndof();
2213 Matrix_pt=
new MATRIX;
2215 if (dynamic_cast<DistributableLinearAlgebraObject*>(Matrix_pt) != 0)
2217 if (dynamic_cast<CRDoubleMatrix*>(Matrix_pt) != 0)
2226 Matrix_can_be_deleted=
true;
2234 oomph_info <<
"Time for setup of Jacobian [sec]: " 2242 if((result.
built()) &&
2248 this->solve_helper(Matrix_pt,f,result);
2254 this->solve_helper(Matrix_pt,f,result);
2271 template <
typename MATRIX>
2278 unsigned n_dof=rhs.
nrow();
2283 if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt) != 0)
2285 if (dynamic_cast<DistributableLinearAlgebraObject*>
2288 std::ostringstream error_message_stream;
2289 error_message_stream
2290 <<
"The matrix must not be distributed.";
2292 OOMPH_CURRENT_FUNCTION,
2293 OOMPH_EXCEPTION_LOCATION);
2299 std::ostringstream error_message_stream;
2300 error_message_stream
2301 <<
"The rhs vector distribution must be setup.";
2303 OOMPH_CURRENT_FUNCTION,
2304 OOMPH_EXCEPTION_LOCATION);
2307 if(rhs.
nrow() != n_dof)
2310 "RHS does not have the same dimension as the linear system",
2311 OOMPH_CURRENT_FUNCTION,
2312 OOMPH_EXCEPTION_LOCATION);
2317 std::ostringstream error_message_stream;
2318 error_message_stream
2319 <<
"The rhs vector must not be distributed.";
2321 OOMPH_CURRENT_FUNCTION,
2322 OOMPH_EXCEPTION_LOCATION);
2326 if (solution.
built())
2330 std::ostringstream error_message_stream;
2331 error_message_stream
2332 <<
"If the result distribution is setup then it must be the same as the " 2333 <<
"rhs distribution";
2335 OOMPH_CURRENT_FUNCTION,
2336 OOMPH_EXCEPTION_LOCATION);
2342 if (!solution.
built())
2362 if (!Iteration_restart)
2392 oomph_info <<
"Time for setup of preconditioner [sec]: " 2401 oomph_info <<
"Setup of preconditioner is bypassed in resolve mode" 2408 if(Preconditioner_LHS)
2420 for (
unsigned i = 0;
i < n_dof;
i++)
2422 normb += r_pt[
i] * r_pt[
i];
2424 normb = sqrt(normb);
2427 double beta = normb;
2430 if (normb == 0.0) normb = 1;
2431 resid = beta / normb;
2439 oomph_info << 0 <<
" " << resid << std::endl;
2452 oomph_info <<
"GMRES converged immediately. Normalised residual norm: " 2453 << resid << std::endl;
2461 oomph_info <<
"Time for solve with GMRES [sec]: " 2473 v.resize(Restart + 1);
2482 double* v0_pt = v[0].values_pt();
2483 for (
unsigned i = 0;
i < n_dof;
i++)
2485 v0_pt[
i] = r_pt[
i] / beta;
2492 unsigned iter_restart;
2495 for (iter_restart = 0; iter_restart < Restart && iter <=
Max_iter;
2496 iter_restart++, iter++)
2500 H[iter_restart].resize(iter_restart+2);
2505 if(Preconditioner_LHS)
2508 matrix_pt->
multiply(v[iter_restart],temp);
2521 for (
unsigned k = 0; k <= iter_restart; k++)
2525 H[iter_restart][k] = 0.0;
2526 double* vk_pt = v[k].values_pt();
2527 for (
unsigned i = 0;
i < n_dof;
i++)
2529 H[iter_restart][k] += w_pt[
i]*vk_pt[
i];
2533 for (
unsigned i = 0;
i < n_dof;
i++)
2535 w_pt[
i] -= H[iter_restart][k] * vk_pt[
i];
2541 double temp_norm_w = 0.0;
2542 for (
unsigned i = 0;
i < n_dof;
i++)
2544 temp_norm_w += w_pt[
i]*w_pt[
i];
2546 temp_norm_w = sqrt(temp_norm_w);
2547 H[iter_restart][iter_restart+1] = temp_norm_w;
2552 double* v_pt = v[iter_restart + 1].values_pt();
2553 for (
unsigned i = 0;
i < n_dof;
i++)
2555 v_pt[
i] = w_pt[
i] / H[iter_restart][iter_restart+1];
2559 for (
unsigned k = 0; k < iter_restart; k++)
2561 apply_plane_rotation(H[iter_restart][k], H[iter_restart][k+1], cs[k],
2564 generate_plane_rotation(H[iter_restart][iter_restart],
2565 H[iter_restart][iter_restart+1],
2568 apply_plane_rotation(H[iter_restart][iter_restart],
2569 H[iter_restart][iter_restart+1], cs[iter_restart],
2571 apply_plane_rotation(s[iter_restart],s[iter_restart+1],cs[iter_restart],
2575 beta = std::fabs(s[iter_restart+1]);
2586 oomph_info << iter <<
" "<< resid << std::endl;
2598 update(iter_restart, H, s, v, solution);
2604 oomph_info <<
"GMRES converged (1). Normalised residual norm: " 2605 << resid << std::endl;
2606 oomph_info <<
"Number of iterations to convergence: " 2607 << iter << std::endl;
2619 oomph_info <<
"Time for solve with GMRES [sec]: " 2627 if (iter_restart>0) update((iter_restart - 1), H, s, v, solution);
2632 matrix_pt->
multiply(solution,temp);
2635 for (
unsigned i = 0;
i < n_dof;
i++)
2637 temp_pt[
i] = rhs_pt[
i] - temp_pt[
i];
2640 if(Preconditioner_LHS)
2649 for (
unsigned i = 0;
i < n_dof;
i++)
2651 beta += r_pt[
i] * r_pt[
i];
2656 resid = beta / normb;
2662 oomph_info <<
"GMRES converged (2). Normalised residual norm: " 2663 << resid << std::endl;
2664 oomph_info <<
"Number of iterations to convergence: " 2665 << iter << std::endl;
2677 oomph_info <<
"Time for solve with GMRES [sec]: " 2687 oomph_info <<
"GMRES did not converge to required tolerance! " 2689 oomph_info <<
"Returning with normalised residual norm: " 2690 << resid << std::endl;
2697 std::string err =
"Solver failed to converge and you requested an error";
2698 err +=
" on convergence failures.";
2700 OOMPH_CURRENT_FUNCTION);
bool Throw_error_after_max_iter
Should we throw an error instead of just returning when we hit the max iterations?
int * column_index()
Access to C-style column index array.
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
void resolve(const DoubleVector &rhs, DoubleVector &result)
Re-solve the system defined by the last assembled Jacobian and the rhs vector specified here...
static IdentityPreconditioner Default_preconditioner
Default preconditioner: The base class for preconditioners is a fully functional (if trivial!) precon...
Preconditioner *& preconditioner_pt()
Access function to preconditioner.
virtual void preconditioner_solve(const DoubleVector &r, DoubleVector &z)=0
Apply the preconditioner. Pure virtual generic interface function. This method should apply the preco...
void redistribute(const LinearAlgebraDistribution *const &dist_pt)
The contents of the vector are redistributed to match the new distribution. In a non-MPI rebuild this...
double Tolerance
Convergence tolerance.
double * values_pt()
access function to the underlying values
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
unsigned Max_iter
Maximum number of iterations.
bool Enable_resolve
Boolean that indicates whether the matrix (or its factors, in the case of direct solver) should be st...
virtual void multiply(const DoubleVector &x, DoubleVector &soln) const =0
Multiply the matrix by the vector x: soln=Ax.
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
This is where the actual work is done – different implementations for different matrix types...
void resolve(const DoubleVector &rhs, DoubleVector &result)
Re-solve the system defined by the last assembled Jacobian and the rhs vector specified here...
bool distributed() const
access function to the distributed - indicates whether the distribution is serial or distributed ...
std::ofstream Output_file_stream
Output file stream for convergence history.
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
double * value()
Access to C-style value array.
The conjugate gradient method.
void solve(Problem *const &problem_pt, DoubleVector &result)
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
bool Use_as_smoother
When a derived class object is being used as a smoother in the MG solver (or elsewhere) the residual ...
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
bool distributed() const
distribution is serial or distributed
void solve(Problem *const &problem_pt, DoubleVector &result)
Use damped Jacobi iteration as an IterativeLinearSolver: This obtains the Jacobian matrix J and the r...
void solve(Problem *const &problem_pt, DoubleVector &result)
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
void build(const DoubleVector &old_vector)
Just copys the argument DoubleVector.
Base class for any linear algebra object that is distributable. Just contains storage for the LinearA...
virtual void residual(const DoubleVector &x, const DoubleVector &b, DoubleVector &residual_)
Find the residual, i.e. r=b-Ax the residual.
bool Doc_time
Boolean flag that indicates whether the time taken.
double Jacobian_setup_time
Jacobian setup time.
void initialise(const double &v)
initialise the whole vector with value v
unsigned Max_iter
Max. # of Newton iterations.
void resolve(const DoubleVector &rhs, DoubleVector &result)
Re-solve the system defined by the last assembled Jacobian and the rhs vector specified here...
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
void check_validity_of_solve_helper_inputs(MATRIX *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution, const double &n_dof)
Self-test to check that all the dimensions of the inputs to solve helper are consistent and everythin...
double timer()
returns the time in seconds after some point in past
void setup(DoubleMatrixBase *matrix_pt)
Setup the preconditioner: store the matrix pointer and the communicator pointer then call preconditio...
void sort_entries()
Sorts the entries associated with each row of the matrix in the column index vector and the value vec...
double Solution_time
linear solver solution time
unsigned long ndof() const
Return the number of dofs.
virtual void get_jacobian(DoubleVector &residuals, DenseDoubleMatrix &jacobian)
Return the fully-assembled Jacobian and residuals for the problem Interface for the case when the Jac...
virtual void clean_up_memory()
Empty virtual function that can be overloaded in specific linear solvers to clean up any memory that ...
The conjugate gradient method.
unsigned nrow() const
access function to the number of global rows.
double dot(const DoubleVector &vec) const
compute the dot product of this vector with the vector vec.
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
bool Doc_convergence_history
Flag indicating if the convergence history is to be documented.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
void solve(Problem *const &problem_pt, DoubleVector &result)
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
setup the distribution of this distributable linear algebra object
void solve(Problem *const &problem_pt, DoubleVector &result)
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
A vector in the mathematical sense, initially developed for linear algebra type applications. If MPI then this vector can be distributed - its distribution is described by the LinearAlgebraDistribution object at Distribution_pt. Data is stored in a C-style pointer vector (double*)
double norm() const
compute the 2 norm of this vector
bool Setup_preconditioner_before_solve
indicates whether the preconditioner should be setup before solve. Default = true; ...
int * row_start()
Access to C-style row_start array.
Abstract base class for matrices of doubles – adds abstract interfaces for solving, LU decomposition and multiplication by vectors.
A class for compressed row matrices. This is a distributable object.
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
virtual unsigned long ncol() const =0
Return the number of columns of the matrix.
double Preconditioner_setup_time
Preconditioner setup time.
void build(const LinearAlgebraDistribution *distribution_pt, const unsigned &ncol, const Vector< double > &value, const Vector< int > &column_index, const Vector< int > &row_start)
build method: vector of values, vector of column indices, vector of row starts and number of rows and...
Explicit template specialisation of the Gauss Seidel method for compressed row format matrices...