27 #ifndef OOMPH_HELMHOLTZ_GEOMETRIC_MULTIGRID_HEADER
28 #define OOMPH_HELMHOLTZ_GEOMETRIC_MULTIGRID_HEADER
81 template<
unsigned DIM>
148 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
164 for (
unsigned j = 0; j < 2; j++)
182 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
290 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
356 for (
unsigned j = 0; j < 2; j++)
408 ncol, nnz, value, col_index, row_st);
433 "Setup of interpolation matrix distribution ";
434 warning_message +=
"has not been tested with MPI.";
441 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
448 dist_pt, ncol, value, col_index, row_st);
463 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
525 <<
"Multigrid Preconditioner Solve Complete"
526 <<
"=========" << std::endl;
733 template<
unsigned DIM>
738 unsigned n_rows = X_mg_vectors_storage[level][0].nrow();
744 if (residual.size() != 2)
747 throw OomphLibError(
"This residual vector must have length 2. ",
748 OOMPH_CURRENT_FUNCTION,
749 OOMPH_EXCEPTION_LOCATION);
751 if (residual[0].nrow() != residual[1].nrow())
754 std::ostringstream error_message_stream;
757 error_message_stream <<
"Residual[0] has length: " << residual[0].nrow()
758 <<
"\nResidual[1] has length: " << residual[1].nrow()
759 <<
"\nThis method requires that the constituent "
760 <<
"DoubleVectors in residual have the same length. "
765 OOMPH_CURRENT_FUNCTION,
766 OOMPH_EXCEPTION_LOCATION);
771 for (
unsigned i = 0;
i < 2;
i++)
775 if (!residual[
i].distribution_built())
779 Mg_hierarchy_pt[level]->communicator_pt(), n_rows,
false);
782 residual[
i].build(&dist, 0.0);
791 if (residual[
i].distributed())
794 "This method can only assemble a non-distributed residuals vector ",
795 OOMPH_CURRENT_FUNCTION,
796 OOMPH_EXCEPTION_LOCATION);
808 Mg_matrices_storage_pt[level][0]->distribution_pt();
832 Mg_matrices_storage_pt[level][0]->multiply(X_mg_vectors_storage[level][0],
836 Mg_matrices_storage_pt[level][0]->multiply(X_mg_vectors_storage[level][1],
840 Mg_matrices_storage_pt[level][1]->multiply(X_mg_vectors_storage[level][0],
844 Mg_matrices_storage_pt[level][1]->multiply(X_mg_vectors_storage[level][1],
848 residual[0] = Rhs_mg_vectors_storage[level][0];
849 residual[0] -= temp_vec_rr;
850 residual[0] += temp_vec_cc;
853 residual[1] = Rhs_mg_vectors_storage[level][1];
854 residual[1] -= temp_vec_rc;
855 residual[1] -= temp_vec_cr;
858 double norm_r = residual[0].norm();
861 double norm_c = residual[1].norm();
865 return sqrt(norm_r * norm_r + norm_c * norm_c);
872 template<
unsigned DIM>
876 clock_t t_bl_start = clock();
879 if (Mg_hierarchy_pt[0]->mesh_pt() == 0)
881 std::stringstream err;
882 err <<
"Please set pointer to mesh using set_bulk_helmholtz_mesh(...).\n";
884 err.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
895 bool allow_different_element_types_in_mesh =
true;
897 0, Mg_problem_pt->mesh_pt(), allow_different_element_types_in_mesh);
901 unsigned n_dof_types = this->ndof_types();
902 if (n_dof_types != 2)
904 std::stringstream tmp;
905 tmp <<
"This preconditioner only works for problems with 2 dof types\n"
906 <<
"Yours has " << n_dof_types;
908 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
916 unsigned nblock_types = this->nblock_types();
918 if (nblock_types != 2)
920 std::stringstream tmp;
921 tmp <<
"There are supposed to be two block types.\n"
922 <<
"Yours has " << nblock_types;
924 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
933 for (
unsigned i = 0;
i < nblock_types;
i++)
935 for (
unsigned j = 0; j < nblock_types; j++)
939 this->get_block(
i, j, *block_pt(
i, j));
946 unsigned nnz1 = block_pt(0, 0)->nnz();
947 unsigned nnz2 = block_pt(1, 1)->nnz();
950 std::stringstream tmp;
951 tmp <<
"nnz of diagonal blocks doesn't match: " << nnz1
952 <<
" != " << nnz2 << std::endl;
954 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
956 unsigned nrow1 = block_pt(0, 0)->
nrow();
957 unsigned nrow2 = block_pt(1, 1)->
nrow();
960 std::stringstream tmp;
961 tmp <<
"nrow of diagonal blocks doesn't match: " << nrow1
962 <<
" != " << nrow2 << std::endl;
964 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
969 double tol = 1.0e-15;
970 std::stringstream tmp;
973 for (
unsigned i = 0;
i < nrow1 + 1;
i++)
975 if (block_pt(0, 0)->row_start()[
i] != block_pt(1, 1)->row_start()[
i])
978 tmp <<
"Row starts of diag matrices don't match for row " <<
i
979 <<
" : " << block_pt(0, 0)->row_start()[
i] <<
" "
980 << block_pt(1, 1)->row_start()[
i] <<
" " << std::endl;
985 for (
unsigned i = 0;
i < nnz1;
i++)
987 if (block_pt(0, 0)->column_index()[
i] !=
988 block_pt(1, 1)->column_index()[
i])
991 tmp <<
"Column of diag matrices indices don't match for entry " <<
i
992 <<
" : " << block_pt(0, 0)->column_index()[
i] <<
" "
993 << block_pt(1, 1)->column_index()[
i] <<
" " << std::endl;
996 if (fabs(block_pt(0, 0)->value()[
i] - block_pt(1, 1)->value()[
i]) > tol)
999 tmp <<
"Values of diag matrices don't match for entry " <<
i <<
" : "
1000 << block_pt(0, 0)->value()[
i] <<
" " << block_pt(1, 1)->value()[
i]
1001 <<
" " << std::endl;
1007 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1014 unsigned nnz1 = block_pt(0, 1)->nnz();
1015 unsigned nnz2 = block_pt(1, 0)->nnz();
1018 std::stringstream tmp;
1019 tmp <<
"nnz of diagonal blocks doesn't match: " << nnz1
1020 <<
" != " << nnz2 << std::endl;
1022 tmp.str(), OOMPH_CURRENT_FUNCTION, 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: " << nrow1
1030 <<
" != " << nrow2 << std::endl;
1032 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1038 double tol = 1.0e-15;
1039 std::stringstream tmp;
1042 for (
unsigned i = 0;
i < nrow1 + 1;
i++)
1044 if (block_pt(0, 1)->row_start()[
i] != block_pt(1, 0)->row_start()[
i])
1047 tmp <<
"Row starts of off-diag matrices don't match for row " <<
i
1048 <<
" : " << block_pt(0, 1)->row_start()[
i] <<
" "
1049 << block_pt(1, 0)->row_start()[
i] <<
" " << std::endl;
1054 for (
unsigned i = 0;
i < nnz1;
i++)
1056 if (block_pt(0, 1)->column_index()[
i] !=
1057 block_pt(1, 0)->column_index()[
i])
1060 tmp <<
"Column indices of off-diag matrices don't match for entry "
1061 <<
i <<
" : " << block_pt(0, 1)->column_index()[
i] <<
" "
1062 << block_pt(1, 0)->column_index()[
i] <<
" " << std::endl;
1065 if (fabs(block_pt(0, 1)->value()[
i] + block_pt(1, 0)->value()[
i]) > tol)
1068 tmp <<
"Values of off-diag matrices aren't negatives of "
1069 <<
"each other for entry " <<
i <<
" : "
1070 << block_pt(0, 1)->value()[
i] <<
" " << block_pt(1, 0)->value()[
i]
1071 <<
" " << std::endl;
1077 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1082 for (
unsigned i = 0;
i < nblock_types;
i++)
1084 for (
unsigned j = 0; j < nblock_types; j++)
1086 delete block_pt(
i, j);
1092 clock_t t_bl_end = clock();
1093 double total_setup_time = double(t_bl_end - t_bl_start) / CLOCKS_PER_SEC;
1094 oomph_info <<
"CPU time for block preconditioner self-test [sec]: "
1095 << total_setup_time <<
"\n"
1102 template<
unsigned DIM>
1105 #ifdef OOMPH_HAS_MPI
1111 OomphLibWarning(
"Can't guarantee the MG solver will work in parallel!",
1112 OOMPH_CURRENT_FUNCTION,
1113 OOMPH_EXCEPTION_LOCATION);
1118 double t_fs_start = 0.0;
1121 if (!Suppress_all_output)
1128 <<
"\n========Starting Setup of Multigrid Preconditioner========"
1133 <<
"\nStarting the full setup of the Helmholtz multigrid solver."
1140 if (
dynamic_cast<FiniteElement*
>(Mg_problem_pt->mesh_pt()->element_pt(0))
1144 std::string err_strng =
"The dimension of the elements used in the mesh ";
1145 err_strng +=
"does not match the dimension of the solver.";
1149 err_strng, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1154 if (Mg_problem_pt->mg_bulk_mesh_pt() != 0)
1157 unsigned n_elements = Mg_problem_pt->mg_bulk_mesh_pt()->nelement();
1161 for (
unsigned el_counter = 0; el_counter < n_elements; el_counter++)
1165 Mg_problem_pt->mg_bulk_mesh_pt()->element_pt(el_counter));
1172 std::ostringstream error_message_stream;
1175 error_message_stream <<
"Element in bulk mesh could not be upcast to "
1176 <<
"a refineable element." << std::endl;
1180 OOMPH_CURRENT_FUNCTION,
1181 OOMPH_EXCEPTION_LOCATION);
1189 std::ostringstream error_message_stream;
1192 error_message_stream
1193 <<
"The provided bulk mesh pointer is a null pointer. " << std::endl;
1197 OOMPH_CURRENT_FUNCTION,
1198 OOMPH_EXCEPTION_LOCATION);
1207 Mg_hierarchy_pt.resize(1, 0);
1210 Mg_hierarchy_pt[0] = Mg_problem_pt;
1213 setup_mg_hierarchy();
1216 setup_transfer_matrices();
1220 setup_mg_structures();
1226 for (
unsigned i = 1;
i < Nlevel;
i++)
1229 delete Mg_hierarchy_pt[
i];
1232 Mg_hierarchy_pt[
i] = 0;
1236 Has_been_setup =
true;
1239 if (!Suppress_all_output)
1243 double full_setup_time = t_fs_end - t_fs_start;
1246 oomph_info <<
"\nCPU time for full setup [sec]: " << full_setup_time
1251 <<
"Multigrid Full Setup Complete"
1252 <<
"==============\n"
1262 template<
unsigned DIM>
1266 double t_m_start = 0.0;
1269 if (!Suppress_all_output)
1273 <<
"Creating Multigrid Hierarchy"
1274 <<
"===============\n"
1284 bool managed_to_create_unrefined_copy =
true;
1292 while (managed_to_create_unrefined_copy)
1305 managed_to_create_unrefined_copy =
1308 Mg_hierarchy_pt[level]->mg_bulk_mesh_pt());
1312 if (managed_to_create_unrefined_copy)
1319 if (!Suppress_all_output)
1323 <<
" has been created:" << std::endl;
1336 Mg_hierarchy_pt.push_back(new_problem_pt);
1342 delete new_problem_pt;
1348 Nlevel = Mg_hierarchy_pt.size();
1352 if (!Suppress_all_output)
1356 <<
"Number of levels: " << Nlevel << std::endl;
1367 Mg_matrices_storage_pt.resize(Nlevel);
1370 X_mg_vectors_storage.resize(Nlevel);
1373 Rhs_mg_vectors_storage.resize(Nlevel);
1376 Residual_mg_vectors_storage.resize(Nlevel);
1380 Max_edge_width.resize(Nlevel - 1, 0.0);
1384 Pre_smoothers_storage_pt.resize(Nlevel - 1, 0);
1388 Post_smoothers_storage_pt.resize(Nlevel - 1, 0);
1391 Interpolation_matrices_storage_pt.resize(Nlevel - 1, 0);
1394 Restriction_matrices_storage_pt.resize(Nlevel - 1, 0);
1397 if (!Suppress_all_output)
1401 double total_setup_time = double(t_m_end - t_m_start);
1403 <<
"\nCPU time for creation of hierarchy of MG problems [sec]: "
1404 << total_setup_time << std::endl;
1408 <<
"Hierarchy Creation Complete"
1409 <<
"================\n"
1421 template<
unsigned DIM>
1425 double t_r_start = 0.0;
1428 if (!Suppress_all_output)
1431 oomph_info <<
"Creating the transfer matrices." << std::endl;
1441 Mg_problem_pt->mg_bulk_mesh_pt()))
1443 setup_interpolation_matrices();
1449 setup_interpolation_matrices_unstructured();
1453 set_restriction_matrices_as_interpolation_transposes();
1456 if (!Suppress_all_output)
1460 double total_G_setup_time = double(t_r_end - t_r_start);
1461 oomph_info <<
"\nCPU time for transfer matrices setup [sec]: "
1462 << total_G_setup_time << std::endl;
1466 <<
"\n============Transfer Matrices Setup Complete=============="
1475 template<
unsigned DIM>
1479 double t_m_start = 0.0;
1482 if (!Suppress_all_output)
1496 Mg_problem_pt->mg_bulk_mesh_pt()->element_pt(0));
1501 Wavenumber = sqrt(pml_helmholtz_el_pt->
k_squared());
1505 pml_helmholtz_el_pt = 0;
1511 for (
unsigned i = 0;
i < Nlevel;
i++)
1514 if (!Suppress_all_output)
1517 oomph_info <<
"Setting up MG structures on level: " <<
i <<
"\n"
1522 unsigned n_dof_per_block = Mg_hierarchy_pt[
i]->ndof() / 2;
1526 Mg_hierarchy_pt[
i]->communicator_pt(), n_dof_per_block,
false);
1529 #ifdef OOMPH_HAS_MPI
1531 std::string warning_message =
"Setup of distribution has not been ";
1532 warning_message +=
"tested with MPI.";
1539 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1548 Mg_matrices_storage_pt[
i].resize(2, 0);
1551 for (
unsigned j = 0; j < 2; j++)
1558 Mg_matrices_storage_pt[
i][0]->
build(dist_pt);
1561 Mg_matrices_storage_pt[
i][1]->build(dist_pt);
1566 X_mg_vectors_storage[
i].resize(2);
1569 X_mg_vectors_storage[
i][0].build(dist_pt);
1572 X_mg_vectors_storage[
i][1].build(dist_pt);
1577 Rhs_mg_vectors_storage[
i].resize(2);
1580 Rhs_mg_vectors_storage[
i][0].build(dist_pt);
1583 Rhs_mg_vectors_storage[
i][1].build(dist_pt);
1588 Residual_mg_vectors_storage[
i].resize(2);
1591 Residual_mg_vectors_storage[
i][0].build(dist_pt);
1594 Residual_mg_vectors_storage[
i][1].build(dist_pt);
1609 double t_jac_start = 0.0;
1612 if (!Suppress_all_output)
1620 block_preconditioner_self_test();
1629 bool allow_different_element_types_in_mesh =
true;
1631 Mg_hierarchy_pt[0]->mesh_pt(),
1632 allow_different_element_types_in_mesh);
1636 unsigned n_dof_types = this->ndof_types();
1639 if (n_dof_types != 2)
1642 std::stringstream tmp;
1644 <<
"This preconditioner only works for problems with 2 dof types\n"
1645 <<
"Yours has " << n_dof_types;
1649 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1654 if (Alpha_shift != 0.0)
1662 double* alpha_shift_pt =
new double(Alpha_shift);
1665 unsigned n_element = Mg_hierarchy_pt[0]->mesh_pt()->nelement();
1672 Mg_hierarchy_pt[0]->mesh_pt()->element_pt(0));
1675 static double* default_physical_constant_value_pt = el_pt->
alpha_pt();
1678 for (
unsigned i_el = 0; i_el < n_element; i_el++)
1683 Mg_hierarchy_pt[0]->mesh_pt()->element_pt(i_el));
1687 el_pt->
alpha_pt() = alpha_shift_pt;
1712 Mg_hierarchy_pt[0]->get_jacobian(residuals, *shifted_jacobian_pt);
1715 this->set_matrix_pt(shifted_jacobian_pt);
1718 this->block_setup();
1721 unsigned nblock_types = this->nblock_types();
1725 if (nblock_types != 2)
1728 std::stringstream tmp;
1729 tmp <<
"There are supposed to be two block types.\nYours has "
1730 << nblock_types << std::endl;
1734 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1742 for (
unsigned i_row = 0; i_row < nblock_types; i_row++)
1749 i_row, j_col, *Mg_matrices_storage_pt[level][i_row]);
1754 delete shifted_jacobian_pt;
1759 this->set_matrix_pt(jacobian_pt);
1765 for (
unsigned i_el = 0; i_el < n_element; i_el++)
1770 Mg_hierarchy_pt[0]->mesh_pt()->element_pt(i_el));
1773 el_pt->
alpha_pt() = default_physical_constant_value_pt;
1778 delete alpha_shift_pt;
1789 this->block_setup();
1792 unsigned nblock_types = this->nblock_types();
1796 if (nblock_types != 2)
1798 std::stringstream tmp;
1799 tmp <<
"There are supposed to be two block types.\n"
1800 <<
"Yours has " << nblock_types;
1802 tmp.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1810 for (
unsigned i_row = 0; i_row < nblock_types; i_row++)
1817 i_row, j_col, *Mg_matrices_storage_pt[level][i_row]);
1821 if (!Suppress_all_output)
1825 double jacobian_setup_time = t_jac_end - t_jac_start;
1826 oomph_info <<
" - Time for setup of Jacobian block matrix [sec]: "
1827 << jacobian_setup_time <<
"\n"
1836 double t_gal_start = 0.0;
1839 if (!Suppress_all_output)
1861 Mg_matrices_storage_pt[
i - 1][0]->multiply(
1862 *Interpolation_matrices_storage_pt[
i - 1],
1863 *Mg_matrices_storage_pt[
i][0]);
1868 Restriction_matrices_storage_pt[
i - 1]->multiply(
1869 *Mg_matrices_storage_pt[
i][0], *Mg_matrices_storage_pt[
i][0]);
1875 Mg_matrices_storage_pt[
i - 1][1]->multiply(
1876 *Interpolation_matrices_storage_pt[
i - 1],
1877 *Mg_matrices_storage_pt[
i][1]);
1882 Restriction_matrices_storage_pt[
i - 1]->multiply(
1883 *Mg_matrices_storage_pt[
i][1], *Mg_matrices_storage_pt[
i][1]);
1886 if (!Suppress_all_output)
1892 double galerkin_matrix_calculation_time = t_gal_end - t_gal_start;
1895 oomph_info <<
" - Time for system block matrix formation using the "
1896 <<
"Galerkin approximation [sec]: "
1897 << galerkin_matrix_calculation_time <<
"\n"
1908 double t_para_start = 0.0;
1911 if (!Suppress_all_output)
1918 maximum_edge_width(
i, Max_edge_width[
i]);
1921 if (!Suppress_all_output)
1927 double parameter_calculation_time = t_para_end - t_para_start;
1930 oomph_info <<
" - Time for maximum edge width calculation [sec]: "
1931 << parameter_calculation_time <<
"\n"
1940 setup_coarsest_level_structures();
1943 if (!Suppress_all_output)
1947 double total_setup_time = double(t_m_end - t_m_start);
1948 oomph_info <<
"CPU time for setup of MG structures [sec]: "
1949 << total_setup_time << std::endl;
1953 <<
"Multigrid Structures Setup Complete"
1979 template<
unsigned DIM>
1990 CRDoubleMatrix* real_matrix_pt = Mg_matrices_storage_pt[Nlevel - 1][0];
1991 CRDoubleMatrix* imag_matrix_pt = Mg_matrices_storage_pt[Nlevel - 1][1];
1994 unsigned nnz_r = real_matrix_pt->
nnz();
1995 unsigned nnz_c = imag_matrix_pt->
nnz();
1998 unsigned n_rows_r = real_matrix_pt->
nrow();
2003 const double* value_r_pt = real_matrix_pt->
value();
2004 const int* row_start_r_pt = real_matrix_pt->
row_start();
2005 const int* column_index_r_pt = real_matrix_pt->
column_index();
2008 const double* value_c_pt = imag_matrix_pt->
value();
2009 const int* row_start_c_pt = imag_matrix_pt->
row_start();
2010 const int* column_index_c_pt = imag_matrix_pt->
column_index();
2015 if (real_matrix_pt->
nrow() != imag_matrix_pt->
nrow())
2017 std::ostringstream error_message_stream;
2018 error_message_stream <<
"The real and imaginary matrices do not have "
2019 <<
"compatible sizes";
2021 OOMPH_CURRENT_FUNCTION,
2022 OOMPH_EXCEPTION_LOCATION);
2026 if (real_matrix_pt->
ncol() != imag_matrix_pt->
ncol())
2028 std::ostringstream error_message_stream;
2029 error_message_stream <<
"The real and imaginary matrices do not have "
2030 <<
"compatible sizes";
2032 OOMPH_CURRENT_FUNCTION,
2033 OOMPH_EXCEPTION_LOCATION);
2038 unsigned nnz = 2 * (nnz_r + nnz_c);
2059 for (
unsigned i = 0;
i < n_rows_r;
i++)
2062 row_start[
i] = *(row_start_r_pt +
i) + *(row_start_c_pt +
i);
2066 for (
unsigned i = n_rows_r;
i < 2 * n_rows_r;
i++)
2069 row_start[
i] = row_start[
i - n_rows_r] + (nnz_r + nnz_c);
2073 row_start[2 * n_rows_r] = nnz;
2083 for (
unsigned i = 0;
i < n_rows_r;
i++)
2086 unsigned i_row_r_nnz = *(row_start_r_pt +
i + 1) - *(row_start_r_pt +
i);
2089 unsigned i_row_c_nnz = *(row_start_c_pt +
i + 1) - *(row_start_c_pt +
i);
2092 unsigned i_first_entry_r = *(row_start_r_pt +
i);
2095 unsigned i_first_entry_c = *(row_start_c_pt +
i);
2098 for (
unsigned j = 0; j < i_row_r_nnz; j++)
2102 column_index[i_nnz] = *(column_index_r_pt + i_first_entry_r + j);
2105 value[i_nnz] = *(value_r_pt + i_first_entry_r + j);
2112 for (
unsigned j = 0; j < i_row_c_nnz; j++)
2116 column_index[i_nnz] =
2117 *(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] =
2164 *(column_index_r_pt + i_first_entry_r + j) + n_rows_r;
2167 value[i_nnz] = *(value_r_pt + i_first_entry_r + j);
2183 Mg_hierarchy_pt[Nlevel - 1]->communicator_pt(), 2 * n_rows_r,
false);
2188 Coarsest_matrix_mg_pt->build(
2189 dist_pt, 2 * n_rows_r, value, column_index, row_start);
2192 Coarsest_x_mg.build(dist_pt);
2195 Coarsest_rhs_mg.build(dist_pt);
2202 double total_setup_time = double(t_cm_end - t_cm_start);
2203 oomph_info <<
" - Time for formation of the full matrix "
2204 <<
"on the coarsest level [sec]: " << total_setup_time <<
"\n"
2227 Mg_hierarchy_pt[level]->mg_bulk_mesh_pt();
2243 corner_node_id[0] = 0;
2246 corner_node_id[1] = nnode_1d - 1;
2249 corner_node_id[2] = nnode_1d * nnode_1d - 1;
2252 corner_node_id[3] = nnode_1d * (nnode_1d - 1);
2257 Node* first_node_pt = 0;
2260 Node* second_node_pt = 0;
2273 unsigned n_element = bulk_mesh_pt->
nelement();
2279 double test_h = 0.0;
2282 unsigned n_edge = 4;
2285 for (
unsigned i = 0;
i < n_element;
i++)
2291 for (
unsigned j = 0; j < n_edge; j++)
2294 first_node_pt = el_pt->
node_pt(corner_node_id[j]);
2297 second_node_pt = el_pt->
node_pt(corner_node_id[(j + 1) % 4]);
2300 for (
unsigned n = 0; n < 2; n++)
2303 first_node_x[n] = first_node_pt->x(n);
2307 for (
unsigned n = 0; n < 2; n++)
2310 second_node_x[n] = second_node_pt->
x(n);
2317 for (
unsigned n = 0; n < 2; n++)
2320 test_h += pow(second_node_x[n] - first_node_x[n], 2.0);
2324 test_h = sqrt(test_h);
2359 Mg_hierarchy_pt[level]->mg_bulk_mesh_pt();
2417 unsigned n_edge = 12;
2423 edge_node_pair[0] = std::make_pair(corner_node_id[0], corner_node_id[1]);
2426 edge_node_pair[1] = std::make_pair(corner_node_id[0], corner_node_id[2]);
2429 edge_node_pair[2] = std::make_pair(corner_node_id[0], corner_node_id[4]);
2432 edge_node_pair[3] = std::make_pair(corner_node_id[1], corner_node_id[3]);
2435 edge_node_pair[4] = std::make_pair(corner_node_id[1], corner_node_id[5]);
2438 edge_node_pair[5] = std::make_pair(corner_node_id[2], corner_node_id[3]);
2441 edge_node_pair[6] = std::make_pair(corner_node_id[2], corner_node_id[6]);
2444 edge_node_pair[7] = std::make_pair(corner_node_id[3], corner_node_id[7]);
2447 edge_node_pair[8] = std::make_pair(corner_node_id[4], corner_node_id[5]);
2450 edge_node_pair[9] = std::make_pair(corner_node_id[4], corner_node_id[6]);
2453 edge_node_pair[10] = std::make_pair(corner_node_id[5], corner_node_id[7]);
2456 edge_node_pair[11] = std::make_pair(corner_node_id[6], corner_node_id[7]);
2461 Node* first_node_pt = 0;
2464 Node* second_node_pt = 0;
2477 unsigned n_element = bulk_mesh_pt->
nelement();
2483 double test_h = 0.0;
2486 for (
unsigned i = 0;
i < n_element;
i++)
2492 for (
unsigned j = 0; j < n_edge; j++)
2495 first_node_pt = el_pt->
node_pt(edge_node_pair[j].first);
2498 second_node_pt = el_pt->
node_pt(edge_node_pair[j].second);
2501 for (
unsigned n = 0; n < 3; n++)
2504 first_node_x[n] = first_node_pt->
x(n);
2508 for (
unsigned n = 0; n < 3; n++)
2511 second_node_x[n] = second_node_pt->
x(n);
2518 for (
unsigned n = 0; n < 3; n++)
2521 test_h += pow(second_node_x[n] - first_node_x[n], 2.0);
2525 test_h = sqrt(test_h);
2540 template<
unsigned DIM>
2544 double t_m_start = 0.0;
2547 if (!Suppress_all_output)
2550 oomph_info <<
"Starting the setup of all smoothers.\n" << std::endl;
2557 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
2562 if (0 == Pre_smoother_factory_function_pt)
2568 if (Wavenumber * Max_edge_width[
i] < 0.5)
2575 Pre_smoothers_storage_pt[
i] = damped_jacobi_pt;
2587 Pre_smoothers_storage_pt[
i] = gmres_pt;
2595 Pre_smoothers_storage_pt[
i] = (*Pre_smoother_factory_function_pt)();
2601 if (0 == Post_smoother_factory_function_pt)
2607 if (Wavenumber * Max_edge_width[
i] < 0.5)
2614 Post_smoothers_storage_pt[
i] = damped_jacobi_pt;
2626 Post_smoothers_storage_pt[
i] = gmres_pt;
2634 Post_smoothers_storage_pt[
i] = (*Post_smoother_factory_function_pt)();
2643 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
2646 Pre_smoothers_storage_pt[
i]->
tolerance() = 1.0e-16;
2649 Post_smoothers_storage_pt[
i]->tolerance() = 1.0e-16;
2654 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
2657 Pre_smoothers_storage_pt[
i]->max_iter() = Npre_smooth;
2660 Post_smoothers_storage_pt[
i]->max_iter() = Npost_smooth;
2664 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
2668 Pre_smoothers_storage_pt[
i]->complex_smoother_setup(
2669 Mg_matrices_storage_pt[
i]);
2673 Post_smoothers_storage_pt[
i]->complex_smoother_setup(
2674 Mg_matrices_storage_pt[
i]);
2678 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
2683 unsigned n_dof = X_mg_vectors_storage[
i][0].nrow();
2688 Mg_hierarchy_pt[
i]->communicator_pt(), n_dof,
false);
2691 #ifdef OOMPH_HAS_MPI
2694 "Setup of pre- and post-smoother distribution ";
2695 warning_message +=
"has not been tested with MPI.";
2702 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2708 Pre_smoothers_storage_pt[
i]->build_distribution(dist);
2711 Post_smoothers_storage_pt[
i]->build_distribution(dist);
2720 disable_smoother_and_superlu_doc_time();
2724 if (!Suppress_all_output)
2728 double total_setup_time = double(t_m_end - t_m_start);
2729 oomph_info <<
"CPU time for setup of smoothers on all levels [sec]: "
2730 << total_setup_time << std::endl;
2734 <<
"Smoother Setup Complete"
2735 <<
"=================" << std::endl;
2743 template<
unsigned DIM>
2760 std::ostringstream error_message_stream;
2761 error_message_stream <<
"DIM should be 2 or 3 not " << DIM << std::endl;
2763 OOMPH_CURRENT_FUNCTION,
2764 OOMPH_EXCEPTION_LOCATION);
2773 if (Mg_hierarchy_pt[0]->mesh_pt(0) != Mg_hierarchy_pt[0]->mg_bulk_mesh_pt())
2776 std::ostringstream error_message_stream;
2779 error_message_stream <<
"MG solver requires the first submesh be the "
2780 <<
"refineable bulk mesh provided by the user."
2785 OOMPH_CURRENT_FUNCTION,
2786 OOMPH_EXCEPTION_LOCATION);
2801 unsigned nnod_element =
2802 dynamic_cast<FiniteElement*
>(Mg_problem_pt->mesh_pt()->element_pt(0))
2812 for (
unsigned level = 0; level < Nlevel - 1; level++)
2815 unsigned fine_level = level;
2818 unsigned coarse_level = level + 1;
2822 Mesh* ref_fine_mesh_pt = Mg_hierarchy_pt[fine_level]->mesh_pt();
2826 Mesh* ref_coarse_mesh_pt = Mg_hierarchy_pt[coarse_level]->mesh_pt();
2831 unsigned fine_n_element = ref_fine_mesh_pt->
nelement();
2834 unsigned n_bulk_mesh_element =
2835 Mg_hierarchy_pt[fine_level]->mg_bulk_mesh_pt()->nelement();
2842 if (fine_n_element > n_bulk_mesh_element)
2845 coarse_mesh_from_obj_pt =
2850 unsigned n_fine_dof = Mg_hierarchy_pt[fine_level]->ndof();
2853 unsigned n_coarse_dof = Mg_hierarchy_pt[coarse_level]->ndof();
2861 unsigned n_row = n_fine_dof / 2.0;
2864 unsigned n_col = n_coarse_dof / 2.0;
2874 coarse_mesh_reference_element_pt;
2877 unsigned e_fine = 0;
2880 unsigned e_coarse = 0;
2888 while (e_fine < n_bulk_mesh_element)
2898 if (e_coarse > ref_coarse_mesh_pt->
nelement() - 1)
2901 std::ostringstream error_message_stream;
2904 error_message_stream
2905 <<
"The coarse level mesh has " << ref_coarse_mesh_pt->
nelement()
2906 <<
" elements but the coarse\nelement loop "
2907 <<
"is looking at the " << e_coarse <<
"-th element!" << std::endl;
2911 OOMPH_CURRENT_FUNCTION,
2912 OOMPH_EXCEPTION_LOCATION);
2923 if (el_fine_pt->tree_pt()->level() > el_coarse_pt->tree_pt()->level())
2930 for (
unsigned i = 0;
i < n_sons;
i++)
2933 coarse_mesh_reference_element_pt
2944 else if (el_fine_pt->tree_pt()->level() ==
2945 el_coarse_pt->tree_pt()->level())
2949 coarse_mesh_reference_element_pt
2970 std::ostringstream error_message_stream;
2973 error_message_stream <<
"Element unrefined between levels! Can't "
2974 <<
"handle this case yet..." << std::endl;
2978 OOMPH_CURRENT_FUNCTION,
2979 OOMPH_EXCEPTION_LOCATION);
2987 std::vector<bool> contribution_made(n_row,
false);
3012 for (
unsigned k = 0; k < fine_n_element; k++)
3034 if (k < n_bulk_mesh_element)
3038 el_coarse_pt = coarse_mesh_reference_element_pt[el_fine_pt];
3042 if (el_fine_pt->tree_pt()->level() !=
3043 el_coarse_pt->tree_pt()->level())
3046 son_type = el_fine_pt->tree_pt()->son_type();
3056 for (
unsigned i = 0;
i < nnod_element;
i++)
3060 int ii = el_fine_pt->node_pt(
i)->eqn_number(0);
3070 if (contribution_made[ii / 2] ==
false)
3078 row_start[index] = value.size();
3095 if (k >= n_bulk_mesh_element)
3099 el_fine_pt->node_pt(
i)->position(fine_node_position);
3109 fine_node_position, el_pt,
s);
3117 el_fine_pt->local_coordinate_of_node(
i,
s);
3122 level_up_local_coord_of_node(son_type,
s);
3126 Shape psi(el_coarse_pt->nnode());
3129 el_coarse_pt->shape(
s, psi);
3132 std::map<unsigned, double> contribution;
3136 unsigned nnod_coarse = el_coarse_pt->nnode();
3139 for (
unsigned j = 0; j < nnod_coarse; j++)
3144 int jj = el_coarse_pt->node_pt(j)->eqn_number(0);
3151 if (el_coarse_pt->node_pt(j)->is_hanging())
3156 el_coarse_pt->node_pt(j)->hanging_pt();
3157 unsigned nmaster = hang_info_pt->
nmaster();
3160 for (
unsigned i_master = 0; i_master < nmaster; i_master++)
3163 Node* master_node_pt =
3169 int master_jj = master_node_pt->
eqn_number(0);
3178 contribution[master_jj / 2] +=
3192 contribution[jj / 2] += psi(j);
3198 for (std::map<unsigned, double>::iterator it =
3199 contribution.begin();
3200 it != contribution.end();
3203 if (it->second != 0)
3206 column_index.push_back(it->first);
3210 value.push_back(it->second);
3221 contribution_made[ii / 2] =
true;
3228 row_start[n_row] = value.size();
3233 interpolation_matrix_set(
3234 level, value, column_index, row_start, n_col, n_row);
3241 template<
unsigned DIM>
3243 DIM>::setup_interpolation_matrices_unstructured()
3246 if ((DIM != 2) && (DIM != 3))
3248 std::ostringstream error_message_stream;
3249 error_message_stream <<
"DIM should be 2 or 3 not " << DIM << std::endl;
3251 OOMPH_CURRENT_FUNCTION,
3252 OOMPH_EXCEPTION_LOCATION);
3262 for (
unsigned level = 0; level < Nlevel - 1; level++)
3265 unsigned coarse_level = level + 1;
3266 unsigned fine_level = level;
3270 Mesh* ref_fine_mesh_pt = Mg_hierarchy_pt[fine_level]->mg_bulk_mesh_pt();
3279 unsigned coarse_n_unknowns = Mg_hierarchy_pt[coarse_level]->ndof();
3280 unsigned fine_n_unknowns = Mg_hierarchy_pt[fine_level]->ndof();
3300 unsigned n_node_fine_mesh = ref_fine_mesh_pt->
nnode();
3303 for (
unsigned i_fine_node = 0; i_fine_node < n_node_fine_mesh;
3307 Node* fine_node_pt = ref_fine_mesh_pt->
node_pt(i_fine_node);
3317 row_start[i_fine] = value.size();
3320 fine_node_pt->
position(fine_node_position);
3327 coarse_mesh_from_obj_pt->
locate_zeta(fine_node_position, el_pt,
s);
3333 unsigned n_node = el_coarse_pt->
nnode();
3339 el_coarse_pt->
shape(
s, psi);
3342 std::map<unsigned, double> contribution;
3347 for (
unsigned j_node = 0; j_node < n_node; j_node++)
3350 Node* coarse_node_pt = el_coarse_pt->
node_pt(j_node);
3354 int j_coarse = coarse_node_pt->
eqn_number(0);
3366 unsigned nmaster = hang_info_pt->
nmaster();
3369 for (
unsigned i_master = 0; i_master < nmaster; i_master++)
3377 int master_jj = master_node_pt->
eqn_number(0);
3386 contribution[master_jj] +=
3398 if (psi(j_node) != 0.0)
3400 contribution[j_coarse] += psi(j_node);
3407 for (std::map<unsigned, double>::iterator it = contribution.begin();
3408 it != contribution.end();
3411 if (it->second != 0)
3413 value.push_back(it->second);
3414 column_index.push_back(it->first);
3421 row_start[fine_n_unknowns] = value.size();
3426 interpolation_matrix_set(level,
3455 s[0] = (
s[0] + 1.0) / 2.0;
3456 s[1] = (
s[1] + 1.0) / 2.0;
3457 s[2] = (
s[2] + 1.0) / 2.0;
3522 s[0] = (
s[0] + 1.0) / 2.0;
3523 s[1] = (
s[1] + 1.0) / 2.0;
3562 template<
unsigned DIM>
3567 if (!(level < Nlevel - 1))
3570 throw OomphLibError(
"Input level exceeds the possible parameter choice.",
3571 OOMPH_CURRENT_FUNCTION,
3572 OOMPH_EXCEPTION_LOCATION);
3578 Restriction_matrices_storage_pt[level]->multiply(
3579 Residual_mg_vectors_storage[level][0],
3580 Rhs_mg_vectors_storage[level + 1][0]);
3584 Restriction_matrices_storage_pt[level]->multiply(
3585 Residual_mg_vectors_storage[level][1],
3586 Rhs_mg_vectors_storage[level + 1][1]);
3594 template<
unsigned DIM>
3596 const unsigned& level)
3603 throw OomphLibError(
"Input level exceeds the possible parameter choice.",
3604 OOMPH_CURRENT_FUNCTION,
3605 OOMPH_EXCEPTION_LOCATION);
3611 X_mg_vectors_storage[level - 1][0].distribution_pt());
3615 X_mg_vectors_storage[level - 1][1].distribution_pt());
3618 Interpolation_matrices_storage_pt[level - 1]->multiply(
3619 X_mg_vectors_storage[level][0], temp_soln_r);
3622 Interpolation_matrices_storage_pt[level - 1]->multiply(
3623 X_mg_vectors_storage[level][1], temp_soln_c);
3626 X_mg_vectors_storage[level - 1][0] += temp_soln_r;
3629 X_mg_vectors_storage[level - 1][1] += temp_soln_c;
3637 template<
unsigned DIM>
3641 double t_mg_start = 0.0;
3642 if (!Suppress_v_cycle_output)
3649 unsigned finest_level = 0;
3652 V_cycle_counter = 0;
3655 double normalised_residual_norm = residual_norm(finest_level);
3656 if (!Suppress_v_cycle_output)
3658 oomph_info <<
"\nResidual on finest level for V-cycle: "
3659 << normalised_residual_norm << std::endl;
3666 while ((normalised_residual_norm > Tolerance) &&
3667 (V_cycle_counter != Nvcycle))
3670 if (!Suppress_v_cycle_output)
3673 oomph_info <<
"\nStarting V-cycle: " << V_cycle_counter << std::endl;
3679 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
3687 X_mg_vectors_storage[
i][0].initialise(0.0);
3690 X_mg_vectors_storage[
i][1].initialise(0.0);
3693 Residual_mg_vectors_storage[
i][0].initialise(0.0);
3696 Residual_mg_vectors_storage[
i][1].initialise(0.0);
3705 restrict_residual(
i);
3718 for (
unsigned i = Nlevel - 1;
i > 0;
i--)
3722 interpolate_and_correct(
i);
3734 normalised_residual_norm = residual_norm(finest_level);
3737 if (!Suppress_v_cycle_output)
3739 oomph_info <<
"Residual on finest level of V-cycle: "
3740 << normalised_residual_norm << std::endl;
3745 result = X_mg_vectors_storage[finest_level];
3748 if (!Suppress_v_cycle_output)
3754 if (!Suppress_all_output)
3757 if (normalised_residual_norm < Tolerance)
3759 Has_been_solved =
true;
3764 if (!Suppress_v_cycle_output)
3768 double total_G_setup_time = double(t_mg_end - t_mg_start);
3769 oomph_info <<
"CPU time for MG solver [sec]: " << total_G_setup_time
Block Preconditioner base class. The block structure of the overall problem is determined from the Me...
void return_block_vectors(const Vector< unsigned > &block_vec_number, const Vector< DoubleVector > &s, DoubleVector &v) const
Takes the vector of block vectors, s, and copies its entries into the naturally ordered vector,...
void get_block_vectors(const Vector< unsigned > &block_vec_number, const DoubleVector &v, Vector< DoubleVector > &s) const
Takes the naturally ordered vector and rearranges it into a vector of sub vectors corresponding to th...
A class for compressed row matrices. This is a distributable object.
int * column_index()
Access to C-style column index array.
int * row_start()
Access to C-style row_start array.
unsigned long ncol() const
Return the number of columns of the matrix.
unsigned long nnz() const
Return the number of nonzero entries (the local nnz)
double * value()
Access to C-style value array.
unsigned long nrow() const
Return the number of rows of the matrix.
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 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....
The GMRES method rewritten for complex matrices.
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
//////////////////////////////////////////////////////////////////////////// ////////////////////////...
unsigned long nrow() const
Return the number of rows of the matrix.
unsigned nrow() const
access function to the number of global rows.
LinearSolver *& linear_solver_pt()
Return a pointer to the linear solver object.
void solve(DoubleVector &rhs)
Complete LU solve (replaces matrix by its LU decomposition and overwrites RHS with solution)....
A vector in the mathematical sense, initially developed for linear algebra type applications....
A general Finite Element class.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
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...
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
unsigned nnode() const
Return the number of nodes.
/////////////////////////////////////////////////////////////////////
Class that contains data for hanging nodes.
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
unsigned nmaster() const
Return the number of master nodes.
/////////////////////////////////////////////////////// /////////////////////////////////////////////...
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 pre_smooth(const unsigned &level)
Pre-smoother: Perform 'max_iter' smoothing steps on the linear system Ax=b with current RHS vector,...
void enable_v_cycle_output()
Enable the output of the V-cycle timings and other output.
void direct_solve()
Call the direct solver (SuperLU) to solve the problem exactly.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Function applies MG to the vector r for a full solve.
PreSmootherFactoryFctPt Pre_smoother_factory_function_pt
Function to create pre-smoothers.
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.
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...
Vector< double > Max_edge_width
Vector to storage the maximum edge width of each mesh. We only need the maximum edge width on levels ...
void disable_output()
Suppress anything that can be suppressed, i.e. any timings. Things like mesh adaptation can not howev...
CRDoubleMatrix * Coarsest_matrix_mg_pt
Stores the system matrix on the coarest level in the fully expanded format: |--—|---—| | A_r | -A_c |...
HelmholtzSmoother *(* PostSmootherFactoryFctPt)()
typedef for a function that returns a pointer to an object of the class HelmholtzSmoother to be used ...
double Tolerance
The tolerance of the multigrid preconditioner.
void setup_mg_structures()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level.
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...
Vector< CRDoubleMatrix * > Restriction_matrices_storage_pt
Vector to store the restriction matrices.
void disable_doc_time()
Disable time documentation.
unsigned iterations() const
Number of iterations.
DoubleVector Coarsest_rhs_mg
Assuming we're solving the system Ax=b, this vector will contain the expanded solution vector on the ...
void setup_interpolation_matrices()
Setup the interpolation matrix on each level.
bool Has_been_setup
Boolean variable to indicate whether or not the solver has been setup.
void full_setup()
Do a full setup (assumes everything will be setup around the HelmholtzMGProblem pointer given in the ...
unsigned Npre_smooth
Number of pre-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....
Vector< CRDoubleMatrix * > Interpolation_matrices_storage_pt
Vector to store the interpolation matrices.
void disable_smoother_and_superlu_doc_time()
Suppress the output of both smoothers and SuperLU.
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...
PostSmootherFactoryFctPt Post_smoother_factory_function_pt
Function to create post-smoothers.
bool Doc_time
Indicates whether or not time documentation should be used.
void post_smooth(const unsigned &level)
Post-smoother: Perform max_iter smoothing steps on the linear system Ax=b with current RHS vector,...
unsigned Npost_smooth
Number of post-smoothing steps.
Vector< HelmholtzMGProblem * > Mg_hierarchy_pt
Vector containing pointers to problems in hierarchy.
bool Suppress_v_cycle_output
Indicates whether or not the V-cycle output should be suppressed.
void interpolate_and_correct(const unsigned &level)
Interpolate solution at current level onto next finer mesh and correct the solution x at that level.
void setup_transfer_matrices()
Setup the transfer matrices on each level.
HelmholtzMGPreconditioner(HelmholtzMGProblem *mg_problem_pt)
Constructor: Set up default values for number of V-cycles and pre- and post-smoothing steps.
void setup_smoothers()
Function to set up all of the smoothers once the system matrices have been set up.
void clean_up_memory()
Clean up anything that needs to be cleaned up.
void set_restriction_matrices_as_interpolation_transposes()
Builds a CRDoubleMatrix on each level that is used to restrict the residual between levels....
void enable_output()
Enable the output from anything that could have been suppressed.
DoubleVector Coarsest_x_mg
Assuming we're solving the system Ax=b, this vector will contain the expanded solution vector on the ...
void block_preconditioner_self_test()
Function to ensure the block form of the Jacobian matches the form described, i.e....
void set_post_smoother_factory_function(PostSmootherFactoryFctPt post_smoother_fn)
Access function to set the post-smoother creation function.
double Alpha_shift
Temporary version of the shift – to run bash scripts.
void enable_doc_time()
Enable time documentation.
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...
double & alpha_shift()
Function to change the value of the shift.
unsigned & npre_smooth()
Return the number of pre-smoothing iterations (lvalue)
void maximum_edge_width(const unsigned &level, double &h)
Estimate the value of the parameter h on the level-th problem in the hierarchy.
Vector< HelmholtzSmoother * > Pre_smoothers_storage_pt
Vector to store the pre-smoothers.
double Wavenumber
The value of the wavenumber, k.
std::ostream * Stream_pt
Pointer to the output stream – defaults to std::cout.
unsigned & npost_smooth()
Return the number of post-smoothing iterations (lvalue)
void setup()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level.
Vector< HelmholtzSmoother * > Post_smoothers_storage_pt
Vector to store the post-smoothers.
HelmholtzMGProblem * Mg_problem_pt
Pointer to the MG problem (deep copy)
HelmholtzSmoother *(* PreSmootherFactoryFctPt)()
typedef for a function that returns a pointer to an object of the class HelmholtzSmoother to be used ...
void setup_interpolation_matrices_unstructured()
Setup the interpolation matrix on each level (used for unstructured meshes)
void set_pre_smoother_factory_function(PreSmootherFactoryFctPt pre_smoother_fn)
Access function to set the pre-smoother creation function.
bool Suppress_all_output
If this is set to true then all output from the solver is suppressed.
bool Has_been_solved
Boolean variable to indicate whether or not the problem was successfully solved.
unsigned Nvcycle
Maximum number of V-cycles.
void setup_mg_hierarchy()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level.
double residual_norm(const unsigned &level)
Return norm of residual r=b-Ax and the residual vector itself on the level-th level.
double & tolerance()
Access function for the variable Tolerance (lvalue)
~HelmholtzMGPreconditioner()
Delete any dynamically allocated data.
unsigned V_cycle_counter
Pointer to counter for V-cycles.
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...
void mg_solve(Vector< DoubleVector > &result)
Do the actual solve – this is called through the pure virtual solve function in the LinearSolver base...
unsigned Nlevel
The number of levels in the multigrid heirachy.
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...
HelmholtzMGProblem class; subclass of Problem.
virtual ~HelmholtzMGProblem()
Destructor (empty)
HelmholtzMGProblem()
Constructor. Initialise pointers to coarser and finer levels.
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...
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 ...
Helmholtz smoother class: The smoother class is designed for the Helmholtz equation to be used in con...
double & tolerance()
Access to convergence tolerance.
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
void disable_doc_time()
Disable documentation of solve times.
static OomphCommunicator * communicator_pt()
access to global communicator. This is the oomph-lib equivalent of MPI_COMM_WORLD
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
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...
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
unsigned long nnode() const
Return number of nodes in the mesh.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
unsigned long nelement() const
Return number of elements in the mesh.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
double & x(const unsigned &i)
Return the i-th nodal coordinate.
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
void position(Vector< double > &pos) const
Compute Vector of nodal positions either directly or via hanging node representation.
bool is_hanging() const
Test whether the node is geometrically hanging.
OcTree class: Recursively defined, generalised octree.
static unsigned vertex_to_node_number(const int &vertex, const unsigned &nnode1d)
Return the local node number of given vertex [LDB,RDB,...] in an element with nnode1d nodes in each c...
std::ostream *& stream_pt()
Access function for the stream pointer.
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
A class for all isoparametric elements that solve the Helmholtz equations with pml capabilities....
double k_squared()
Get the square of wavenumber.
double *& alpha_pt()
Pointer to Alpha, wavenumber complex shift.
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...
virtual void actions_before_adapt()
Actions that are to be performed before a mesh adaptation. These might include removing any additiona...
virtual void actions_after_adapt()
Actions that are to be performed after a mesh adaptation.
RefineableElements are FiniteElements that may be subdivided into children to provide a better local ...
Refineable version of QElement<3,NNODE_1D>.
A class that is used to template the refineable Q elements by dimension. It's really nothing more tha...
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
///////////////////////////////////////////////////////////////// ///////////////////////////////////...
virtual bool refine_base_mesh_as_in_reference_mesh_minus_one(TreeBasedRefineableMeshBase *const &ref_mesh_pt)
Refine base mesh to same degree as reference mesh minus one level of refinement (relative to original...
static const int OMEGA
Default value for an unassigned neighbour.
A slight extension to the standard template vector class so that we can include "graceful" array rang...
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
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 concatenate(const Vector< DoubleVector * > &in_vector_pt, DoubleVector &out_vector)
Concatenate DoubleVectors. Takes a Vector of DoubleVectors. If the out vector is built,...
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
void clean_up_memory()
Clean up function that deletes anything dynamically allocated in this namespace.
double timer()
returns the time in seconds after some point in past
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Nullstream oomph_nullstream
///////////////////////////////////////////////////////////////////////// ///////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...