2 #ifndef OOMPH_HELMHOLTZ_GEOMETRIC_MULTIGRID_HEADER 3 #define OOMPH_HELMHOLTZ_GEOMETRIC_MULTIGRID_HEADER 61 template<
unsigned DIM>
77 PreSmootherFactoryFctPt pre_smoother_fn)
80 Pre_smoother_factory_function_pt=pre_smoother_fn;
85 PostSmootherFactoryFctPt post_smoother_fn)
88 Post_smoother_factory_function_pt=post_smoother_fn;
95 Pre_smoother_factory_function_pt(0),
96 Post_smoother_factory_function_pt(0),
97 Mg_problem_pt(mg_problem_pt),
103 Suppress_v_cycle_output(false),
104 Suppress_all_output(false),
105 Has_been_setup(false),
106 Has_been_solved(false),
112 Mg_hierarchy_pt.push_back(Mg_problem_pt);
130 for (
unsigned i=0;
i<Nlevel-1;
i++)
133 delete Pre_smoothers_storage_pt[
i];
136 Pre_smoothers_storage_pt[
i]=0;
139 delete Post_smoothers_storage_pt[
i];
142 Post_smoothers_storage_pt[
i]=0;
146 for (
unsigned j=0;j<2;j++)
149 delete Mg_matrices_storage_pt[
i][j];
152 Mg_matrices_storage_pt[
i][j]=0;
158 delete Coarsest_matrix_mg_pt;
161 Coarsest_matrix_mg_pt=0;
164 for (
unsigned i=0;
i<Nlevel-1;
i++)
167 delete Interpolation_matrices_storage_pt[
i];
170 Interpolation_matrices_storage_pt[
i]=0;
173 delete Restriction_matrices_storage_pt[
i];
176 Restriction_matrices_storage_pt[
i]=0;
181 Has_been_setup=
false;
214 Suppress_v_cycle_output=
true;
225 Suppress_v_cycle_output=
true;
228 Suppress_all_output=
true;
252 Suppress_v_cycle_output=
false;
262 Suppress_all_output=
false;
265 Suppress_v_cycle_output=
false;
272 for (
unsigned i=0;
i<Nlevel-1;
i++)
275 Pre_smoothers_storage_pt[
i]->disable_doc_time();
278 Post_smoothers_storage_pt[
i]->disable_doc_time();
283 Coarsest_matrix_mg_pt->linear_solver_pt()->disable_doc_time();
310 Pre_smoothers_storage_pt[level]->
311 complex_smoother_solve(Rhs_mg_vectors_storage[level],
312 X_mg_vectors_storage[level]);
315 residual_norm(level);
326 Post_smoothers_storage_pt[level]->
327 complex_smoother_solve(Rhs_mg_vectors_storage[level],
328 X_mg_vectors_storage[level]);
331 residual_norm(level);
340 for (
unsigned j=0;j<2;j++)
343 Residual_mg_vectors_storage[level][j].initialise(0.0);
347 return residual_norm(level,Residual_mg_vectors_storage[level]);
355 void setup_coarsest_level_structures();
370 Coarsest_matrix_mg_pt->solve(Coarsest_rhs_mg,Coarsest_x_mg);
390 Interpolation_matrices_storage_pt[level]->
391 build_without_copy(ncol,nnz,value,col_index,row_st);
416 std::string warning_message=
"Setup of interpolation matrix distribution ";
417 warning_message+=
"has not been tested with MPI.";
424 OOMPH_CURRENT_FUNCTION,
425 OOMPH_EXCEPTION_LOCATION);
431 Interpolation_matrices_storage_pt[level]->
432 build(dist_pt,ncol,value,col_index,row_st);
447 for (
unsigned i=0;
i<Nlevel-1;
i++)
454 Interpolation_matrices_storage_pt[
i]->
455 get_matrix_transpose(Restriction_matrices_storage_pt[
i]);
461 void restrict_residual(
const unsigned& level);
465 void interpolate_and_correct(
const unsigned& level);
471 void level_up_local_coord_of_node(
const int& son_type,
475 void setup_interpolation_matrices();
479 void setup_interpolation_matrices_unstructured();
482 void setup_transfer_matrices();
493 this->get_block_vectors(r,Rhs_mg_vectors_storage[0]);
497 this->get_block_vectors(z,X_mg_vectors_storage[0]);
500 this->mg_solve(X_mg_vectors_storage[0]);
503 this->return_block_vectors(X_mg_vectors_storage[0],z);
506 if (!(this->Suppress_v_cycle_output))
510 <<
"Multigrid Preconditioner Solve Complete" 511 <<
"=========" << std::endl;
516 if (this->Suppress_all_output)
527 return V_cycle_counter;
555 void block_preconditioner_self_test();
566 if (this->Suppress_all_output)
575 void setup_mg_hierarchy();
579 void setup_mg_structures();
583 void maximum_edge_width(
const unsigned& level,
double& h);
587 void setup_smoothers();
719 template<
unsigned DIM>
724 unsigned n_rows=X_mg_vectors_storage[level][0].nrow();
730 if (residual.size()!=2)
733 throw OomphLibError(
"This residual vector must have length 2. ",
734 OOMPH_CURRENT_FUNCTION,
735 OOMPH_EXCEPTION_LOCATION);
737 if (residual[0].nrow()!=residual[1].nrow())
740 std::ostringstream error_message_stream;
743 error_message_stream <<
"Residual[0] has length: " << residual[0].nrow()
744 <<
"\nResidual[1] has length: " << residual[1].nrow()
745 <<
"\nThis method requires that the constituent " 746 <<
"DoubleVectors in residual have the same length. " 751 OOMPH_CURRENT_FUNCTION,
752 OOMPH_EXCEPTION_LOCATION);
757 for (
unsigned i=0;
i<2;
i++)
761 if (!residual[
i].distribution_built())
768 residual[
i].build(&dist,0.0);
780 (
"This method can only assemble a non-distributed residuals vector ",
781 OOMPH_CURRENT_FUNCTION,
782 OOMPH_EXCEPTION_LOCATION);
794 Mg_matrices_storage_pt[level][0]->distribution_pt();
818 Mg_matrices_storage_pt[level][0]->
819 multiply(X_mg_vectors_storage[level][0],temp_vec_rr);
822 Mg_matrices_storage_pt[level][0]->
823 multiply(X_mg_vectors_storage[level][1],temp_vec_rc);
826 Mg_matrices_storage_pt[level][1]->
827 multiply(X_mg_vectors_storage[level][0],temp_vec_cr);
830 Mg_matrices_storage_pt[level][1]->
831 multiply(X_mg_vectors_storage[level][1],temp_vec_cc);
834 residual[0]=Rhs_mg_vectors_storage[level][0];
835 residual[0]-=temp_vec_rr;
836 residual[0]+=temp_vec_cc;
839 residual[1]=Rhs_mg_vectors_storage[level][1];
840 residual[1]-=temp_vec_rc;
841 residual[1]-=temp_vec_cr;
844 double norm_r=residual[0].norm();
847 double norm_c=residual[1].norm();
851 return sqrt(norm_r*norm_r+norm_c*norm_c);
858 template<
unsigned DIM>
862 clock_t t_bl_start=clock();
865 if (Mg_hierarchy_pt[0]->
mesh_pt()==0)
867 std::stringstream err;
868 err <<
"Please set pointer to mesh using set_bulk_helmholtz_mesh(...).\n";
870 OOMPH_CURRENT_FUNCTION,
871 OOMPH_EXCEPTION_LOCATION);
882 bool allow_different_element_types_in_mesh=
true;
883 this->set_mesh(0,Mg_problem_pt->mesh_pt(),
884 allow_different_element_types_in_mesh);
888 unsigned n_dof_types=this->ndof_types();
891 std::stringstream tmp;
892 tmp <<
"This preconditioner only works for problems with 2 dof types\n" 893 <<
"Yours has " << n_dof_types;
895 OOMPH_CURRENT_FUNCTION,
896 OOMPH_EXCEPTION_LOCATION);
904 unsigned nblock_types=this->nblock_types();
908 std::stringstream tmp;
909 tmp <<
"There are supposed to be two block types.\n" 910 <<
"Yours has " << nblock_types;
912 OOMPH_CURRENT_FUNCTION,
913 OOMPH_EXCEPTION_LOCATION);
921 for (
unsigned i=0;
i<nblock_types;
i++)
923 for (
unsigned j=0;j<nblock_types;j++)
927 this->get_block(
i,j,*block_pt(
i,j));
934 unsigned nnz1=block_pt(0,0)->nnz();
935 unsigned nnz2=block_pt(1,1)->nnz();
938 std::stringstream tmp;
939 tmp <<
"nnz of diagonal blocks doesn't match: " 940 << nnz1 <<
" != " << nnz2 << std::endl;
942 OOMPH_CURRENT_FUNCTION,
943 OOMPH_EXCEPTION_LOCATION);
945 unsigned nrow1=block_pt(0,0)->nrow();
946 unsigned nrow2=block_pt(1,1)->nrow();
949 std::stringstream tmp;
950 tmp <<
"nrow of diagonal blocks doesn't match: " 951 << nrow1 <<
" != " << nrow2 << std::endl;
953 OOMPH_CURRENT_FUNCTION,
954 OOMPH_EXCEPTION_LOCATION);
960 std::stringstream tmp;
963 for (
unsigned i=0;
i<nrow1+1;
i++)
965 if (block_pt(0,0)->row_start()[
i]!=
966 block_pt(1,1)->row_start()[
i])
969 tmp <<
"Row starts of diag matrices don't match for row " <<
i 971 << block_pt(0,0)->row_start()[
i] <<
" " 972 << block_pt(1,1)->row_start()[
i] <<
" " 978 for (
unsigned i=0;
i<nnz1;
i++)
980 if (block_pt(0,0)->column_index()[
i]!=
981 block_pt(1,1)->column_index()[
i])
984 tmp <<
"Column of diag matrices indices don't match for entry " <<
i 986 << block_pt(0,0)->column_index()[
i] <<
" " 987 << block_pt(1,1)->column_index()[
i] <<
" " 991 if (fabs(block_pt(0,0)->value()[
i]-
992 block_pt(1,1)->value()[
i])>tol)
995 tmp <<
"Values of diag matrices don't match for entry " <<
i 997 << block_pt(0,0)->value()[
i] <<
" " 998 << block_pt(1,1)->value()[
i] <<
" " 1005 OOMPH_CURRENT_FUNCTION,
1006 OOMPH_EXCEPTION_LOCATION);
1013 unsigned nnz1=block_pt(0,1)->nnz();
1014 unsigned nnz2=block_pt(1,0)->nnz();
1017 std::stringstream tmp;
1018 tmp <<
"nnz of diagonal blocks doesn't match: " 1019 << nnz1 <<
" != " << nnz2 << std::endl;
1021 OOMPH_CURRENT_FUNCTION,
1022 OOMPH_EXCEPTION_LOCATION);
1024 unsigned nrow1=block_pt(0,1)->nrow();
1025 unsigned nrow2=block_pt(1,0)->nrow();
1028 std::stringstream tmp;
1029 tmp <<
"nrow of off-diagonal blocks doesn't match: " 1030 << nrow1 <<
" != " << nrow2 << std::endl;
1032 OOMPH_CURRENT_FUNCTION,
1033 OOMPH_EXCEPTION_LOCATION);
1040 std::stringstream tmp;
1043 for (
unsigned i=0;
i<nrow1+1;
i++)
1045 if (block_pt(0,1)->row_start()[
i]!=
1046 block_pt(1,0)->row_start()[
i])
1049 tmp <<
"Row starts of off-diag matrices don't match for row " <<
i 1051 << block_pt(0,1)->row_start()[
i] <<
" " 1052 << block_pt(1,0)->row_start()[
i] <<
" " 1058 for (
unsigned i=0;
i<nnz1;
i++)
1060 if (block_pt(0,1)->column_index()[
i]!=
1061 block_pt(1,0)->column_index()[
i])
1064 tmp <<
"Column indices of off-diag matrices don't match for entry " <<
i 1066 << block_pt(0,1)->column_index()[
i] <<
" " 1067 << block_pt(1,0)->column_index()[
i] <<
" " 1071 if (fabs(block_pt(0,1)->value()[
i]+
1072 block_pt(1,0)->value()[
i])>tol)
1075 tmp <<
"Values of off-diag matrices aren't negatives of " 1076 <<
"each other for entry " <<
i 1078 << block_pt(0,1)->value()[
i] <<
" " 1079 << block_pt(1,0)->value()[
i] <<
" " 1086 OOMPH_CURRENT_FUNCTION,
1087 OOMPH_EXCEPTION_LOCATION);
1092 for (
unsigned i=0;
i<nblock_types;
i++)
1094 for (
unsigned j=0;j<nblock_types;j++)
1096 delete block_pt(
i,j);
1102 clock_t t_bl_end=clock();
1103 double total_setup_time=double(t_bl_end-t_bl_start)/CLOCKS_PER_SEC;
1104 oomph_info <<
"CPU time for block preconditioner self-test [sec]: " 1105 << total_setup_time <<
"\n" << std::endl;
1112 template<
unsigned DIM>
1115 #ifdef OOMPH_HAS_MPI 1121 OomphLibWarning(
"Can't guarantee the MG solver will work in parallel!",
1122 OOMPH_CURRENT_FUNCTION,
1123 OOMPH_EXCEPTION_LOCATION);
1128 double t_fs_start=0.0;
1131 if (!Suppress_all_output)
1137 oomph_info <<
"\n========Starting Setup of Multigrid Preconditioner========" 1141 oomph_info <<
"\nStarting the full setup of the Helmholtz multigrid solver." 1148 if (dynamic_cast<FiniteElement*>
1149 (Mg_problem_pt->mesh_pt()->element_pt(0))->dim()!=DIM)
1152 std::string err_strng=
"The dimension of the elements used in the mesh ";
1153 err_strng+=
"does not match the dimension of the solver.";
1157 OOMPH_CURRENT_FUNCTION,
1158 OOMPH_EXCEPTION_LOCATION);
1163 if (Mg_problem_pt->mg_bulk_mesh_pt()!=0)
1166 unsigned n_elements=Mg_problem_pt->mg_bulk_mesh_pt()->nelement();
1170 for (
unsigned el_counter=0;el_counter<n_elements;el_counter++)
1174 (Mg_problem_pt->mg_bulk_mesh_pt()->element_pt(el_counter));
1181 std::ostringstream error_message_stream;
1184 error_message_stream <<
"Element in bulk mesh could not be upcast to " 1185 <<
"a refineable element." << std::endl;
1189 OOMPH_CURRENT_FUNCTION,
1190 OOMPH_EXCEPTION_LOCATION);
1198 std::ostringstream error_message_stream;
1201 error_message_stream <<
"The provided bulk mesh pointer is a null pointer. " 1206 OOMPH_CURRENT_FUNCTION,
1207 OOMPH_EXCEPTION_LOCATION);
1216 Mg_hierarchy_pt.resize(1,0);
1219 Mg_hierarchy_pt[0]=Mg_problem_pt;
1222 setup_mg_hierarchy();
1225 setup_transfer_matrices();
1229 setup_mg_structures();
1235 for (
unsigned i=1;
i<Nlevel;
i++)
1238 delete Mg_hierarchy_pt[
i];
1241 Mg_hierarchy_pt[
i]=0;
1245 Has_been_setup=
true;
1248 if (!Suppress_all_output)
1252 double full_setup_time=t_fs_end-t_fs_start;
1255 oomph_info <<
"\nCPU time for full setup [sec]: " 1256 << full_setup_time << std::endl;
1260 <<
"Multigrid Full Setup Complete" 1261 <<
"==============\n" << std::endl;
1270 template<
unsigned DIM>
1274 double t_m_start=0.0;
1277 if (!Suppress_all_output)
1281 <<
"Creating Multigrid Hierarchy" 1282 <<
"===============\n" << std::endl;
1291 bool managed_to_create_unrefined_copy=
true;
1299 while (managed_to_create_unrefined_copy)
1312 managed_to_create_unrefined_copy=
1314 refine_base_mesh_as_in_reference_mesh_minus_one(
1319 if (managed_to_create_unrefined_copy)
1326 if (!Suppress_all_output)
1330 <<
" has been created:" << std::endl;
1339 <<
"\n" << std::endl;
1343 Mg_hierarchy_pt.push_back(new_problem_pt);
1349 delete new_problem_pt;
1355 Nlevel=Mg_hierarchy_pt.size();
1359 if (!Suppress_all_output)
1363 <<
"Number of levels: " << Nlevel << std::endl;
1374 Mg_matrices_storage_pt.resize(Nlevel);
1377 X_mg_vectors_storage.resize(Nlevel);
1380 Rhs_mg_vectors_storage.resize(Nlevel);
1383 Residual_mg_vectors_storage.resize(Nlevel);
1387 Max_edge_width.resize(Nlevel-1,0.0);
1391 Pre_smoothers_storage_pt.resize(Nlevel-1,0);
1395 Post_smoothers_storage_pt.resize(Nlevel-1,0);
1398 Interpolation_matrices_storage_pt.resize(Nlevel-1,0);
1401 Restriction_matrices_storage_pt.resize(Nlevel-1,0);
1404 if (!Suppress_all_output)
1408 double total_setup_time=double(t_m_end-t_m_start);
1409 oomph_info <<
"\nCPU time for creation of hierarchy of MG problems [sec]: " 1410 << total_setup_time << std::endl;
1414 <<
"Hierarchy Creation Complete" 1415 <<
"================\n" << std::endl;
1426 template<
unsigned DIM>
1430 double t_r_start=0.0;
1433 if (!Suppress_all_output)
1436 oomph_info <<
"Creating the transfer matrices." << std::endl;
1445 if (dynamic_cast<TreeBasedRefineableMeshBase*>
1446 (Mg_problem_pt->mg_bulk_mesh_pt()))
1448 setup_interpolation_matrices();
1454 setup_interpolation_matrices_unstructured();
1458 set_restriction_matrices_as_interpolation_transposes();
1461 if (!Suppress_all_output)
1465 double total_G_setup_time=double(t_r_end-t_r_start);
1466 oomph_info <<
"\nCPU time for transfer matrices setup [sec]: " 1467 << total_G_setup_time << std::endl;
1470 oomph_info <<
"\n============Transfer Matrices Setup Complete==============" 1471 <<
"\n" << std::endl;
1478 template<
unsigned DIM>
1482 double t_m_start=0.0;
1485 if (!Suppress_all_output)
1499 (Mg_problem_pt->mg_bulk_mesh_pt()->element_pt(0));
1504 Wavenumber=sqrt(pml_helmholtz_el_pt->
k_squared());
1508 pml_helmholtz_el_pt=0;
1514 for (
unsigned i=0;
i<Nlevel;
i++)
1517 if (!Suppress_all_output)
1520 oomph_info <<
"Setting up MG structures on level: " <<
i 1521 <<
"\n" << std::endl;
1525 unsigned n_dof_per_block=Mg_hierarchy_pt[
i]->ndof()/2;
1530 n_dof_per_block,
false);
1533 #ifdef OOMPH_HAS_MPI 1535 std::string warning_message=
"Setup of distribution has not been ";
1536 warning_message+=
"tested with MPI.";
1543 OOMPH_CURRENT_FUNCTION,
1544 OOMPH_EXCEPTION_LOCATION);
1553 Mg_matrices_storage_pt[
i].resize(2,0);
1556 for (
unsigned j=0;j<2;j++)
1563 Mg_matrices_storage_pt[
i][0]->
build(dist_pt);
1566 Mg_matrices_storage_pt[
i][1]->build(dist_pt);
1571 X_mg_vectors_storage[
i].resize(2);
1574 X_mg_vectors_storage[
i][0].build(dist_pt);
1577 X_mg_vectors_storage[
i][1].build(dist_pt);
1582 Rhs_mg_vectors_storage[
i].resize(2);
1585 Rhs_mg_vectors_storage[
i][0].build(dist_pt);
1588 Rhs_mg_vectors_storage[
i][1].build(dist_pt);
1593 Residual_mg_vectors_storage[
i].resize(2);
1596 Residual_mg_vectors_storage[
i][0].build(dist_pt);
1599 Residual_mg_vectors_storage[
i][1].build(dist_pt);
1614 double t_jac_start=0.0;
1617 if (!Suppress_all_output)
1625 block_preconditioner_self_test();
1634 bool allow_different_element_types_in_mesh=
true;
1635 this->set_mesh(0,Mg_hierarchy_pt[0]->
mesh_pt(),
1636 allow_different_element_types_in_mesh);
1640 unsigned n_dof_types=this->ndof_types();
1646 std::stringstream tmp;
1647 tmp <<
"This preconditioner only works for problems with 2 dof types\n" 1648 <<
"Yours has " << n_dof_types;
1652 OOMPH_CURRENT_FUNCTION,
1653 OOMPH_EXCEPTION_LOCATION);
1658 if (Alpha_shift!=0.0)
1666 double* alpha_shift_pt=
new double(Alpha_shift);
1669 unsigned n_element=Mg_hierarchy_pt[0]->mesh_pt()->nelement();
1676 (Mg_hierarchy_pt[0]->mesh_pt()->element_pt(0));
1679 static double* default_physical_constant_value_pt=el_pt->
alpha_pt();
1682 for (
unsigned i_el=0;i_el<n_element;i_el++)
1687 (Mg_hierarchy_pt[0]->mesh_pt()->element_pt(i_el));
1715 Mg_hierarchy_pt[0]->get_jacobian(residuals,*shifted_jacobian_pt);
1718 this->set_matrix_pt(shifted_jacobian_pt);
1721 this->block_setup();
1724 unsigned nblock_types=this->nblock_types();
1728 if (nblock_types!=2)
1731 std::stringstream tmp;
1732 tmp <<
"There are supposed to be two block types.\nYours has " 1733 << nblock_types << std::endl;
1737 OOMPH_CURRENT_FUNCTION,
1738 OOMPH_EXCEPTION_LOCATION);
1746 for (
unsigned i_row=0;i_row<nblock_types;i_row++)
1752 this->get_block(i_row,j_col,*Mg_matrices_storage_pt[level][i_row]);
1757 delete shifted_jacobian_pt;
1762 this->set_matrix_pt(jacobian_pt);
1768 for (
unsigned i_el=0;i_el<n_element;i_el++)
1773 (Mg_hierarchy_pt[0]->mesh_pt()->element_pt(i_el));
1776 el_pt->
alpha_pt()=default_physical_constant_value_pt;
1781 delete alpha_shift_pt;
1792 this->block_setup();
1795 unsigned nblock_types=this->nblock_types();
1799 if (nblock_types!=2)
1801 std::stringstream tmp;
1802 tmp <<
"There are supposed to be two block types.\n" 1803 <<
"Yours has " << nblock_types;
1805 OOMPH_CURRENT_FUNCTION,
1806 OOMPH_EXCEPTION_LOCATION);
1814 for (
unsigned i_row=0;i_row<nblock_types;i_row++)
1820 this->get_block(i_row,j_col,*Mg_matrices_storage_pt[level][i_row]);
1824 if (!Suppress_all_output)
1828 double jacobian_setup_time=t_jac_end-t_jac_start;
1829 oomph_info <<
" - Time for setup of Jacobian block matrix [sec]: " 1830 << jacobian_setup_time <<
"\n" << std::endl;
1838 double t_gal_start=0.0;
1841 if (!Suppress_all_output)
1863 Mg_matrices_storage_pt[
i-1][0]->
1864 multiply(*Interpolation_matrices_storage_pt[
i-1],
1865 *Mg_matrices_storage_pt[
i][0]);
1870 Restriction_matrices_storage_pt[i-1]->
1871 multiply(*Mg_matrices_storage_pt[i][0],
1872 *Mg_matrices_storage_pt[i][0]);
1878 Mg_matrices_storage_pt[i-1][1]->
1879 multiply(*Interpolation_matrices_storage_pt[i-1],
1880 *Mg_matrices_storage_pt[i][1]);
1885 Restriction_matrices_storage_pt[i-1]->
1886 multiply(*Mg_matrices_storage_pt[i][1],
1887 *Mg_matrices_storage_pt[i][1]);
1890 if (!Suppress_all_output)
1896 double galerkin_matrix_calculation_time=t_gal_end-t_gal_start;
1899 oomph_info <<
" - Time for system block matrix formation using the " 1900 <<
"Galerkin approximation [sec]: " 1901 << galerkin_matrix_calculation_time <<
"\n" << std::endl;
1911 double t_para_start=0.0;
1914 if (!Suppress_all_output)
1921 maximum_edge_width(
i,Max_edge_width[
i]);
1924 if (!Suppress_all_output)
1930 double parameter_calculation_time=t_para_end-t_para_start;
1933 oomph_info <<
" - Time for maximum edge width calculation [sec]: " 1934 << parameter_calculation_time <<
"\n" << std::endl;
1942 setup_coarsest_level_structures();
1945 if (!Suppress_all_output)
1949 double total_setup_time=double(t_m_end-t_m_start);
1950 oomph_info <<
"CPU time for setup of MG structures [sec]: " 1951 << total_setup_time << std::endl;
1955 <<
"Multigrid Structures Setup Complete" 1956 <<
"===========\n" << std::endl;
1980 template<
unsigned DIM>
1991 CRDoubleMatrix* real_matrix_pt=Mg_matrices_storage_pt[Nlevel-1][0];
1992 CRDoubleMatrix* imag_matrix_pt=Mg_matrices_storage_pt[Nlevel-1][1];
1995 unsigned nnz_r=real_matrix_pt->
nnz();
1996 unsigned nnz_c=imag_matrix_pt->
nnz();
1999 unsigned n_rows_r=real_matrix_pt->
nrow();
2004 const double* value_r_pt=real_matrix_pt->
value();
2005 const int* row_start_r_pt=real_matrix_pt->
row_start();
2006 const int* column_index_r_pt=real_matrix_pt->
column_index();
2009 const double* value_c_pt=imag_matrix_pt->
value();
2010 const int* row_start_c_pt=imag_matrix_pt->
row_start();
2011 const int* column_index_c_pt=imag_matrix_pt->
column_index();
2016 if (real_matrix_pt->
nrow()!=imag_matrix_pt->
nrow())
2018 std::ostringstream error_message_stream;
2019 error_message_stream <<
"The real and imaginary matrices do not have " 2020 <<
"compatible sizes";
2022 OOMPH_CURRENT_FUNCTION,
2023 OOMPH_EXCEPTION_LOCATION);
2027 if (real_matrix_pt->
ncol()!=imag_matrix_pt->
ncol())
2029 std::ostringstream error_message_stream;
2030 error_message_stream <<
"The real and imaginary matrices do not have " 2031 <<
"compatible sizes";
2033 OOMPH_CURRENT_FUNCTION,
2034 OOMPH_EXCEPTION_LOCATION);
2039 unsigned nnz=2*(nnz_r+nnz_c);
2060 for (
unsigned i=0;
i<n_rows_r;
i++)
2063 row_start[
i]=*(row_start_r_pt+
i)+*(row_start_c_pt+
i);
2067 for (
unsigned i=n_rows_r;
i<2*n_rows_r;
i++)
2070 row_start[
i]=row_start[
i-n_rows_r]+(nnz_r+nnz_c);
2074 row_start[2*n_rows_r]=nnz;
2084 for (
unsigned i=0;
i<n_rows_r;
i++)
2087 unsigned i_row_r_nnz=*(row_start_r_pt+
i+1)-*(row_start_r_pt+
i);
2090 unsigned i_row_c_nnz=*(row_start_c_pt+
i+1)-*(row_start_c_pt+
i);
2093 unsigned i_first_entry_r=*(row_start_r_pt+
i);
2096 unsigned i_first_entry_c=*(row_start_c_pt+
i);
2099 for (
unsigned j=0;j<i_row_r_nnz;j++)
2103 column_index[i_nnz]=*(column_index_r_pt+i_first_entry_r+j);
2106 value[i_nnz]=*(value_r_pt+i_first_entry_r+j);
2113 for (
unsigned j=0;j<i_row_c_nnz;j++)
2117 column_index[i_nnz]=*(column_index_c_pt+i_first_entry_c+j)+n_rows_r;
2120 value[i_nnz]=-*(value_c_pt+i_first_entry_c+j);
2128 for (
unsigned i=n_rows_r;
i<2*n_rows_r;
i++)
2131 unsigned i_row_r_nnz=
2132 *(row_start_r_pt+
i-n_rows_r+1)-*(row_start_r_pt+
i-n_rows_r);
2135 unsigned i_row_c_nnz=
2136 *(row_start_c_pt+
i-n_rows_r+1)-*(row_start_c_pt+
i-n_rows_r);
2139 unsigned i_first_entry_r=*(row_start_r_pt+
i-n_rows_r);
2142 unsigned i_first_entry_c=*(row_start_c_pt+
i-n_rows_r);
2145 for (
unsigned j=0;j<i_row_c_nnz;j++)
2149 column_index[i_nnz]=*(column_index_c_pt+i_first_entry_c+j);
2152 value[i_nnz]=*(value_c_pt+i_first_entry_c+j);
2159 for (
unsigned j=0;j<i_row_r_nnz;j++)
2163 column_index[i_nnz]=*(column_index_r_pt+i_first_entry_r+j)+n_rows_r;
2166 value[i_nnz]=*(value_r_pt+i_first_entry_r+j);
2188 Coarsest_matrix_mg_pt->build(dist_pt,
2195 Coarsest_x_mg.build(dist_pt);
2198 Coarsest_rhs_mg.build(dist_pt);
2205 double total_setup_time=double(t_cm_end-t_cm_start);
2206 oomph_info <<
" - Time for formation of the full matrix " 2207 <<
"on the coarsest level [sec]: " 2208 << total_setup_time <<
"\n" << std::endl;
2230 Mg_hierarchy_pt[level]->mg_bulk_mesh_pt();
2246 corner_node_id[0]=0;
2249 corner_node_id[1]=nnode_1d-1;
2252 corner_node_id[2]=nnode_1d*nnode_1d-1;
2255 corner_node_id[3]=nnode_1d*(nnode_1d-1);
2260 Node* first_node_pt=0;
2263 Node* second_node_pt=0;
2276 unsigned n_element=bulk_mesh_pt->
nelement();
2288 for (
unsigned i=0;
i<n_element;
i++)
2294 for (
unsigned j=0;j<n_edge;j++)
2297 first_node_pt=el_pt->
node_pt(corner_node_id[j]);
2300 second_node_pt=el_pt->
node_pt(corner_node_id[(j+1)%4]);
2303 for (
unsigned n=0;n<2;n++)
2306 first_node_x[n]=first_node_pt->x(n);
2310 for (
unsigned n=0;n<2;n++)
2313 second_node_x[n]=second_node_pt->
x(n);
2320 for (
unsigned n=0;n<2;n++)
2323 test_h+=pow(second_node_x[n]-first_node_x[n],2.0);
2327 test_h=sqrt(test_h);
2362 Mg_hierarchy_pt[level]->mg_bulk_mesh_pt();
2385 corner_node_id[0]=octree_pt->
2389 corner_node_id[1]=octree_pt->
2393 corner_node_id[2]=octree_pt->
2397 corner_node_id[3]=octree_pt->
2401 corner_node_id[4]=octree_pt->
2405 corner_node_id[5]=octree_pt->
2409 corner_node_id[6]=octree_pt->
2413 corner_node_id[7]=octree_pt->
2425 edge_node_pair[0]=std::make_pair(corner_node_id[0],corner_node_id[1]);
2428 edge_node_pair[1]=std::make_pair(corner_node_id[0],corner_node_id[2]);
2431 edge_node_pair[2]=std::make_pair(corner_node_id[0],corner_node_id[4]);
2434 edge_node_pair[3]=std::make_pair(corner_node_id[1],corner_node_id[3]);
2437 edge_node_pair[4]=std::make_pair(corner_node_id[1],corner_node_id[5]);
2440 edge_node_pair[5]=std::make_pair(corner_node_id[2],corner_node_id[3]);
2443 edge_node_pair[6]=std::make_pair(corner_node_id[2],corner_node_id[6]);
2446 edge_node_pair[7]=std::make_pair(corner_node_id[3],corner_node_id[7]);
2449 edge_node_pair[8]=std::make_pair(corner_node_id[4],corner_node_id[5]);
2452 edge_node_pair[9]=std::make_pair(corner_node_id[4],corner_node_id[6]);
2455 edge_node_pair[10]=std::make_pair(corner_node_id[5],corner_node_id[7]);
2458 edge_node_pair[11]=std::make_pair(corner_node_id[6],corner_node_id[7]);
2463 Node* first_node_pt=0;
2466 Node* second_node_pt=0;
2479 unsigned n_element=bulk_mesh_pt->
nelement();
2488 for (
unsigned i=0;
i<n_element;
i++)
2494 for (
unsigned j=0;j<n_edge;j++)
2497 first_node_pt=el_pt->
node_pt(edge_node_pair[j].first);
2500 second_node_pt=el_pt->
node_pt(edge_node_pair[j].second);
2503 for (
unsigned n=0;n<3;n++)
2506 first_node_x[n]=first_node_pt->
x(n);
2510 for (
unsigned n=0;n<3;n++)
2513 second_node_x[n]=second_node_pt->
x(n);
2520 for (
unsigned n=0;n<3;n++)
2523 test_h+=pow(second_node_x[n]-first_node_x[n],2.0);
2527 test_h=sqrt(test_h);
2542 template<
unsigned DIM>
2546 double t_m_start=0.0;
2549 if (!Suppress_all_output)
2552 oomph_info <<
"Starting the setup of all smoothers.\n" << std::endl;
2559 for (
unsigned i=0;
i<Nlevel-1;
i++)
2564 if (0==Pre_smoother_factory_function_pt)
2570 if (Wavenumber*Max_edge_width[
i]<0.5)
2577 Pre_smoothers_storage_pt[
i]=damped_jacobi_pt;
2588 Pre_smoothers_storage_pt[
i]=gmres_pt;
2596 Pre_smoothers_storage_pt[
i]=
2597 (*Pre_smoother_factory_function_pt)();
2603 if (0==Post_smoother_factory_function_pt)
2609 if (Wavenumber*Max_edge_width[
i]<0.5)
2616 Post_smoothers_storage_pt[
i]=damped_jacobi_pt;
2627 Post_smoothers_storage_pt[
i]=gmres_pt;
2635 Post_smoothers_storage_pt[
i]=
2636 (*Post_smoother_factory_function_pt)();
2645 for (
unsigned i=0;
i<Nlevel-1;
i++)
2648 Pre_smoothers_storage_pt[
i]->
tolerance()=1.0e-16;
2651 Post_smoothers_storage_pt[
i]->tolerance()=1.0e-16;
2656 for (
unsigned i=0;
i<Nlevel-1;
i++)
2659 Pre_smoothers_storage_pt[
i]->max_iter()=Npre_smooth;
2662 Post_smoothers_storage_pt[
i]->max_iter()=Npost_smooth;
2666 for (
unsigned i=0;
i<Nlevel-1;
i++)
2670 Pre_smoothers_storage_pt[
i]->
2671 complex_smoother_setup(Mg_matrices_storage_pt[
i]);
2675 Post_smoothers_storage_pt[
i]->
2676 complex_smoother_setup(Mg_matrices_storage_pt[i]);
2680 for (
unsigned i=0;
i<Nlevel-1;
i++)
2685 unsigned n_dof=X_mg_vectors_storage[
i][0].nrow();
2693 #ifdef OOMPH_HAS_MPI 2695 std::string warning_message=
"Setup of pre- and post-smoother distribution ";
2696 warning_message+=
"has not been tested with MPI.";
2703 OOMPH_CURRENT_FUNCTION,
2704 OOMPH_EXCEPTION_LOCATION);
2710 Pre_smoothers_storage_pt[
i]->build_distribution(dist);
2713 Post_smoothers_storage_pt[
i]->build_distribution(dist);
2722 disable_smoother_and_superlu_doc_time();
2726 if (!Suppress_all_output)
2730 double total_setup_time=double(t_m_end-t_m_start);
2731 oomph_info <<
"CPU time for setup of smoothers on all levels [sec]: " 2732 << total_setup_time << std::endl;
2736 <<
"Smoother Setup Complete" 2737 <<
"=================" << std::endl;
2745 template<
unsigned DIM>
2762 std::ostringstream error_message_stream;
2763 error_message_stream <<
"DIM should be 2 or 3 not " 2764 << DIM << std::endl;
2766 OOMPH_CURRENT_FUNCTION,
2767 OOMPH_EXCEPTION_LOCATION);
2776 if (Mg_hierarchy_pt[0]->
mesh_pt(0)!=Mg_hierarchy_pt[0]->mg_bulk_mesh_pt())
2779 std::ostringstream error_message_stream;
2782 error_message_stream <<
"MG solver requires the first submesh be the " 2783 <<
"refineable bulk mesh provided by the user." 2788 OOMPH_CURRENT_FUNCTION,
2789 OOMPH_EXCEPTION_LOCATION);
2805 (Mg_problem_pt->mesh_pt()->element_pt(0))->nnode();
2814 for (
unsigned level=0;level<Nlevel-1;level++)
2817 unsigned fine_level=level;
2820 unsigned coarse_level=level+1;
2824 Mesh* ref_fine_mesh_pt=Mg_hierarchy_pt[fine_level]->mesh_pt();
2828 Mesh* ref_coarse_mesh_pt=Mg_hierarchy_pt[coarse_level]->mesh_pt();
2833 unsigned fine_n_element=ref_fine_mesh_pt->
nelement();
2836 unsigned n_bulk_mesh_element=
2837 Mg_hierarchy_pt[fine_level]->mg_bulk_mesh_pt()->nelement();
2844 if (fine_n_element>n_bulk_mesh_element)
2847 coarse_mesh_from_obj_pt=
2852 unsigned n_fine_dof=Mg_hierarchy_pt[fine_level]->ndof();
2855 unsigned n_coarse_dof=Mg_hierarchy_pt[coarse_level]->ndof();
2863 unsigned n_row=n_fine_dof/2.0;
2866 unsigned n_col=n_coarse_dof/2.0;
2875 std::map<RefineableQElement<DIM>*,
2882 unsigned e_coarse=0;
2890 while (e_fine<n_bulk_mesh_element)
2900 if (e_coarse>ref_coarse_mesh_pt->
nelement()-1)
2903 std::ostringstream error_message_stream;
2906 error_message_stream <<
"The coarse level mesh has " 2908 <<
" elements but the coarse\nelement loop " 2909 <<
"is looking at the " 2910 << e_coarse <<
"-th element!" << std::endl;
2914 OOMPH_CURRENT_FUNCTION,
2915 OOMPH_EXCEPTION_LOCATION);
2926 if (el_fine_pt->tree_pt()->level()>el_coarse_pt->tree_pt()->level())
2933 for (
unsigned i=0;
i<n_sons;
i++)
2936 coarse_mesh_reference_element_pt[
2947 else if (el_fine_pt->tree_pt()->level()==el_coarse_pt->tree_pt()->level())
2951 coarse_mesh_reference_element_pt[
2972 std::ostringstream error_message_stream;
2975 error_message_stream <<
"Element unrefined between levels! Can't " 2976 <<
"handle this case yet..." << std::endl;
2980 OOMPH_CURRENT_FUNCTION,
2981 OOMPH_EXCEPTION_LOCATION);
2989 std::vector<bool> contribution_made(n_row,
false);
3014 for (
unsigned k=0;k<fine_n_element;k++)
3036 if (k<n_bulk_mesh_element)
3040 el_coarse_pt=coarse_mesh_reference_element_pt[el_fine_pt];
3044 if (el_fine_pt->tree_pt()->level()!=el_coarse_pt->tree_pt()->level())
3047 son_type=el_fine_pt->tree_pt()->son_type();
3057 for(
unsigned i=0;
i<nnod_element;
i++)
3061 int ii=el_fine_pt->node_pt(
i)->eqn_number(0);
3071 if(contribution_made[ii/2]==
false)
3079 row_start[index]=value.size();
3095 if (k>=n_bulk_mesh_element)
3099 el_fine_pt->node_pt(
i)->position(fine_node_position);
3108 coarse_mesh_from_obj_pt->
locate_zeta(fine_node_position,el_pt,s);
3116 el_fine_pt->local_coordinate_of_node(
i,s);
3121 level_up_local_coord_of_node(son_type,s);
3125 Shape psi(el_coarse_pt->nnode());
3128 el_coarse_pt->shape(s,psi);
3131 std::map<unsigned,double> contribution;
3135 unsigned nnod_coarse=el_coarse_pt->nnode();
3138 for (
unsigned j=0;j<nnod_coarse;j++)
3143 int jj=el_coarse_pt->node_pt(j)->eqn_number(0);
3150 if (el_coarse_pt->node_pt(j)->is_hanging())
3154 HangInfo* hang_info_pt=el_coarse_pt->node_pt(j)->hanging_pt();
3155 unsigned nmaster=hang_info_pt->
nmaster();
3158 for (
unsigned i_master=0;i_master<nmaster;i_master++)
3174 contribution[master_jj/2]+=
3187 contribution[jj/2]+=psi(j);
3193 for (std::map<unsigned,double>::iterator it=contribution.begin();
3194 it!=contribution.end(); ++it)
3199 column_index.push_back(it->first);
3203 value.push_back(it->second);
3214 contribution_made[ii/2]=
true;
3221 row_start[n_row]=value.size();
3226 interpolation_matrix_set(level,
3238 template<
unsigned DIM>
3244 if ((DIM!=2)&&(DIM!=3))
3246 std::ostringstream error_message_stream;
3247 error_message_stream <<
"DIM should be 2 or 3 not " 3248 << DIM << std::endl;
3250 OOMPH_CURRENT_FUNCTION,
3251 OOMPH_EXCEPTION_LOCATION);
3261 for (
unsigned level=0;level<Nlevel-1;level++)
3264 unsigned coarse_level=level+1;
3265 unsigned fine_level=level;
3269 Mesh* ref_fine_mesh_pt=Mg_hierarchy_pt[fine_level]->mg_bulk_mesh_pt();
3278 unsigned coarse_n_unknowns=Mg_hierarchy_pt[coarse_level]->ndof();
3279 unsigned fine_n_unknowns=Mg_hierarchy_pt[fine_level]->ndof();
3299 unsigned n_node_fine_mesh=ref_fine_mesh_pt->
nnode();
3302 for (
unsigned i_fine_node=0;i_fine_node<n_node_fine_mesh;i_fine_node++)
3305 Node* fine_node_pt=ref_fine_mesh_pt->
node_pt(i_fine_node);
3315 row_start[i_fine]=value.size();
3318 fine_node_pt->
position(fine_node_position);
3325 coarse_mesh_from_obj_pt->
locate_zeta(fine_node_position,el_pt,s);
3331 unsigned n_node=el_coarse_pt->
nnode();
3337 el_coarse_pt->
shape(s,psi);
3340 std::map<unsigned,double> contribution;
3345 for(
unsigned j_node=0;j_node<n_node;j_node++)
3348 Node* coarse_node_pt=el_coarse_pt->
node_pt(j_node);
3364 unsigned nmaster=hang_info_pt->
nmaster();
3367 for (
unsigned i_master=0;i_master<nmaster;i_master++)
3383 contribution[master_jj]+=
3395 if (psi(j_node)!=0.0)
3397 contribution[j_coarse]+=psi(j_node);
3403 for (std::map<unsigned,double>::iterator it=contribution.begin();
3404 it!=contribution.end(); ++it)
3408 value.push_back(it->second);
3409 column_index.push_back(it->first);
3416 row_start[fine_n_unknowns]=value.size();
3421 interpolation_matrix_set(level,
3450 s[0]=(s[0]+1.0)/2.0;
3451 s[1]=(s[1]+1.0)/2.0;
3452 s[2]=(s[2]+1.0)/2.0;
3517 s[0]=(s[0]+1.0)/2.0;
3518 s[1]=(s[1]+1.0)/2.0;
3557 template<
unsigned DIM>
3562 if (!(level<Nlevel-1))
3565 throw OomphLibError(
"Input level exceeds the possible parameter choice.",
3566 OOMPH_CURRENT_FUNCTION,
3567 OOMPH_EXCEPTION_LOCATION);
3573 Restriction_matrices_storage_pt[level]->
3574 multiply(Residual_mg_vectors_storage[level][0],
3575 Rhs_mg_vectors_storage[level+1][0]);
3579 Restriction_matrices_storage_pt[level]->
3580 multiply(Residual_mg_vectors_storage[level][1],
3581 Rhs_mg_vectors_storage[level+1][1]);
3589 template<
unsigned DIM>
3598 throw OomphLibError(
"Input level exceeds the possible parameter choice.",
3599 OOMPH_CURRENT_FUNCTION,
3600 OOMPH_EXCEPTION_LOCATION);
3605 DoubleVector temp_soln_r(X_mg_vectors_storage[level-1][0].distribution_pt());
3608 DoubleVector temp_soln_c(X_mg_vectors_storage[level-1][1].distribution_pt());
3611 Interpolation_matrices_storage_pt[level-1]->
3612 multiply(X_mg_vectors_storage[level][0],temp_soln_r);
3615 Interpolation_matrices_storage_pt[level-1]->
3616 multiply(X_mg_vectors_storage[level][1],temp_soln_c);
3619 X_mg_vectors_storage[level-1][0]+=temp_soln_r;
3622 X_mg_vectors_storage[level-1][1]+=temp_soln_c;
3630 template<
unsigned DIM>
3634 double t_mg_start=0.0;
3635 if (!Suppress_v_cycle_output)
3642 unsigned finest_level=0;
3648 double normalised_residual_norm=residual_norm(finest_level);
3649 if (!Suppress_v_cycle_output)
3651 oomph_info <<
"\nResidual on finest level for V-cycle: " 3652 << normalised_residual_norm << std::endl;
3659 while((normalised_residual_norm>Tolerance) &&
3660 (V_cycle_counter!=Nvcycle))
3663 if (!Suppress_v_cycle_output)
3666 oomph_info <<
"\nStarting V-cycle: " << V_cycle_counter << std::endl;
3672 for (
unsigned i=0;
i<Nlevel-1;
i++)
3680 X_mg_vectors_storage[
i][0].initialise(0.0);
3683 X_mg_vectors_storage[
i][1].initialise(0.0);
3686 Residual_mg_vectors_storage[
i][0].initialise(0.0);
3689 Residual_mg_vectors_storage[
i][1].initialise(0.0);
3698 restrict_residual(
i);
3711 for (
unsigned i=Nlevel-1;
i>0;
i--)
3715 interpolate_and_correct(
i);
3727 normalised_residual_norm=residual_norm(finest_level);
3730 if (!Suppress_v_cycle_output)
3732 oomph_info <<
"Residual on finest level of V-cycle: " 3733 << normalised_residual_norm << std::endl;
3738 result=X_mg_vectors_storage[finest_level];
3741 if (!Suppress_v_cycle_output)
3747 if (!Suppress_all_output)
3750 if (normalised_residual_norm<Tolerance)
3752 Has_been_solved=
true;
3757 if (!Suppress_v_cycle_output)
3761 double total_G_setup_time=double(t_mg_end-t_mg_start);
3762 oomph_info <<
"CPU time for MG solver [sec]: " 3763 << total_G_setup_time << std::endl;
double Alpha_shift
Temporary version of the shift – to run bash scripts.
void setup()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level...
int * column_index()
Access to C-style column index array.
unsigned long nnz() const
Return the number of nonzero entries (the local nnz)
virtual void actions_before_adapt()
Actions that are to be performed before a mesh adaptation. These might include removing any additiona...
void level_up_local_coord_of_node(const int &son_type, Vector< double > &s)
Given the son_type of an element and a local node number j in that element with nnode_1d nodes per co...
void setup_mg_hierarchy()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level...
double & tolerance()
Access to convergence tolerance.
Nullstream oomph_nullstream
Single (global) instantiation of the Nullstream.
void enable_doc_time()
Enable time documentation.
The GMRES method rewritten for complex matrices.
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
void pre_smooth(const unsigned &level)
Pre-smoother: Perform 'max_iter' smoothing steps on the linear system Ax=b with current RHS vector...
void setup_smoothers()
Function to set up all of the smoothers once the system matrices have been set up.
unsigned Nvcycle
Maximum number of V-cycles.
void interpolation_matrix_set(const unsigned &level, Vector< double > &value, Vector< int > &col_index, Vector< int > &row_st, unsigned &ncol, unsigned &nrow)
Builds a CRDoubleMatrix that is used to interpolate the residual between levels. The transpose can be...
HelmholtzMGPreconditioner(HelmholtzMGProblem *mg_problem_pt)
Constructor: Set up default values for number of V-cycles and pre- and post-smoothing steps...
Vector< Vector< DoubleVector > > X_mg_vectors_storage
Vector of vectors to store the solution vectors (X_mg) in two parts; the real and imaginary...
void setup_transfer_matrices()
Setup the transfer matrices on each level.
virtual TreeBasedRefineableMeshBase * mg_bulk_mesh_pt()=0
Function to get a pointer to the mesh we will be working with. If there are flux elements present in ...
PreSmootherFactoryFctPt Pre_smoother_factory_function_pt
Function to create pre-smoothers.
virtual void actions_after_adapt()
Actions that are to be performed after a mesh adaptation.
bool Has_been_solved
Boolean variable to indicate whether or not the problem was successfully solved.
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
double Wavenumber
The value of the wavenumber, k.
unsigned Npost_smooth
Number of post-smoothing steps.
bool Doc_time
Indicates whether or not time documentation should be used.
A general Finite Element class.
double & tolerance()
Access function for the variable Tolerance (lvalue)
Vector< Vector< CRDoubleMatrix * > > Mg_matrices_storage_pt
Vector of vectors to store the system matrices. The i-th entry in this vector contains a vector of le...
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
void multiply(const CRDoubleMatrix *matrix, const DoubleVector &x, DoubleVector &soln)
Function to perform a matrix-vector multiplication on a oomph-lib matrix and vector using Trilinos fu...
void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s, const bool &use_coordinate_as_initial_guess=false)
Find the sub geometric object and local coordinate therein that corresponds to the intrinsic coordina...
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
unsigned nmaster() const
Return the number of master nodes.
bool Suppress_all_output
If this is set to true then all output from the solver is suppressed.
static OomphCommunicator * communicator_pt()
access to the global oomph-lib communicator
Vector< CRDoubleMatrix * > Restriction_matrices_storage_pt
Vector to store the restriction matrices.
Mesh *& mesh_pt()
Return a pointer to the global mesh.
bool is_hanging() const
Test whether the node is geometrically hanging.
double *& alpha_pt()
Pointer to Alpha, wavenumber complex shift.
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
void interpolate_and_correct(const unsigned &level)
Interpolate solution at current level onto next finer mesh and correct the solution x at that level...
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
double * value()
Access to C-style value array.
void setup_mg_structures()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level...
void block_preconditioner_self_test()
Function to ensure the block form of the Jacobian matches the form described, i.e. we should have: |--—|---—| | A_r | -A_c | A = |--—|---—|. | A_c | A_r | |--—|---—|.
Vector< HelmholtzSmoother * > Post_smoothers_storage_pt
Vector to store the post-smoothers.
double residual_norm(const unsigned &level)
Return norm of residual r=b-Ax and the residual vector itself on the level-th level.
unsigned long nelement() const
Return number of elements in the mesh.
void mg_solve(Vector< DoubleVector > &result)
Do the actual solve – this is called through the pure virtual solve function in the LinearSolver bas...
void set_restriction_matrices_as_interpolation_transposes()
Builds a CRDoubleMatrix on each level that is used to restrict the residual between levels...
void disable_smoother_and_superlu_doc_time()
Suppress the output of both smoothers and SuperLU.
unsigned iterations() const
Number of iterations.
Vector< HelmholtzMGProblem * > Mg_hierarchy_pt
Vector containing pointers to problems in hierarchy.
DoubleVector Coarsest_rhs_mg
Assuming we're solving the system Ax=b, this vector will contain the expanded solution vector on the ...
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
unsigned long ncol() const
Return the number of columns of the matrix.
void setup_coarsest_level_structures()
Function to create the fully expanded system matrix on the coarsest level.
void disable_v_cycle_output()
Disable all output from mg_solve apart from the number of V-cycles used to solve the problem...
virtual HelmholtzMGProblem * make_new_problem()=0
This function needs to be implemented in the derived problem: Returns a pointer to a new object of th...
void enable_v_cycle_output()
Enable the output of the V-cycle timings and other output.
void disable_doc_time()
Disable time documentation.
void maximum_edge_width(const unsigned &level, double &h)
Estimate the value of the parameter h on the level-th problem in the hierarchy.
std::ostream *& stream_pt()
Access function for the stream pointer.
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Vector< Vector< DoubleVector > > Rhs_mg_vectors_storage
Vector of vectors to store the RHS vectors. This uses the same format as the X_mg_vectors_storage vec...
Base class for tree-based refineable meshes.
void setup_interpolation_matrices()
Setup the interpolation matrix on each level.
HelmholtzMGProblem class; subclass of Problem.
void post_smooth(const unsigned &level)
Post-smoother: Perform max_iter smoothing steps on the linear system Ax=b with current RHS vector...
void interpolation_matrix_set(const unsigned &level, double *value, int *col_index, int *row_st, unsigned &ncol, unsigned &nnz)
Builds a CRDoubleMatrix that is used to interpolate the residual between levels. The transpose can be...
unsigned & npre_smooth()
Return the number of pre-smoothing iterations (lvalue)
void position(Vector< double > &pos) const
Compute Vector of nodal positions either directly or via hanging node representation.
DoubleVector Coarsest_x_mg
Assuming we're solving the system Ax=b, this vector will contain the expanded solution vector on the ...
Vector< HelmholtzSmoother * > Pre_smoothers_storage_pt
Vector to store the pre-smoothers.
PostSmootherFactoryFctPt Post_smoother_factory_function_pt
Function to create post-smoothers.
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
void setup_interpolation_matrices_unstructured()
Setup the interpolation matrix on each level (used for unstructured meshes)
double timer()
returns the time in seconds after some point in past
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
double k_squared() const
Get the square of wavenumber.
Class that contains data for hanging nodes.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
HelmholtzMGProblem()
Constructor. Initialise pointers to coarser and finer levels.
Vector< Vector< DoubleVector > > Residual_mg_vectors_storage
Vector to vectors to store the residual vectors. This uses the same format as the X_mg_vectors_storag...
void disable_output()
Suppress anything that can be suppressed, i.e. any timings. Things like mesh adaptation can not howev...
unsigned long nnode() const
Return number of nodes in the mesh.
void restrict_residual(const unsigned &level)
Restrict residual (computed on level-th MG level) to the next coarser mesh and stick it into the coar...
void full_setup()
Do a full setup (assumes everything will be setup around the HelmholtzMGProblem pointer given in the ...
HelmholtzMGProblem * Mg_problem_pt
Pointer to the MG problem (deep copy)
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
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...
static const int OMEGA
Default value for an unassigned neighbour.
void enable_output()
Enable the output from anything that could have been suppressed.
double Tolerance
The tolerance of the multigrid preconditioner.
void set_pre_smoother_factory_function(PreSmootherFactoryFctPt pre_smoother_fn)
Access function to set the pre-smoother creation function.
double & alpha_shift()
Function to change the value of the shift.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
unsigned V_cycle_counter
Pointer to counter for V-cycles.
bool Has_been_setup
Boolean variable to indicate whether or not the solver has been setup.
virtual void setup()=0
Setup the preconditioner. Pure virtual generic interface function.
unsigned long assign_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Assign all equation numbers for problem: Deals with global data (= data that isn't attached to any el...
Class for dense matrices, storing all the values of the matrix as a pointer to a pointer with assorte...
void concatenate(const Vector< DoubleVector *> &in_vector_pt, DoubleVector &out_vector)
Concatenate DoubleVectors. Takes a Vector of DoubleVectors. If the out vector is built, we will not build a new distribution. Otherwise we build a uniform distribution.
bool Suppress_v_cycle_output
Indicates whether or not the V-cycle output should be suppressed.
unsigned Nlevel
The number of levels in the multigrid heirachy.
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*)
unsigned long nrow() const
Return the number of rows of the matrix.
std::ostream * Stream_pt
Pointer to the output stream – defaults to std::cout.
Vector< CRDoubleMatrix * > Interpolation_matrices_storage_pt
Vector to store the interpolation matrices.
unsigned & npost_smooth()
Return the number of post-smoothing iterations (lvalue)
CRDoubleMatrix * Coarsest_matrix_mg_pt
Stores the system matrix on the coarest level in the fully expanded format: |--—|---—| | A_r | -A_c...
int * row_start()
Access to C-style row_start array.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Function applies MG to the vector r for a full solve.
Vector< double > Max_edge_width
Vector to storage the maximum edge width of each mesh. We only need the maximum edge width on levels ...
~HelmholtzMGPreconditioner()
Delete any dynamically allocated data.
unsigned nnode() const
Return the number of nodes.
A class for compressed row matrices. This is a distributable object.
void split(const DoubleVector &in_vector, Vector< DoubleVector *> &out_vector_pt)
Split a DoubleVector into the out DoubleVectors. Let vec_A be the in Vector, and let vec_B and vec_C ...
void set_post_smoother_factory_function(PostSmootherFactoryFctPt post_smoother_fn)
Access function to set the post-smoother creation function.
virtual void shape(const Vector< double > &s, Shape &psi) const =0
Calculate the geometric shape functions at local coordinate s. This function must be overloaded for e...
virtual ~HelmholtzMGProblem()
Destructor (empty)
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...
void clean_up_memory()
Clean up anything that needs to be cleaned up.
unsigned Npre_smooth
Number of pre-smoothing steps.
void direct_solve()
Call the direct solver (SuperLU) to solve the problem exactly.