2 #ifndef OOMPH_COMPLEX_SMOOTHER_HEADER 3 #define OOMPH_COMPLEX_SMOOTHER_HEADER 7 #include <oomph-lib-config.h> 53 if (matrices_pt.size()!=2)
56 std::ostringstream error_message_stream;
59 error_message_stream <<
"Can only deal with two matrices. You have " 61 <<
" matrices." << std::endl;
65 OOMPH_CURRENT_FUNCTION,
66 OOMPH_EXCEPTION_LOCATION);
72 std::ostringstream error_message_stream;
75 error_message_stream <<
"Can only deal with two input vectors. You have " 77 <<
" vectors." << std::endl;
81 OOMPH_CURRENT_FUNCTION,
82 OOMPH_EXCEPTION_LOCATION);
88 std::ostringstream error_message_stream;
91 error_message_stream <<
"Can only deal with two output vectors. You have " 93 <<
" output vectors." << std::endl;
97 OOMPH_CURRENT_FUNCTION,
98 OOMPH_EXCEPTION_LOCATION);
119 matrices_pt[0]->multiply(x[0],soln[0]);
122 matrices_pt[0]->multiply(x[1],soln[1]);
128 matrices_pt[1]->multiply(x[1],temp);
134 matrices_pt[1]->multiply(x[0],temp);
142 template <
typename MATRIX>
147 const double& n_dof);
163 template<
typename MATRIX>
172 unsigned n_dof_types=2;
178 matrix_storage_pt[0]=real_matrix_pt;
181 matrix_storage_pt[1]=imag_matrix_pt;
184 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
188 if (dynamic_cast<DistributableLinearAlgebraObject*>
189 (matrix_storage_pt[dof_type])!=0)
191 if (dynamic_cast<DistributableLinearAlgebraObject*>
194 std::ostringstream error_message_stream;
195 error_message_stream <<
"The matrix must not be distributed.";
197 OOMPH_CURRENT_FUNCTION,
198 OOMPH_EXCEPTION_LOCATION);
202 if (!(rhs[dof_type].built()))
204 std::ostringstream error_message_stream;
205 error_message_stream <<
"The rhs vector distribution must be setup.";
207 OOMPH_CURRENT_FUNCTION,
208 OOMPH_EXCEPTION_LOCATION);
211 if (rhs[dof_type].
nrow()!=n_dof)
213 std::ostringstream error_message_stream;
214 error_message_stream <<
"RHS does not have the same dimension as the " 217 OOMPH_CURRENT_FUNCTION,
218 OOMPH_EXCEPTION_LOCATION);
223 std::ostringstream error_message_stream;
224 error_message_stream <<
"The rhs vector must not be distributed.";
226 OOMPH_CURRENT_FUNCTION,
227 OOMPH_EXCEPTION_LOCATION);
231 if (solution[dof_type].built())
236 std::ostringstream error_message_stream;
237 error_message_stream <<
"If the result distribution is setup then it " 238 <<
"must be the same as the rhs distribution";
240 OOMPH_CURRENT_FUNCTION,
241 OOMPH_EXCEPTION_LOCATION);
258 template<
typename MATRIX>
266 Matrix_can_be_deleted(true),
284 if ((Matrix_real_pt!=0) && (Matrix_can_be_deleted))
287 delete Matrix_real_pt;
295 if ((Matrix_imag_pt!=0) && (Matrix_can_be_deleted))
298 delete Matrix_imag_pt;
329 double omega=(12.0-4.0*pow(kh,2.0))/(18.0-3.0*pow(kh,2.0));
337 if ((omega>tolerance) && !(omega>1))
347 else if ((k>pi) && (kh>2*cos(pi*h/2)))
350 double omega_2=(2.0-pow(kh,2.0));
353 omega_2/=(2.0*pow(sin(pi*h/2),2.0)-0.5*pow(kh,2.0));
356 if (omega_2>(2.0/3.0))
365 Omega=0.5*(tolerance+omega_2);
392 Matrix_can_be_deleted=
false;
395 Matrix_real_pt=helmholtz_matrix_pt[0];
398 Matrix_imag_pt=helmholtz_matrix_pt[1];
403 if (Matrix_real_pt->nrow()!=Matrix_imag_pt->nrow())
405 std::ostringstream error_message_stream;
406 error_message_stream <<
"Incompatible real and complex matrix sizes.";
408 OOMPH_CURRENT_FUNCTION,
409 OOMPH_EXCEPTION_LOCATION);
421 Matrix_diagonal_real=Matrix_real_pt->diagonal_entries();
424 Matrix_diagonal_imag=Matrix_imag_pt->diagonal_entries();
428 unsigned n_dof=Matrix_diagonal_real.size();
431 Matrix_diagonal_inv_sq.resize(n_dof,0.0);
441 for (
unsigned i=0;
i<n_dof;
i++)
444 dummy_r=Matrix_diagonal_real[
i];
447 dummy_c=Matrix_diagonal_imag[
i];
450 Matrix_diagonal_inv_sq[
i]=1.0/(dummy_r*dummy_r+dummy_c*dummy_c);
465 complex_solve_helper(rhs,solution);
519 template<
typename MATRIX>
525 unsigned n_dof=Matrix_real_pt->nrow();
535 this->check_validity_of_solve_helper_inputs<MATRIX>(tmp_rmatrix_pt,
577 double res_real_norm=0.0;
578 double res_imag_norm=0.0;
600 for(
unsigned i=0;
i<n_dof;
i++)
604 constant_term_real[
i]=(Matrix_diagonal_real[
i]*rhs_real[
i]+
605 Matrix_diagonal_imag[
i]*rhs_imag[
i]);
608 constant_term_real[
i]*=Matrix_diagonal_inv_sq[
i];
611 constant_term_real[
i]*=Omega;
615 constant_term_imag[
i]=(Matrix_diagonal_real[
i]*rhs_imag[
i]-
616 Matrix_diagonal_imag[
i]*rhs_real[
i]);
619 constant_term_imag[
i]*=Matrix_diagonal_inv_sq[
i];
622 constant_term_imag[
i]*=Omega;
636 Matrix_real_pt->multiply(x_real,temp_vec_rr);
637 Matrix_imag_pt->multiply(x_imag,temp_vec_cc);
638 Matrix_real_pt->multiply(x_imag,temp_vec_rc);
639 Matrix_imag_pt->multiply(x_real,temp_vec_cr);
660 residual_real=rhs_real;
661 residual_real-=temp_vec_rr;
662 residual_real+=temp_vec_cc;
665 residual_imag=rhs_imag;
666 residual_imag-=temp_vec_rc;
667 residual_imag-=temp_vec_cr;
679 double res_real_norm=residual_real.
norm();
680 double res_imag_norm=residual_imag.
norm();
681 double norm_res=sqrt(res_real_norm*res_real_norm+
682 res_imag_norm*res_imag_norm);
690 oomph_info << Iterations <<
" " << norm_res << std::endl;
705 temp_vec_real=temp_vec_rr;
706 temp_vec_real-=temp_vec_cc;
709 temp_vec_imag=temp_vec_cr;
710 temp_vec_imag+=temp_vec_rc;
713 for (
unsigned iter_num=0;iter_num<
Max_iter;iter_num++)
717 for (
unsigned i=0;
i<n_dof;
i++)
724 dummy_r=(Matrix_diagonal_real[
i]*temp_vec_real[
i]+
725 Matrix_diagonal_imag[
i]*temp_vec_imag[
i]);
728 dummy_c=(Matrix_diagonal_real[
i]*temp_vec_imag[
i]-
729 Matrix_diagonal_imag[
i]*temp_vec_real[
i]);
732 dummy_r*=Omega*Matrix_diagonal_inv_sq[
i];
733 dummy_c*=Omega*Matrix_diagonal_inv_sq[
i];
741 x_real+=constant_term_real;
742 x_imag+=constant_term_imag;
747 Matrix_real_pt->multiply(x_real,temp_vec_rr);
748 Matrix_imag_pt->multiply(x_imag,temp_vec_cc);
749 Matrix_real_pt->multiply(x_imag,temp_vec_rc);
750 Matrix_imag_pt->multiply(x_real,temp_vec_cr);
753 temp_vec_real=temp_vec_rr;
754 temp_vec_real-=temp_vec_cc;
757 temp_vec_imag=temp_vec_cr;
758 temp_vec_imag+=temp_vec_rc;
764 residual_real=rhs_real;
765 residual_real-=temp_vec_rr;
766 residual_real+=temp_vec_cc;
769 residual_imag=rhs_imag;
770 residual_imag-=temp_vec_rc;
771 residual_imag-=temp_vec_cr;
774 res_real_norm=residual_real.
norm();
775 res_imag_norm=residual_imag.
norm();
776 norm_res=sqrt(res_real_norm*res_real_norm+
777 res_imag_norm*res_imag_norm)/norm_f;
785 oomph_info << Iterations <<
" " << norm_res << std::endl;
808 oomph_info <<
"\n(Complex) damped Jacobi converged. Residual norm: " 810 <<
"\nNumber of iterations to convergence: " 811 << Iterations <<
"\n" << std::endl;
824 oomph_info <<
"Time for solve with (complex) damped Jacobi [sec]: " 832 std::string error_message=
"Solver failed to converge and you requested ";
833 error_message+=
"an error on convergence failures.";
835 OOMPH_EXCEPTION_LOCATION,
836 OOMPH_CURRENT_FUNCTION);
843 template<
typename MATRIX>
852 Matrices_storage_pt(0),
854 Matrix_can_be_deleted(true)
892 std::string error_message=
"Solve function for class\n\n";
893 error_message+=
"ComplexGMRES\n\n";
894 error_message+=
"is deliberately broken to avoid the accidental \n";
895 error_message+=
"use of the inappropriate C++ default. If you \n";
896 error_message+=
"really need one for this class, write it yourself...\n";
900 OOMPH_CURRENT_FUNCTION,
901 OOMPH_EXCEPTION_LOCATION);
930 Matrix_can_be_deleted=
false;
934 if (helmholtz_matrix_pt.size()!=2)
936 std::ostringstream error_message_stream;
937 error_message_stream <<
"Can only deal with two matrices. You have " 938 << helmholtz_matrix_pt.size()
939 <<
" matrices." << std::endl;
943 OOMPH_CURRENT_FUNCTION,
944 OOMPH_EXCEPTION_LOCATION);
949 Matrices_storage_pt.resize(2,0);
952 Matrices_storage_pt[0]=helmholtz_matrix_pt[0];
955 Matrices_storage_pt[1]=helmholtz_matrix_pt[1];
960 if (Matrices_storage_pt[0]->
nrow()!=Matrices_storage_pt[1]->
nrow())
962 std::ostringstream error_message_stream;
963 error_message_stream <<
"Incompatible real and imag. matrix sizes.";
965 OOMPH_CURRENT_FUNCTION,
966 OOMPH_EXCEPTION_LOCATION);
970 if (Matrices_storage_pt[0]->ncol()!=Matrices_storage_pt[1]->ncol())
972 std::ostringstream error_message_stream;
973 error_message_stream <<
"Incompatible real and imag. matrix sizes.";
975 OOMPH_CURRENT_FUNCTION,
976 OOMPH_EXCEPTION_LOCATION);
992 complex_solve_helper(rhs,solution);
1002 if ((Matrices_storage_pt[0]!=0)&&(Matrix_can_be_deleted))
1005 delete Matrices_storage_pt[0];
1008 Matrices_storage_pt[0]=0;
1013 if ((Matrices_storage_pt[1]!=0)&&(Matrix_can_be_deleted))
1016 delete Matrices_storage_pt[1];
1019 Matrices_storage_pt[1]=0;
1029 const Vector<
Vector<std::complex<double> > >& hessenberg,
1030 const Vector<std::complex<double> >&
s,
1052 for (
int i=
int(k);
i>=0;
i--)
1055 y[
i]/=hessenberg[
i][
i];
1058 for (
int j=
i-1;j>=0;j--)
1061 y[j]-=hessenberg[
i][j]*y[
i];
1067 unsigned n_row=x[0].nrow();
1072 for (
unsigned j=0;j<=k;j++)
1075 const double* vj_r_pt=v[j][0].values_pt();
1078 const double* vj_c_pt=v[j][1].values_pt();
1081 for (
unsigned i=0;
i<n_row;
i++)
1084 x[0][
i]+=(vj_r_pt[
i]*y[j].real())-(vj_c_pt[
i]*y[j].imag());
1087 x[1][
i]+=(vj_c_pt[
i]*y[j].real())+(vj_r_pt[
i]*y[j].imag());
1124 std::complex<double>& dy,
1125 std::complex<double>& cs,
1126 std::complex<double>& sn)
1141 else if(std::abs(dy)>std::abs(dx))
1144 std::complex<double> temp=dx/dy;
1149 sn=(dy/std::abs(dy))/sqrt(1.0+pow(std::abs(temp),2.0));
1162 std::complex<double> temp=dy/dx;
1167 cs=(dx/std::abs(dx))/sqrt(1.0+pow(std::abs(temp),2.0));
1180 if ((std::fabs(sn.imag())>tolerance)||(sn.real()<0))
1183 std::ostringstream error_message_stream;
1186 error_message_stream <<
"The value of sin(theta) is not real " 1187 <<
"and/or nonnegative. Value is: " 1192 OOMPH_CURRENT_FUNCTION,
1193 OOMPH_EXCEPTION_LOCATION);
1216 std::complex<double>& dy,
1217 std::complex<double>& cs,
1218 std::complex<double>& sn)
1221 std::complex<double> temp=std::conj(cs)*dx+std::conj(sn)*dy;
1248 template<
typename MATRIX>
1254 unsigned n_dof_types=2;
1259 unsigned n_row=Matrices_storage_pt[0]->nrow();
1266 std::ostringstream error_message_stream;
1269 error_message_stream <<
"The maximum number of iterations cannot exceed " 1270 <<
"the number of rows in the problem." 1271 <<
"\nMaximum number of iterations: " <<
Max_iter 1272 <<
"\nNumber of rows: " << n_row
1277 OOMPH_CURRENT_FUNCTION,
1278 OOMPH_EXCEPTION_LOCATION);
1282 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
1287 if (dynamic_cast<DistributableLinearAlgebraObject*>
1288 (Matrices_storage_pt[dof_type])!=0)
1290 if (dynamic_cast<DistributableLinearAlgebraObject*>
1291 (Matrices_storage_pt[dof_type])->distributed())
1293 std::ostringstream error_message_stream;
1294 error_message_stream <<
"The matrix must not be distributed.";
1296 OOMPH_CURRENT_FUNCTION,
1297 OOMPH_EXCEPTION_LOCATION);
1301 if (!rhs[dof_type].built())
1303 std::ostringstream error_message_stream;
1304 error_message_stream <<
"The rhs vector distribution must be setup.";
1306 OOMPH_CURRENT_FUNCTION,
1307 OOMPH_EXCEPTION_LOCATION);
1310 if(rhs[dof_type].
nrow()!=n_row)
1312 std::ostringstream error_message_stream;
1313 error_message_stream <<
"RHS does not have the same dimension as the" 1314 <<
" linear system";
1316 OOMPH_CURRENT_FUNCTION,
1317 OOMPH_EXCEPTION_LOCATION);
1322 std::ostringstream error_message_stream;
1323 error_message_stream <<
"The rhs vector must not be distributed.";
1325 OOMPH_CURRENT_FUNCTION,
1326 OOMPH_EXCEPTION_LOCATION);
1330 if (solution[dof_type].built())
1335 std::ostringstream error_message_stream;
1336 error_message_stream <<
"If the result distribution is setup then it " 1337 <<
"must be the same as the rhs distribution";
1339 OOMPH_CURRENT_FUNCTION,
1340 OOMPH_EXCEPTION_LOCATION);
1345 if (!solution[dof_type].built())
1383 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
1394 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
1401 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
1404 r[dof_type]=rhs[dof_type];
1408 double norm_r=r[0].norm();
1411 double norm_c=r[1].norm();
1414 double normb=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
1442 oomph_info << 0 <<
" " << resid << std::endl;
1459 oomph_info <<
"GMRES converged immediately. Normalised residual norm: " 1460 << resid << std::endl;
1475 for (
unsigned dof_type=0;dof_type<n_row+1;dof_type++)
1478 v[dof_type].resize(n_dof_types);
1489 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
1497 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
1500 double* v0_pt=v[0][dof_type].values_pt();
1503 const double* r_pt=r[dof_type].values_pt();
1506 for (
unsigned i=0;
i<n_row;
i++)
1509 v0_pt[
i]=r_pt[
i]/beta;
1522 hessenberg[j].resize(j+2,std::complex<double>(0.0,0.0));
1529 double* w_r_pt=w[0].values_pt();
1532 double* w_c_pt=w[1].values_pt();
1538 for (
unsigned i=0;
i<j+1;
i++)
1541 const double* vi_r_pt=v[
i][0].values_pt();
1544 const double* vi_c_pt=v[
i][1].values_pt();
1547 for (
unsigned k=0;k<n_row;k++)
1550 std::complex<double> complex_v(vi_r_pt[k],vi_c_pt[k]);
1553 std::complex<double> complex_w(w_r_pt[k],w_c_pt[k]);
1557 hessenberg[j][
i]+=std::conj(complex_v)*complex_w;
1562 for (
unsigned k=0;k<n_row;k++)
1565 w_r_pt[k]-=(hessenberg[j][
i].real()*vi_r_pt[k]-
1566 hessenberg[j][
i].imag()*vi_c_pt[k]);
1569 w_c_pt[k]-=(hessenberg[j][
i].real()*vi_c_pt[k]+
1570 hessenberg[j][
i].imag()*vi_r_pt[k]);
1582 hessenberg[j][j+1]=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
1592 if (hessenberg[j][j+1]!=0.0)
1595 double* v_r_pt=v[j+1][0].values_pt();
1598 double* v_c_pt=v[j+1][1].values_pt();
1601 const double* w_r_pt=w[0].values_pt();
1604 const double* w_c_pt=w[1].values_pt();
1611 double h_subdiag_val=hessenberg[j][j+1].real();
1614 for(
unsigned k=0;k<n_row;k++)
1617 v_r_pt[k]=w_r_pt[k]/h_subdiag_val;
1620 v_c_pt[k]=w_c_pt[k]/h_subdiag_val;
1632 oomph_info <<
"Subdiagonal Hessenberg entry is zero." 1633 <<
"Do something here..." << std::endl;
1638 for (
unsigned k=0;k<j;k++)
1642 apply_plane_rotation(hessenberg[j][k],hessenberg[j][k+1],cs[k],sn[k]);
1646 generate_plane_rotation(hessenberg[j][j],hessenberg[j][j+1],cs[j],sn[j]);
1649 apply_plane_rotation(hessenberg[j][j],hessenberg[j][j+1],cs[j],sn[j]);
1653 apply_plane_rotation(s[j],s[j+1],cs[j],sn[j]);
1658 beta=std::abs(s[j+1]);
1671 oomph_info << j+1 <<
" " << resid << std::endl;
1689 update(j,hessenberg,s,v,solution);
1695 oomph_info <<
"\nGMRES converged (1). Normalised residual norm: " 1696 << resid << std::endl;
1699 oomph_info <<
"Number of iterations to convergence: " 1700 << j+1 <<
"\n" << std::endl;
1713 oomph_info <<
"Time for solve with GMRES [sec]: " 1731 update(Max_iter-1,hessenberg,s,v,solution);
1744 oomph_info <<
"Time for solve with GMRES [sec]: " 1761 template<
typename MATRIX>
1772 Matrix_can_be_deleted(true)
1774 Preconditioner_LHS=
true;
1808 std::ostringstream error_message_stream;
1811 error_message_stream <<
"Preconditioner_solve(...) is broken. " 1812 <<
"HelmholtzGMRESMG is only meant to be used as " 1813 <<
"a linear solver.\n";
1817 OOMPH_CURRENT_FUNCTION,
1818 OOMPH_EXCEPTION_LOCATION);
1826 std::ostringstream error_message_stream;
1829 error_message_stream <<
"This function is broken. HelmholtzGMRESMG is " 1830 <<
"only meant to be used as a linear solver.\n";
1834 OOMPH_CURRENT_FUNCTION,
1835 OOMPH_EXCEPTION_LOCATION);
1843 #ifdef OOMPH_HAS_MPI 1849 OomphLibWarning(
"Can't guarantee the MG solver will work in parallel!",
1850 OOMPH_CURRENT_FUNCTION,
1851 OOMPH_EXCEPTION_LOCATION);
1856 unsigned n_dof=problem_pt->
ndof();
1880 MATRIX* matrix_pt=
new MATRIX;
1882 if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt) != 0)
1884 if (dynamic_cast<CRDoubleMatrix*>(matrix_pt) != 0)
1896 Matrix_can_be_deleted=
true;
1899 this->set_matrix_pt(matrix_pt);
1909 bool allow_different_element_types_in_mesh=
true;
1910 this->set_mesh(0,problem_pt->
mesh_pt(),
1911 allow_different_element_types_in_mesh);
1914 this->block_setup();
1917 unsigned nblock_types=this->nblock_types();
1921 if (nblock_types!=2)
1924 std::stringstream tmp;
1925 tmp <<
"There are supposed to be two block types.\nYours has " 1926 << nblock_types << std::endl;
1930 OOMPH_CURRENT_FUNCTION,
1931 OOMPH_EXCEPTION_LOCATION);
1936 Matrices_storage_pt.resize(2,0);
1939 for (
unsigned i=0;
i<nblock_types;
i++)
1948 this->get_block(
i,j,*Matrices_storage_pt[
i]);
1957 oomph_info <<
"\nTime for setup of block Jacobian [sec]: " 1975 solve_helper(matrix_pt,f,result);
1984 solve_helper(matrix_pt,f,result);
2002 std::ostringstream error_message_stream;
2005 error_message_stream <<
"This function is broken. The block preconditioner " 2006 <<
"needs access to the underlying mesh.\n";
2010 OOMPH_CURRENT_FUNCTION,
2011 OOMPH_EXCEPTION_LOCATION);
2034 if ((Matrices_storage_pt[0]==0)||(Matrices_storage_pt[1]==0))
2036 throw OomphLibError(
"No matrix was stored -- cannot re-solve",
2037 OOMPH_CURRENT_FUNCTION,
2038 OOMPH_EXCEPTION_LOCATION);
2048 solve_helper(matrix_pt,rhs,result);
2083 if (Matrices_storage_pt.size()>0)
2087 if ((Matrices_storage_pt[0]!=0)&&(Matrix_can_be_deleted))
2090 delete Matrices_storage_pt[0];
2093 Matrices_storage_pt[0]=0;
2098 if ((Matrices_storage_pt[1]!=0)&&(Matrix_can_be_deleted))
2101 delete Matrices_storage_pt[1];
2104 Matrices_storage_pt[1]=0;
2119 if (matrices_pt.size()!=2)
2122 std::ostringstream error_message_stream;
2125 error_message_stream <<
"Can only deal with two matrices. You have " 2126 << matrices_pt.size()
2127 <<
" matrices." << std::endl;
2131 OOMPH_CURRENT_FUNCTION,
2132 OOMPH_EXCEPTION_LOCATION);
2138 std::ostringstream error_message_stream;
2141 error_message_stream <<
"Can only deal with two input vectors. You have " 2143 <<
" vectors." << std::endl;
2147 OOMPH_CURRENT_FUNCTION,
2148 OOMPH_EXCEPTION_LOCATION);
2154 std::ostringstream error_message_stream;
2157 error_message_stream <<
"Can only deal with two output vectors. You have " 2159 <<
" output vectors." << std::endl;
2163 OOMPH_CURRENT_FUNCTION,
2164 OOMPH_EXCEPTION_LOCATION);
2189 matrices_pt[0]->multiply(x[0],soln[0]);
2192 matrices_pt[0]->multiply(x[1],soln[1]);
2198 matrices_pt[1]->multiply(x[1],temp);
2204 matrices_pt[1]->multiply(x[0],temp);
2212 const Vector<
Vector<std::complex<double> > >& hessenberg,
2213 const Vector<std::complex<double> >&
s,
2236 for (
int i=
int(k);
i>=0;
i--)
2239 y[
i]/=hessenberg[
i][
i];
2242 for (
int j=
i-1;j>=0;j--)
2245 y[j]-=hessenberg[
i][j]*y[
i];
2251 unsigned n_row=x[0].nrow();
2260 for (
unsigned dof_type=0;dof_type<2;dof_type++)
2270 double* block_temp_r_pt=block_temp[0].values_pt();
2273 double* block_temp_c_pt=block_temp[1].values_pt();
2276 for (
unsigned j=0;j<=k;j++)
2279 const double* vj_r_pt=v[j][0].values_pt();
2282 const double* vj_c_pt=v[j][1].values_pt();
2285 for (
unsigned i=0;
i<n_row;
i++)
2288 block_temp_r_pt[
i]+=(vj_r_pt[
i]*y[j].real())-(vj_c_pt[
i]*y[j].imag());
2291 block_temp_c_pt[
i]+=(vj_c_pt[
i]*y[j].real())+(vj_r_pt[
i]*y[j].imag());
2296 if(Preconditioner_LHS)
2300 for (
unsigned dof_type=0;dof_type<2;dof_type++)
2303 x[dof_type]+=block_temp[dof_type];
2313 this->return_block_vectors(block_temp,temp);
2319 this->return_block_vectors(block_z,z);
2327 this->get_block_vectors(z,block_z);
2331 for (
unsigned dof_type=0;dof_type<2;dof_type++)
2334 x[dof_type]+=block_z[dof_type];
2371 std::complex<double>& dy,
2372 std::complex<double>& cs,
2373 std::complex<double>& sn)
2388 else if(std::abs(dy)>std::abs(dx))
2391 std::complex<double> temp=dx/dy;
2396 sn=(dy/std::abs(dy))/sqrt(1.0+pow(std::abs(temp),2.0));
2409 std::complex<double> temp=dy/dx;
2414 cs=(dx/std::abs(dx))/sqrt(1.0+pow(std::abs(temp),2.0));
2427 if ((std::fabs(sn.imag())>tolerance)||(sn.real()<0))
2430 std::ostringstream error_message_stream;
2433 error_message_stream <<
"The value of sin(theta) is not real " 2434 <<
"and/or nonnegative. Value is: " 2439 OOMPH_CURRENT_FUNCTION,
2440 OOMPH_EXCEPTION_LOCATION);
2463 std::complex<double>& dy,
2464 std::complex<double>& cs,
2465 std::complex<double>& sn)
2468 std::complex<double> temp=std::conj(cs)*dx+std::conj(sn)*dy;
2508 template <
typename MATRIX>
2515 unsigned n_dof_types=this->ndof_types();
2522 std::stringstream error_message_stream;
2525 error_message_stream <<
"This preconditioner only works for problems " 2526 <<
"with 2 dof types\nYours has " << n_dof_types;
2530 OOMPH_CURRENT_FUNCTION,
2531 OOMPH_EXCEPTION_LOCATION);
2538 unsigned n_row=Matrices_storage_pt[0]->nrow();
2545 std::ostringstream error_message_stream;
2548 error_message_stream <<
"The maximum number of iterations cannot exceed " 2549 <<
"the number of rows in the problem." 2550 <<
"\nMaximum number of iterations: " <<
Max_iter 2551 <<
"\nNumber of rows: " << n_row
2556 OOMPH_CURRENT_FUNCTION,
2557 OOMPH_EXCEPTION_LOCATION);
2562 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2566 if (dynamic_cast<DistributableLinearAlgebraObject*>
2567 (Matrices_storage_pt[dof_type])!=0)
2569 if (dynamic_cast<DistributableLinearAlgebraObject*>
2570 (Matrices_storage_pt[dof_type])->distributed())
2572 std::ostringstream error_message_stream;
2573 error_message_stream <<
"The matrix must not be distributed.";
2575 OOMPH_CURRENT_FUNCTION,
2576 OOMPH_EXCEPTION_LOCATION);
2583 std::ostringstream error_message_stream;
2584 error_message_stream <<
"The rhs vector distribution must be setup.";
2586 OOMPH_CURRENT_FUNCTION,
2587 OOMPH_EXCEPTION_LOCATION);
2590 if(rhs.
nrow()!=2*n_row)
2592 std::ostringstream error_message_stream;
2593 error_message_stream <<
"RHS does not have the same dimension as the" 2594 <<
" linear system";
2596 OOMPH_CURRENT_FUNCTION,
2597 OOMPH_EXCEPTION_LOCATION);
2602 std::ostringstream error_message_stream;
2603 error_message_stream <<
"The rhs vector must not be distributed.";
2605 OOMPH_CURRENT_FUNCTION,
2606 OOMPH_EXCEPTION_LOCATION);
2610 if (solution.
built())
2614 std::ostringstream error_message_stream;
2615 error_message_stream <<
"If the result distribution is setup then it " 2616 <<
"must be the same as the rhs distribution";
2618 OOMPH_CURRENT_FUNCTION,
2619 OOMPH_EXCEPTION_LOCATION);
2625 if (!solution.
built())
2646 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2649 block_solution[dof_type].build(this->block_distribution_pt(dof_type),0.0);
2652 block_rhs[dof_type].build(this->block_distribution_pt(dof_type),0.0);
2656 this->get_block_vectors(solution,block_solution);
2659 this->get_block_vectors(rhs,block_rhs);
2686 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2689 block_w[dof_type].build(this->block_distribution_pt(dof_type),0.0);
2712 oomph_info <<
"Time for setup of preconditioner [sec]: " 2723 oomph_info <<
"Setup of preconditioner is bypassed in resolve mode" 2733 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2736 block_r[dof_type].build(this->block_distribution_pt(dof_type),0.0);
2741 if(Preconditioner_LHS)
2747 this->return_block_vectors(block_r,r);
2753 this->get_block_vectors(r,block_r);
2758 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2761 block_r[dof_type]=block_rhs[dof_type];
2766 double norm_r=block_r[0].norm();
2769 double norm_c=block_r[1].norm();
2772 double normb=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
2800 oomph_info << 0 <<
" " << resid << std::endl;
2817 oomph_info <<
"GMRES converged immediately. Normalised residual norm: " 2818 << resid << std::endl;
2829 block_v.resize(n_row+1);
2833 for (
unsigned dof_type=0;dof_type<n_row+1;dof_type++)
2836 block_v[dof_type].resize(n_dof_types);
2847 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2851 block_v[0][dof_type].build(this->block_distribution_pt(dof_type),0.0);
2855 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2858 double* v0_pt=block_v[0][dof_type].values_pt();
2861 const double* block_r_pt=block_r[dof_type].values_pt();
2864 for (
unsigned i=0;
i<n_row;
i++)
2867 v0_pt[
i]=block_r_pt[
i]/beta;
2880 hessenberg[j].resize(j+2,std::complex<double>(0.0,0.0));
2897 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
2899 block_temp[dof_type].build(this->block_distribution_pt(dof_type),0.0);
2903 if(Preconditioner_LHS)
2910 this->return_block_vectors(block_temp,temp);
2913 this->return_block_vectors(block_w,w);
2919 this->get_block_vectors(w,block_w);
2925 this->return_block_vectors(block_v[j],vj);
2931 this->get_block_vectors(temp,block_temp);
2940 double* block_w_r_pt=block_w[0].values_pt();
2943 double* block_w_c_pt=block_w[1].values_pt();
2949 for (
unsigned i=0;
i<j+1;
i++)
2952 const double* vi_r_pt=block_v[
i][0].values_pt();
2955 const double* vi_c_pt=block_v[
i][1].values_pt();
2958 for (
unsigned k=0;k<n_row;k++)
2961 std::complex<double> complex_v(vi_r_pt[k],vi_c_pt[k]);
2964 std::complex<double> complex_w(block_w_r_pt[k],block_w_c_pt[k]);
2968 hessenberg[j][
i]+=std::conj(complex_v)*complex_w;
2973 for (
unsigned k=0;k<n_row;k++)
2976 block_w_r_pt[k]-=(hessenberg[j][
i].real()*vi_r_pt[k]-
2977 hessenberg[j][
i].imag()*vi_c_pt[k]);
2980 block_w_c_pt[k]-=(hessenberg[j][
i].real()*vi_c_pt[k]+
2981 hessenberg[j][
i].imag()*vi_r_pt[k]);
2986 norm_r=block_w[0].norm();
2989 norm_c=block_w[1].norm();
2993 hessenberg[j][j+1]=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
2996 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3000 block_v[j+1][dof_type].build(this->block_distribution_pt(dof_type),0.0);
3005 if (hessenberg[j][j+1]!=0.0)
3008 double* v_r_pt=block_v[j+1][0].values_pt();
3011 double* v_c_pt=block_v[j+1][1].values_pt();
3014 const double* block_w_r_pt=block_w[0].values_pt();
3017 const double* block_w_c_pt=block_w[1].values_pt();
3024 double h_subdiag_val=hessenberg[j][j+1].real();
3027 for(
unsigned k=0;k<n_row;k++)
3030 v_r_pt[k]=block_w_r_pt[k]/h_subdiag_val;
3033 v_c_pt[k]=block_w_c_pt[k]/h_subdiag_val;
3045 oomph_info <<
"Subdiagonal Hessenberg entry is zero. " 3046 <<
"Do something here..." << std::endl;
3051 for (
unsigned k=0;k<j;k++)
3055 apply_plane_rotation(hessenberg[j][k],hessenberg[j][k+1],cs[k],sn[k]);
3059 generate_plane_rotation(hessenberg[j][j],hessenberg[j][j+1],cs[j],sn[j]);
3062 apply_plane_rotation(hessenberg[j][j],hessenberg[j][j+1],cs[j],sn[j]);
3066 apply_plane_rotation(s[j],s[j+1],cs[j],sn[j]);
3071 beta=std::abs(s[j+1]);
3084 oomph_info << j+1 <<
" " << resid << std::endl;
3102 update(j,hessenberg,s,block_v,block_solution);
3105 this->return_block_vectors(block_solution,solution);
3111 oomph_info <<
"\nGMRES converged (1). Normalised residual norm: " 3112 << resid << std::endl;
3115 oomph_info <<
"Number of iterations to convergence: " 3116 << j+1 <<
"\n" << std::endl;
3129 oomph_info <<
"Time for solve with GMRES [sec]: " 3147 update(Max_iter-1,hessenberg,s,block_v,block_solution);
3150 this->return_block_vectors(block_solution,solution);
3159 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3162 block_temp[dof_type].build(this->block_distribution_pt(dof_type),0.0);
3169 double* block_temp_r_pt=block_temp[0].values_pt();
3172 double* block_temp_c_pt=block_temp[1].values_pt();
3175 const double* block_rhs_r_pt=block_rhs[0].values_pt();
3178 const double* block_rhs_c_pt=block_rhs[1].values_pt();
3181 for (
unsigned i=0;
i<n_row;
i++)
3184 block_temp_r_pt[
i]=block_rhs_r_pt[
i]-block_temp_r_pt[
i];
3187 block_temp_c_pt[
i]=block_rhs_c_pt[
i]-block_temp_c_pt[
i];
3191 if(Preconditioner_LHS)
3200 this->return_block_vectors(block_temp,temp);
3203 this->return_block_vectors(block_r,r);
3214 norm_r=block_r[0].norm();
3217 norm_c=block_r[1].norm();
3220 beta=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
3232 oomph_info <<
"\nGMRES converged (2). Normalised residual norm: " 3234 <<
"\nNumber of iterations to convergence: " 3235 << Iterations <<
"\n" << std::endl;
3247 oomph_info <<
"Time for solve with GMRES [sec]: " 3254 oomph_info <<
"\nGMRES did not converge to required tolerance! " 3255 <<
"\nReturning with normalised residual norm: " << resid
3256 <<
"\nafter " << Max_iter <<
" iterations.\n" << std::endl;
3261 std::string err=
"Solver failed to converge and you requested an error";
3262 err+=
" on convergence failures.";
3264 OOMPH_CURRENT_FUNCTION);
3284 template<
typename MATRIX>
3294 this->Preconditioner_LHS=
false;
3321 std::ostringstream error_message_stream;
3324 error_message_stream <<
"FGMRES cannot use left preconditioning. It is " 3325 <<
"only capable of using right preconditioning." 3330 OOMPH_CURRENT_FUNCTION,
3331 OOMPH_EXCEPTION_LOCATION);
3339 #ifdef OOMPH_HAS_MPI 3345 OomphLibWarning(
"Can't guarantee the MG solver will work in parallel!",
3346 OOMPH_CURRENT_FUNCTION,
3347 OOMPH_EXCEPTION_LOCATION);
3352 unsigned n_dof=problem_pt->
ndof();
3358 this->Resolving=
false;
3376 MATRIX* matrix_pt=
new MATRIX;
3378 if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt) != 0)
3380 if (dynamic_cast<CRDoubleMatrix*>(matrix_pt) != 0)
3392 this->Matrix_can_be_deleted=
true;
3395 this->set_matrix_pt(matrix_pt);
3405 bool allow_different_element_types_in_mesh=
true;
3406 this->set_mesh(0,problem_pt->
mesh_pt(),
3407 allow_different_element_types_in_mesh);
3410 this->block_setup();
3413 unsigned nblock_types=this->nblock_types();
3417 if (nblock_types!=2)
3420 std::stringstream tmp;
3421 tmp <<
"There are supposed to be two block types.\nYours has " 3422 << nblock_types << std::endl;
3426 OOMPH_CURRENT_FUNCTION,
3427 OOMPH_EXCEPTION_LOCATION);
3432 this->Matrices_storage_pt.resize(2,0);
3435 for (
unsigned i=0;
i<nblock_types;
i++)
3444 this->get_block(
i,j,*(this->Matrices_storage_pt[
i]));
3453 oomph_info <<
"\nTime for setup of block Jacobian [sec]: " 3471 solve_helper(matrix_pt,f,result);
3480 solve_helper(matrix_pt,f,result);
3500 const Vector<
Vector<std::complex<double> > >& hessenberg,
3501 const Vector<std::complex<double> >&
s,
3524 for (
int i=
int(k);
i>=0;
i--)
3527 y[
i]/=hessenberg[
i][
i];
3530 for (
int j=
i-1;j>=0;j--)
3533 y[j]-=hessenberg[
i][j]*y[
i];
3539 unsigned n_row=x[0].nrow();
3545 for (
unsigned dof_type=0;dof_type<2;dof_type++)
3552 double* block_update_r_pt=block_update[0].values_pt();
3555 double* block_update_c_pt=block_update[1].values_pt();
3558 for (
unsigned j=0;j<=k;j++)
3561 const double* z_mj_r_pt=z_m[j][0].values_pt();
3564 const double* z_mj_c_pt=z_m[j][1].values_pt();
3567 for (
unsigned i=0;
i<n_row;
i++)
3570 block_update_r_pt[
i]+=(z_mj_r_pt[
i]*y[j].real())-(z_mj_c_pt[
i]*y[j].imag());
3573 block_update_c_pt[
i]+=(z_mj_c_pt[
i]*y[j].real())+(z_mj_r_pt[
i]*y[j].imag());
3579 for (
unsigned dof_type=0;dof_type<2;dof_type++)
3582 x[dof_type]+=block_update[dof_type];
3601 template <
typename MATRIX>
3608 unsigned n_dof_types=this->ndof_types();
3615 std::stringstream error_message_stream;
3618 error_message_stream <<
"This preconditioner only works for problems " 3619 <<
"with 2 dof types\nYours has " << n_dof_types;
3623 OOMPH_CURRENT_FUNCTION,
3624 OOMPH_EXCEPTION_LOCATION);
3631 unsigned n_row=this->Matrices_storage_pt[0]->nrow();
3638 std::ostringstream error_message_stream;
3641 error_message_stream <<
"The maximum number of iterations cannot exceed " 3642 <<
"the number of rows in the problem." 3643 <<
"\nMaximum number of iterations: " << this->
Max_iter 3644 <<
"\nNumber of rows: " << n_row
3649 OOMPH_CURRENT_FUNCTION,
3650 OOMPH_EXCEPTION_LOCATION);
3655 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3659 if (dynamic_cast<DistributableLinearAlgebraObject*>
3660 (this->Matrices_storage_pt[dof_type])!=0)
3662 if (dynamic_cast<DistributableLinearAlgebraObject*>
3663 (this->Matrices_storage_pt[dof_type])->distributed())
3665 std::ostringstream error_message_stream;
3666 error_message_stream <<
"The matrix must not be distributed.";
3668 OOMPH_CURRENT_FUNCTION,
3669 OOMPH_EXCEPTION_LOCATION);
3676 std::ostringstream error_message_stream;
3677 error_message_stream <<
"The rhs vector distribution must be setup.";
3679 OOMPH_CURRENT_FUNCTION,
3680 OOMPH_EXCEPTION_LOCATION);
3683 if(rhs.
nrow()!=2*n_row)
3685 std::ostringstream error_message_stream;
3686 error_message_stream <<
"RHS does not have the same dimension as the" 3687 <<
" linear system";
3689 OOMPH_CURRENT_FUNCTION,
3690 OOMPH_EXCEPTION_LOCATION);
3695 std::ostringstream error_message_stream;
3696 error_message_stream <<
"The rhs vector must not be distributed.";
3698 OOMPH_CURRENT_FUNCTION,
3699 OOMPH_EXCEPTION_LOCATION);
3703 if (solution.
built())
3707 std::ostringstream error_message_stream;
3708 error_message_stream <<
"If the result distribution is setup then it " 3709 <<
"must be the same as the rhs distribution";
3711 OOMPH_CURRENT_FUNCTION,
3712 OOMPH_EXCEPTION_LOCATION);
3718 if (!solution.
built())
3739 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3742 block_solution[dof_type].build(this->block_distribution_pt(dof_type),0.0);
3745 block_rhs[dof_type].build(this->block_distribution_pt(dof_type),0.0);
3749 this->get_block_vectors(solution,block_solution);
3752 this->get_block_vectors(rhs,block_rhs);
3779 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3782 block_w[dof_type].build(this->block_distribution_pt(dof_type),0.0);
3786 if (!(this->Resolving))
3805 oomph_info <<
"Time for setup of preconditioner [sec]: " 3816 oomph_info <<
"Setup of preconditioner is bypassed in resolve mode" 3826 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3829 block_r[dof_type].build(this->block_distribution_pt(dof_type),0.0);
3833 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3836 block_r[dof_type]=block_rhs[dof_type];
3840 double norm_r=block_r[0].norm();
3843 double norm_c=block_r[1].norm();
3846 double normb=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
3874 oomph_info << 0 <<
" " << resid << std::endl;
3891 oomph_info <<
"FGMRES converged immediately. Normalised residual norm: " 3892 << resid << std::endl;
3903 block_v.resize(n_row+1);
3909 block_z.resize(n_row+1);
3913 for (
unsigned i=0;
i<n_row+1;
i++)
3916 block_v[
i].resize(n_dof_types);
3919 block_z[
i].resize(n_dof_types);
3930 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3934 block_v[0][dof_type].build(this->block_distribution_pt(dof_type),0.0);
3938 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3941 double* block_v0_pt=block_v[0][dof_type].values_pt();
3944 const double* block_r_pt=block_r[dof_type].values_pt();
3947 for (
unsigned i=0;
i<n_row;
i++)
3950 block_v0_pt[
i]=block_r_pt[
i]/beta;
3960 for (
unsigned j=0;j<this->
Max_iter;j++)
3963 hessenberg[j].resize(j+2,std::complex<double>(0.0,0.0));
3977 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
3980 block_z[j][dof_type].build(this->block_distribution_pt(dof_type),0.0);
3984 this->return_block_vectors(block_v[j],vj);
3990 this->get_block_vectors(zj,block_z[j]);
3998 double* block_w_r_pt=block_w[0].values_pt();
4001 double* block_w_c_pt=block_w[1].values_pt();
4007 for (
unsigned i=0;
i<j+1;
i++)
4010 const double* block_vi_r_pt=block_v[
i][0].values_pt();
4013 const double* block_vi_c_pt=block_v[
i][1].values_pt();
4016 for (
unsigned k=0;k<n_row;k++)
4019 std::complex<double> complex_v(block_vi_r_pt[k],block_vi_c_pt[k]);
4022 std::complex<double> complex_w(block_w_r_pt[k],block_w_c_pt[k]);
4026 hessenberg[j][
i]+=std::conj(complex_v)*complex_w;
4031 for (
unsigned k=0;k<n_row;k++)
4034 block_w_r_pt[k]-=(hessenberg[j][
i].real()*block_vi_r_pt[k]-
4035 hessenberg[j][
i].imag()*block_vi_c_pt[k]);
4038 block_w_c_pt[k]-=(hessenberg[j][
i].real()*block_vi_c_pt[k]+
4039 hessenberg[j][
i].imag()*block_vi_r_pt[k]);
4044 norm_r=block_w[0].norm();
4047 norm_c=block_w[1].norm();
4051 hessenberg[j][j+1]=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
4054 for (
unsigned dof_type=0;dof_type<n_dof_types;dof_type++)
4058 block_v[j+1][dof_type].build(this->block_distribution_pt(dof_type),0.0);
4063 if (hessenberg[j][j+1]!=0.0)
4066 double* block_v_r_pt=block_v[j+1][0].values_pt();
4069 double* block_v_c_pt=block_v[j+1][1].values_pt();
4072 const double* block_w_r_pt=block_w[0].values_pt();
4075 const double* block_w_c_pt=block_w[1].values_pt();
4082 double h_subdiag_val=hessenberg[j][j+1].real();
4085 for(
unsigned k=0;k<n_row;k++)
4088 block_v_r_pt[k]=block_w_r_pt[k]/h_subdiag_val;
4091 block_v_c_pt[k]=block_w_c_pt[k]/h_subdiag_val;
4103 oomph_info <<
"Subdiagonal Hessenberg entry is zero. " 4104 <<
"Do something here..." << std::endl;
4109 for (
unsigned k=0;k<j;k++)
4113 this->apply_plane_rotation(hessenberg[j][k],hessenberg[j][k+1],cs[k],sn[k]);
4117 this->generate_plane_rotation(hessenberg[j][j],hessenberg[j][j+1],cs[j],sn[j]);
4120 this->apply_plane_rotation(hessenberg[j][j],hessenberg[j][j+1],cs[j],sn[j]);
4124 this->apply_plane_rotation(s[j],s[j+1],cs[j],sn[j]);
4129 beta=std::abs(s[j+1]);
4142 oomph_info << j+1 <<
" " << resid << std::endl;
4153 if (resid<this->Tolerance)
4156 this->Iterations=j+1;
4160 update(j,hessenberg,s,block_z,block_solution);
4163 this->return_block_vectors(block_solution,solution);
4169 oomph_info <<
"\nFGMRES converged (1). Normalised residual norm: " 4170 << resid << std::endl;
4173 oomph_info <<
"Number of iterations to convergence: " 4174 << j+1 <<
"\n" << std::endl;
4187 oomph_info <<
"Time for solve with FGMRES [sec]: " 4201 if (this->Max_iter>0)
4205 update(this->Max_iter-1,hessenberg,s,block_z,block_solution);
4208 this->return_block_vectors(block_solution,solution);
4215 norm_r=block_r[0].norm();
4218 norm_c=block_r[1].norm();
4221 beta=sqrt(pow(norm_r,2.0)+pow(norm_c,2.0));
4227 if (resid<this->Tolerance)
4233 oomph_info <<
"\nFGMRES converged (2). Normalised residual norm: " 4235 <<
"\nNumber of iterations to convergence: " 4236 << this->Iterations <<
"\n" << std::endl;
4248 oomph_info <<
"Time for solve with FGMRES [sec]: " 4255 oomph_info <<
"\nFGMRES did not converge to required tolerance! " 4256 <<
"\nReturning with normalised residual norm: " << resid
4257 <<
"\nafter " << this->Max_iter <<
" iterations.\n" << std::endl;
4262 std::string err=
"Solver failed to converge and you requested an error";
4263 err+=
" on convergence failures.";
4265 OOMPH_CURRENT_FUNCTION);
bool Throw_error_after_max_iter
Should we throw an error instead of just returning when we hit the max iterations?
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 broken_copy(const std::string &class_name)
Issue error message and terminate execution.
~ComplexDampedJacobi()
Empty destructor.
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 apply_plane_rotation(std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
Helper function: Apply plane rotation. This is done using the update: Taken from: Saad Y...
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(Problem *const &problem_pt, DoubleVector &result)
Use damped Jacobi iteration as an IterativeLinearSolver: This obtains the Jacobian matrix J and the r...
Preconditioner *& preconditioner_pt()
Access function to preconditioner.
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
void complex_matrix_multiplication(Vector< CRDoubleMatrix *> const matrices_pt, const Vector< DoubleVector > &x, Vector< DoubleVector > &soln)
Helper function to calculate a complex matrix-vector product. Assumes the matrix has been provided as...
void set_preconditioner_RHS()
Enable right preconditioning.
virtual void preconditioner_solve(const DoubleVector &r, DoubleVector &z)=0
Apply the preconditioner. Pure virtual generic interface function. This method should apply the preco...
double & tolerance()
Access to convergence tolerance.
The GMRES method for the Helmholtz solver.
unsigned iterations() const
Number of iterations taken.
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...
The GMRES method rewritten for complex matrices.
double Tolerance
Convergence tolerance.
CRDoubleMatrix * Matrix_imag_pt
Pointer to the real part of the system matrix.
bool Matrix_can_be_deleted
Boolean flag to indicate if the matrices pointed to by Matrix_real_pt and Matrix_imag_pt can be delet...
void operator=(const ComplexGMRES &)
Broken assignment operator.
void operator=(const ComplexDampedJacobi &)
Broken assignment operator.
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
unsigned Iterations
Number of iterations taken.
unsigned Max_iter
Maximum number of iterations.
HelmholtzSmoother()
Empty constructor.
const double Pi
50 digits from maple
Vector< double > Matrix_diagonal_real
Vector containing the diagonal entries of A_r (real(A))
bool Enable_resolve
Boolean that indicates whether the matrix (or its factors, in the case of direct solver) should be st...
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...
unsigned Iterations
Number of iterations taken.
void update(const unsigned &k, const Vector< Vector< std::complex< double > > > &hessenberg, const Vector< std::complex< double > > &s, const Vector< Vector< DoubleVector > > &z_m, Vector< DoubleVector > &x)
Helper function to update the result vector.
bool Matrix_can_be_deleted
Boolean flag to indicate if the real and imaginary system matrices can be deleted.
static OomphCommunicator * communicator_pt()
access to the global oomph-lib communicator
Mesh *& mesh_pt()
Return a pointer to the global mesh.
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.
double & omega()
Get access to the value of Omega (lvalue)
virtual ~HelmholtzFGMRESMG()
Destructor (cleanup storage)
ComplexDampedJacobi(const ComplexDampedJacobi &)
Broken copy constructor.
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
~ComplexGMRES()
Empty destructor.
void complex_smoother_solve(const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
The smoother_solve function performs fixed number of iterations on the system A*result=rhs. The number of (smoothing) iterations is the same as the max. number of iterations in the underlying IterativeLinearSolver class.
void complex_matrix_multiplication(Vector< CRDoubleMatrix *> matrices_pt, const Vector< DoubleVector > &x, Vector< DoubleVector > &soln)
Helper function to calculate a complex matrix-vector product. Assumes the matrix has been provided as...
bool distributed() const
distribution is serial or distributed
virtual void complex_smoother_solve(const Vector< DoubleVector > &rhs, Vector< DoubleVector > &result)=0
The smoother_solve function performs fixed number of iterations on the system A*result=rhs. The number of (smoothing) iterations is the same as the max. number of iterations in the underlying IterativeLinearSolver class.
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.
void complex_smoother_setup(Vector< CRDoubleMatrix *> helmholtz_matrix_pt)
Setup: Pass pointer to the matrix and store in cast form.
void disable_resolve()
Overload disable resolve so that it cleans up memory too.
HelmholtzFGMRESMG(const HelmholtzFGMRESMG &)
Broken copy constructor.
Vector< CRDoubleMatrix * > Matrices_storage_pt
Vector of pointers to the real and imaginary part of the system matrix.
void operator=(const HelmholtzFGMRESMG &)
Broken assignment operator.
bool Doc_time
Boolean flag that indicates whether the time taken.
The FGMRES method, i.e. the flexible variant of the GMRES method which allows for nonconstant precond...
void solve(DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
Linear-algebra-type solver: Takes pointer to a matrix and rhs vector and returns the solution of the ...
double Jacobian_setup_time
Jacobian setup time.
bool Matrix_can_be_deleted
Boolean flag to indicate if the matrix pointed to be Matrix_pt can be deleted.
bool Use_as_smoother
When a derived class object is being used as a smoother in the MG algorithm the residual norm does no...
void initialise(const double &v)
initialise the whole vector with value v
void complex_solve_helper(const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
This is where the actual work is done.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Implementation of the pure virtual base class function. The function has been broken because this is ...
virtual ~HelmholtzGMRESMG()
Destructor (cleanup storage)
unsigned Iterations
Number of iterations taken.
void set_preconditioner_LHS()
Set left preconditioning (the default)
void generate_plane_rotation(std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
Helper function: Generate a plane rotation. This is done by finding the value of (i...
Vector< double > Matrix_diagonal_imag
Vector containing the diagonal entries of A_c (imag(A))
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
HelmholtzGMRESMG()
Constructor.
bool Resolving
Boolean flag to indicate if the solve is done in re-solve mode, bypassing setup of matrix and precond...
bool Preconditioner_LHS
boolean indicating use of left hand preconditioning (if true) or right hand preconditioning (if false...
Vector< CRDoubleMatrix * > Matrices_storage_pt
Vector of pointers to the real and imaginary part of the system matrix.
double timer()
returns the time in seconds after some point in past
virtual ~HelmholtzSmoother()
Virtual empty destructor.
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
void setup(DoubleMatrixBase *matrix_pt)
Setup the preconditioner: store the matrix pointer and the communicator pointer then call preconditio...
void complex_smoother_setup(Vector< CRDoubleMatrix *> helmholtz_matrix_pt)
Setup: Pass pointer to the matrix and store in cast form.
CRDoubleMatrix * Matrix_real_pt
Pointer to the real part of the system matrix.
void check_validity_of_solve_helper_inputs(CRDoubleMatrix *const &real_matrix_pt, CRDoubleMatrix *const &imag_matrix_pt, const Vector< DoubleVector > &rhs, Vector< 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 Solution_time
linear solver solution time
unsigned long ndof() const
Return the number of dofs.
virtual void disable_resolve()
Disable resolve (i.e. store matrix and/or LU decomposition, say) This function simply resets an inter...
bool Resolving
Boolean flag to indicate if the solve is done in re-solve mode, bypassing setup of matrix and precond...
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 ...
void calculate_omega(const double &k, const double &h)
Function to calculate the value of Omega by passing in the value of k and h [see Elman et al...
double Omega
Damping factor.
void broken_assign(const std::string &class_name)
Issue error message and terminate execution.
unsigned nrow() const
access function to the number of global rows.
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.
HelmholtzFGMRESMG()
Constructor (empty)
void set_preconditioner_LHS()
Overloaded function to let the user know that left preconditioning is not possible with FGMRES...
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
setup the distribution of this distributable linear algebra object
void apply_plane_rotation(std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
Helper function: Apply plane rotation. This is done using the update: Taken from: Saad Y...
void update(const unsigned &k, const Vector< Vector< std::complex< double > > > &hessenberg, const Vector< std::complex< double > > &s, const Vector< Vector< DoubleVector > > &v, Vector< DoubleVector > &x)
Helper function to update the result vector.
void update(const unsigned &k, const Vector< Vector< std::complex< double > > > &hessenberg, const Vector< std::complex< double > > &s, const Vector< Vector< DoubleVector > > &v, Vector< DoubleVector > &x)
Helper function to update the result vector.
void disable_resolve()
Overload disable resolve so that it cleans up memory too.
void solve_helper(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
General interface to solve function.
unsigned iterations() const
Number of iterations taken.
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
void resolve(const DoubleVector &rhs, DoubleVector &result)
Re-solve the system defined by the last assembled Jacobian and the rhs vector specified here...
ComplexGMRES(const ComplexGMRES &)
Broken copy constructor.
Vector< double > Matrix_diagonal_inv_sq
Vector whose j'th entry is given by 1/(A_r(j,j)^2 + A_c(j,j)^2)
bool Setup_preconditioner_before_solve
indicates whether the preconditioner should be setup before solve. Default = true; ...
void operator=(const HelmholtzGMRESMG &)
Broken assignment operator.
void complex_solve_helper(const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
This is where the actual work is done.
void setup()
Implementation of the pure virtual base class function. This accompanies the preconditioner_solve fun...
void solve(DoubleMatrixBase *const &matrix_pt, const DoubleVector &rhs, DoubleVector &solution)
Linear-algebra-type solver: Takes pointer to a matrix and rhs vector and returns the solution of the ...
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.
ComplexGMRES()
Constructor.
void generate_plane_rotation(std::complex< double > &dx, std::complex< double > &dy, std::complex< double > &cs, std::complex< double > &sn)
Helper function: Generate a plane rotation. This is done by finding the value of (i...
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
double Preconditioner_setup_time
Preconditioner setup time.
void solve(DoubleMatrixBase *const &matrix_pt, const Vector< double > &rhs, Vector< double > &result)
Linear-algebra-type solver: Takes pointer to a matrix and rhs vector and returns the solution of the ...
ComplexDampedJacobi(const double &omega=0.5)
Constructor (empty)
virtual void complex_smoother_setup(Vector< CRDoubleMatrix *> matrix_pt)=0
Setup the smoother for the matrix specified by the pointer.
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...
Base class for all linear iterative solvers. This merely defines standard interfaces for linear itera...
unsigned iterations() const
Number of iterations taken.
void complex_smoother_solve(const Vector< DoubleVector > &rhs, Vector< DoubleVector > &solution)
The smoother_solve function performs fixed number of iterations on the system A*result=rhs. The number of (smoothing) iterations is the same as the max. number of iterations in the underlying IterativeLinearSolver class.
void clean_up_memory()
Cleanup data that's stored for resolve (if any has been stored)
HelmholtzGMRESMG(const HelmholtzGMRESMG &)
Broken copy constructor.