27 #ifndef OOMPH_GEOMETRIC_MULTIGRID_HEADER
28 #define OOMPH_GEOMETRIC_MULTIGRID_HEADER
88 template<
unsigned DIM>
94 typedef Smoother* (*PreSmootherFactoryFctPt)();
98 typedef Smoother* (*PostSmootherFactoryFctPt)();
155 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
177 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
239 void plot(
const unsigned& hierarchy_level,
311 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
324 ->disable_doc_time();
414 ncol, nnz, value, col_index, row_st);
438 "Setup of interpolation matrix distribution ";
439 warning_message +=
"has not been tested with MPI.";
446 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
453 dist_pt, ncol, value, col_index, row_st);
467 for (
unsigned i = 0;
i <
Nlevel - 1;
i++)
517 if (0 == mg_problem_pt)
519 throw OomphLibError(
"Input problem must be of type MGProblem.",
520 OOMPH_CURRENT_FUNCTION,
521 OOMPH_EXCEPTION_LOCATION);
531 std::ostringstream error_message_stream;
532 error_message_stream <<
"Cannot currently deal with more than 1 dof"
533 <<
" per node. This problem has " << n_value
534 <<
" dofs per node." << std::endl;
538 OOMPH_CURRENT_FUNCTION,
539 OOMPH_EXCEPTION_LOCATION);
557 <<
"Multigrid Solve Complete"
558 <<
"=================\n"
575 oomph_info <<
"Total number of V-cycles required for solve: "
733 template<
unsigned DIM>
762 OomphLibWarning(
"Can't guarantee the MG solver will work in parallel!",
763 OOMPH_CURRENT_FUNCTION,
764 OOMPH_EXCEPTION_LOCATION);
786 throw OomphLibError(
"Matrix and RHS vector sizes incompatible.",
787 OOMPH_CURRENT_FUNCTION,
788 OOMPH_EXCEPTION_LOCATION);
803 <<
"\n==========Multigrid Preconditioner Solve Complete========="
825 template<
unsigned DIM>
829 double t_fs_start = 0.0;
832 if (!Suppress_all_output)
839 <<
"\n===============Starting Multigrid Full Setup=============="
843 oomph_info <<
"\nStarting the full setup of the multigrid solver."
850 if (
dynamic_cast<FiniteElement*
>(Mg_problem_pt->mesh_pt()->element_pt(0))
853 std::string err_strng =
"The dimension of the elements used in the mesh ";
854 err_strng +=
"does not match the dimension of the solver.";
856 err_strng, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
861 if (Mg_problem_pt->mg_bulk_mesh_pt() != 0)
864 unsigned n_elements = Mg_problem_pt->mg_bulk_mesh_pt()->nelement();
868 for (
unsigned el_counter = 0; el_counter < n_elements; el_counter++)
872 Mg_problem_pt->mg_bulk_mesh_pt()->element_pt(el_counter));
879 "Element in global mesh could not be upcast to a refineable "
880 "element. We cannot deal with elements that are not refineable.",
881 OOMPH_CURRENT_FUNCTION,
882 OOMPH_EXCEPTION_LOCATION);
889 "The provided bulk mesh pointer is set to be a null pointer. "
890 "The multigrid solver operates on the bulk mesh thus a pointer "
891 "to the correct mesh must be given.",
892 OOMPH_CURRENT_FUNCTION,
893 OOMPH_EXCEPTION_LOCATION);
902 Mg_hierarchy.resize(1, 0);
905 Mg_hierarchy[0] = Mg_problem_pt;
908 setup_mg_hierarchy();
911 setup_transfer_matrices();
915 setup_mg_structures();
925 for (
unsigned i = 1;
i < Nlevel;
i++)
928 delete Mg_hierarchy[
i];
942 Has_been_setup =
true;
945 if (!Suppress_all_output)
949 double full_setup_time = t_fs_end - t_fs_start;
952 oomph_info <<
"\nCPU time for full setup [sec]: " << full_setup_time
957 <<
"\n===============Multigrid Full Setup Complete=============="
967 template<
unsigned DIM>
971 double t_m_start = 0.0;
974 if (!Suppress_all_output)
978 <<
"\n===============Creating Multigrid Hierarchy==============="
988 bool managed_to_create_unrefined_copy =
true;
996 while (managed_to_create_unrefined_copy)
1009 managed_to_create_unrefined_copy =
1012 Mg_hierarchy[level]->mg_bulk_mesh_pt());
1016 if (managed_to_create_unrefined_copy)
1023 if (!Suppress_all_output)
1026 oomph_info <<
"\nSuccess! Level " << level <<
" has been created."
1039 Mg_hierarchy.push_back(new_problem_pt);
1045 delete new_problem_pt;
1051 Nlevel = Mg_hierarchy.size();
1055 if (!Suppress_all_output)
1058 oomph_info <<
"\n Reached the coarsest level! "
1059 <<
"Number of levels: " << Nlevel << std::endl;
1067 Mg_matrices_storage_pt.resize(Nlevel, 0);
1070 X_mg_vectors_storage.resize(Nlevel);
1073 Rhs_mg_vectors_storage.resize(Nlevel);
1076 Residual_mg_vectors_storage.resize(Nlevel);
1080 Pre_smoothers_storage_pt.resize(Nlevel - 1, 0);
1084 Post_smoothers_storage_pt.resize(Nlevel - 1, 0);
1087 Interpolation_matrices_storage_pt.resize(Nlevel - 1, 0);
1090 Restriction_matrices_storage_pt.resize(Nlevel - 1, 0);
1092 if (!Suppress_all_output)
1096 double total_setup_time = double(t_m_end - t_m_start);
1098 <<
"\nCPU time for creation of hierarchy of MG problems [sec]: "
1099 << total_setup_time << std::endl;
1103 <<
"\n===============Hierarchy Creation Complete================"
1116 template<
unsigned DIM>
1120 double t_r_start = 0.0;
1123 if (!Suppress_all_output)
1126 oomph_info <<
"Creating the transfer matrices ";
1133 if (!Suppress_all_output)
1136 oomph_info <<
"using full weighting (recommended).\n" << std::endl;
1143 Mg_problem_pt->mg_bulk_mesh_pt()))
1145 setup_interpolation_matrices();
1151 setup_interpolation_matrices_unstructured();
1155 set_restriction_matrices_as_interpolation_transposes();
1158 if (!Suppress_all_output)
1162 double total_G_setup_time = double(t_r_end - t_r_start);
1163 oomph_info <<
"CPU time for transfer matrices setup [sec]: "
1164 << total_G_setup_time << std::endl;
1168 <<
"\n============Transfer Matrices Setup Complete=============="
1179 template<
unsigned DIM>
1183 double t_m_start = 0.0;
1186 if (!Suppress_all_output)
1193 for (
unsigned i = 0;
i < Nlevel;
i++)
1201 for (
unsigned i = 0;
i < Nlevel;
i++)
1204 if (!Suppress_all_output)
1207 oomph_info <<
"Setting up MG structures on level: " <<
i <<
"\n"
1212 unsigned n_dof = Mg_hierarchy[
i]->ndof();
1214 Mg_hierarchy[
i]->communicator_pt(), n_dof,
false);
1217 #ifdef OOMPH_HAS_MPI
1219 std::string warning_message =
"Setup of distribution has not been ";
1220 warning_message +=
"tested with MPI.";
1227 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1233 X_mg_vectors_storage[
i].clear();
1234 X_mg_vectors_storage[
i].build(dist_pt);
1237 Rhs_mg_vectors_storage[
i].clear();
1238 Rhs_mg_vectors_storage[
i].build(dist_pt);
1241 Residual_mg_vectors_storage[
i].clear();
1242 Residual_mg_vectors_storage[
i].build(dist_pt);
1251 Mg_matrices_storage_pt[
i]->
clear();
1252 Mg_matrices_storage_pt[
i]->distribution_pt()->build(
1253 Mg_hierarchy[
i]->communicator_pt(), n_dof,
false);
1265 double t_jac_start = 0.0;
1268 if (!Suppress_all_output)
1276 Mg_hierarchy[0]->get_jacobian(Rhs_mg_vectors_storage[0],
1277 *Mg_matrices_storage_pt[0]);
1279 if (!Suppress_all_output)
1283 double jacobian_setup_time = t_jac_end - t_jac_start;
1284 oomph_info <<
" - Time for setup of Jacobian [sec]: "
1285 << jacobian_setup_time <<
"\n"
1292 double t_gal_start = 0.0;
1295 if (!Suppress_all_output)
1309 Mg_matrices_storage_pt[
i - 1]->multiply(
1310 *Interpolation_matrices_storage_pt[
i - 1],
1311 *Mg_matrices_storage_pt[
i]);
1316 Restriction_matrices_storage_pt[
i - 1]->multiply(
1317 *Mg_matrices_storage_pt[
i], *Mg_matrices_storage_pt[
i]);
1320 if (!Suppress_all_output)
1326 double galerkin_matrix_calculation_time = t_gal_end - t_gal_start;
1330 <<
" - Time for system matrix formation using the Galerkin "
1331 <<
"approximation [sec]: " << galerkin_matrix_calculation_time
1339 if (!Suppress_all_output)
1343 double total_setup_time = double(t_m_end - t_m_start);
1344 oomph_info <<
"Total CPU time for setup of MG structures [sec]: "
1345 << total_setup_time << std::endl;
1349 <<
"Multigrid Structures Setup Complete"
1359 template<
unsigned DIM>
1363 double t_m_start = 0.0;
1366 if (!Suppress_all_output)
1369 oomph_info <<
"Starting the setup of all smoothers.\n" << std::endl;
1376 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
1381 if (0 == Pre_smoother_factory_function_pt)
1390 Pre_smoothers_storage_pt[
i] = (*Pre_smoother_factory_function_pt)();
1396 if (0 == Post_smoother_factory_function_pt)
1405 Post_smoothers_storage_pt[
i] = (*Post_smoother_factory_function_pt)();
1414 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
1417 Pre_smoothers_storage_pt[
i]->
tolerance() = 1.0e-16;
1420 Post_smoothers_storage_pt[
i]->tolerance() = 1.0e-16;
1425 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
1428 Pre_smoothers_storage_pt[
i]->max_iter() = Npre_smooth;
1431 Post_smoothers_storage_pt[
i]->max_iter() = Npost_smooth;
1435 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
1439 Pre_smoothers_storage_pt[
i]->smoother_setup(Mg_matrices_storage_pt[
i]);
1443 Post_smoothers_storage_pt[
i]->smoother_setup(Mg_matrices_storage_pt[
i]);
1447 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
1452 unsigned n_dof = X_mg_vectors_storage[
i].nrow();
1457 Mg_hierarchy[
i]->communicator_pt(), n_dof,
false);
1460 #ifdef OOMPH_HAS_MPI
1463 "Setup of pre- and post-smoother distribution ";
1464 warning_message +=
"has not been tested with MPI.";
1471 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1477 Pre_smoothers_storage_pt[
i]->build_distribution(dist);
1480 Post_smoothers_storage_pt[
i]->build_distribution(dist);
1486 disable_smoother_and_superlu_doc_time();
1490 if (!Suppress_all_output)
1494 double total_setup_time = double(t_m_end - t_m_start);
1495 oomph_info <<
"CPU time for setup of smoothers on all levels [sec]: "
1496 << total_setup_time << std::endl;
1500 <<
"\n==================Smoother Setup Complete================="
1509 template<
unsigned DIM>
1526 std::ostringstream error_message_stream;
1527 error_message_stream <<
"DIM should be 2 or 3 not " << DIM << std::endl;
1529 OOMPH_CURRENT_FUNCTION,
1530 OOMPH_EXCEPTION_LOCATION);
1539 for (
unsigned level = 0; level < Nlevel - 1; level++)
1542 unsigned coarse_level = level + 1;
1543 unsigned fine_level = level;
1548 Mg_hierarchy[fine_level]->mg_bulk_mesh_pt());
1554 Mg_hierarchy[coarse_level]->mg_bulk_mesh_pt());
1559 unsigned fine_n_element = ref_fine_mesh_pt->
nelement();
1565 unsigned n_rows = Mg_hierarchy[fine_level]->ndof();
1566 unsigned n_cols = Mg_hierarchy[coarse_level]->ndof();
1576 coarse_mesh_reference_element_pt;
1580 unsigned e_coarse = 0;
1581 unsigned e_fine = 0;
1586 while (e_fine < fine_n_element)
1600 if (el_fine_pt->tree_pt()->level() != el_coarse_pt->tree_pt()->level())
1607 for (
unsigned i = 0;
i < n_sons;
i++)
1610 coarse_mesh_reference_element_pt
1625 coarse_mesh_reference_element_pt[el_fine_pt] = el_coarse_pt;
1635 std::vector<bool> contribution_made(n_rows,
false);
1656 for (
unsigned k = 0; k < fine_n_element; k++)
1666 coarse_mesh_reference_element_pt[el_fine_pt];
1674 if (el_fine_pt->tree_pt()->level() != el_coarse_pt->tree_pt()->level())
1677 son_type = el_fine_pt->tree_pt()->son_type();
1687 unsigned nnod_fine = el_fine_pt->nnode();
1690 for (
unsigned i = 0;
i < nnod_fine;
i++)
1694 int ii = el_fine_pt->node_pt(
i)->eqn_number(0);
1701 if (contribution_made[ii] ==
false)
1709 row_start[index] = value.size();
1712 el_fine_pt->local_coordinate_of_node(
i,
s);
1717 level_up_local_coord_of_node(son_type,
s);
1720 Shape psi(el_coarse_pt->nnode());
1723 el_coarse_pt->shape(
s, psi);
1726 std::map<unsigned, double> contribution;
1730 unsigned nnod_coarse = el_coarse_pt->nnode();
1733 for (
unsigned j = 0; j < nnod_coarse; j++)
1738 int jj = el_coarse_pt->node_pt(j)->eqn_number(0);
1745 if (el_coarse_pt->node_pt(j)->is_hanging())
1750 el_coarse_pt->node_pt(j)->hanging_pt();
1751 unsigned nmaster = hang_info_pt->
nmaster();
1754 for (
unsigned i_master = 0; i_master < nmaster; i_master++)
1757 Node* master_node_pt =
1763 int master_jj = master_node_pt->
eqn_number(0);
1772 contribution[master_jj] +=
1786 contribution[jj] += psi(j);
1792 for (std::map<unsigned, double>::iterator it =
1793 contribution.begin();
1794 it != contribution.end();
1797 if (it->second != 0)
1799 column_index.push_back(it->first);
1800 value.push_back(it->second);
1811 contribution_made[ii] =
true;
1818 row_start[n_rows] = value.size();
1823 interpolation_matrix_set(
1824 level, value, column_index, row_start, n_cols, n_rows);
1831 template<
unsigned DIM>
1840 for (
unsigned level = 0; level < Nlevel - 1; level++)
1843 unsigned coarse_level = level + 1;
1844 unsigned fine_level = level;
1848 Mesh* ref_fine_mesh_pt = Mg_hierarchy[fine_level]->mg_bulk_mesh_pt();
1857 unsigned coarse_n_unknowns = Mg_hierarchy[coarse_level]->ndof();
1858 unsigned fine_n_unknowns = Mg_hierarchy[fine_level]->ndof();
1878 unsigned n_node_fine_mesh = ref_fine_mesh_pt->
nnode();
1881 for (
unsigned i_fine_node = 0; i_fine_node < n_node_fine_mesh;
1885 Node* fine_node_pt = ref_fine_mesh_pt->
node_pt(i_fine_node);
1895 row_start[i_fine] = value.size();
1898 fine_node_pt->
position(fine_node_position);
1905 coarse_mesh_from_obj_pt->
locate_zeta(fine_node_position, el_pt,
s);
1911 unsigned n_node = el_coarse_pt->
nnode();
1917 el_coarse_pt->
shape(
s, psi);
1920 std::map<unsigned, double> contribution;
1925 for (
unsigned j_node = 0; j_node < n_node; j_node++)
1928 Node* coarse_node_pt = el_coarse_pt->
node_pt(j_node);
1932 int j_coarse = coarse_node_pt->
eqn_number(0);
1944 unsigned nmaster = hang_info_pt->
nmaster();
1947 for (
unsigned i_master = 0; i_master < nmaster; i_master++)
1955 int master_jj = master_node_pt->
eqn_number(0);
1964 contribution[master_jj] +=
1976 if (psi(j_node) != 0.0)
1978 contribution[j_coarse] += psi(j_node);
1985 for (std::map<unsigned, double>::iterator it = contribution.begin();
1986 it != contribution.end();
1989 if (it->second != 0)
1991 value.push_back(it->second);
1992 column_index.push_back(it->first);
1999 row_start[fine_n_unknowns] = value.size();
2004 interpolation_matrix_set(level,
2019 template<
unsigned DIM>
2024 if (!(level < Nlevel - 1))
2026 throw OomphLibError(
"Input exceeds the possible parameter choice.",
2027 OOMPH_CURRENT_FUNCTION,
2028 OOMPH_EXCEPTION_LOCATION);
2034 Restriction_matrices_storage_pt[level]->multiply(
2035 Residual_mg_vectors_storage[level], Rhs_mg_vectors_storage[level + 1]);
2042 template<
unsigned DIM>
2049 throw OomphLibError(
"Input level exceeds the possible parameter choice.",
2050 OOMPH_CURRENT_FUNCTION,
2051 OOMPH_EXCEPTION_LOCATION);
2056 DoubleVector temp_soln(X_mg_vectors_storage[level - 1].distribution_pt());
2059 Interpolation_matrices_storage_pt[level - 1]->multiply(
2060 X_mg_vectors_storage[level], temp_soln);
2063 X_mg_vectors_storage[level - 1] += temp_soln;
2069 template<
unsigned DIM>
2076 for (
unsigned level = 0; level < Nlevel - 1; level++)
2079 restriction_matrix_pt = Restriction_matrices_storage_pt[level];
2082 const int* row_start_pt = restriction_matrix_pt->
row_start();
2085 double* value_pt = restriction_matrix_pt->
value();
2089 unsigned start_index = 0;
2093 unsigned end_index = 0;
2096 unsigned n_row = restriction_matrix_pt->
nrow();
2099 for (
unsigned i = 0;
i < n_row;
i++)
2102 start_index = row_start_pt[
i];
2105 end_index = row_start_pt[
i + 1];
2109 double row_sum = 0.0;
2112 for (
unsigned j = start_index; j < end_index; j++)
2115 row_sum += value_pt[j];
2119 for (
unsigned j = start_index; j < end_index; j++)
2122 value_pt[j] /= row_sum;
2134 template<
unsigned DIM>
2141 oomph_info <<
"\nStarting the multigrid solver self-test." << std::endl;
2144 Restriction_self_test_vectors_storage.resize(Nlevel);
2147 Interpolation_self_test_vectors_storage.resize(Nlevel);
2150 unsigned n_dof = X_mg_vectors_storage[0].nrow();
2154 Mg_problem_pt->communicator_pt(), n_dof,
false);
2157 #ifdef OOMPH_HAS_MPI
2159 std::string warning_message =
"Setup of distribution has not been ";
2160 warning_message +=
"tested with MPI.";
2167 warning_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2173 Restriction_self_test_vectors_storage[0].build(dist_pt);
2183 set_self_test_vector();
2186 restriction_self_test();
2191 Interpolation_self_test_vectors_storage[Nlevel - 1] =
2192 Restriction_self_test_vectors_storage[Nlevel - 1];
2195 interpolation_self_test();
2198 Restriction_self_test_vectors_storage.resize(0);
2201 Interpolation_self_test_vectors_storage.resize(0);
2205 double total_st_time = double(t_st_end - t_st_start);
2206 oomph_info <<
"\nCPU time for self-test [sec]: " << total_st_time
2210 oomph_info <<
"\n====================Self-Test Complete===================="
2218 template<
unsigned DIM>
2223 Mg_problem_pt->mg_bulk_mesh_pt();
2226 unsigned n_el = bulk_mesh_pt->
nelement();
2230 unsigned n_dim = bulk_mesh_pt->
node_pt(0)->
ndim();
2236 for (
unsigned e = 0;
e < n_el;
e++)
2242 for (
unsigned j = 0; j < nnod; j++)
2248 if (nod_pt->
nvalue() != 1)
2251 std::ostringstream error_stream;
2254 error_stream <<
"Sorry, not sure what to do here! I can't deal with "
2255 << nod_pt->
nvalue() <<
" values!" << std::endl;
2260 OOMPH_CURRENT_FUNCTION,
2261 OOMPH_EXCEPTION_LOCATION);
2271 double coordinate_sum = 0.0;
2274 for (
unsigned i = 0;
i < n_dim;
i++)
2277 coordinate_sum += nod_pt->
x(
i);
2284 Restriction_self_test_vectors_storage[0][eqn_num] =
2285 sin(pi * (nod_pt->
x(0))) * sin(pi * (nod_pt->
x(1)));
2306 template<
unsigned DIM>
2311 std::string outputfile =
"RESLT/restriction_self_test";
2314 for (
unsigned level = 0; level < Nlevel - 1; level++)
2317 Restriction_matrices_storage_pt[level]->multiply(
2318 Restriction_self_test_vectors_storage[level],
2319 Restriction_self_test_vectors_storage[level + 1]);
2323 for (
unsigned level = 0; level < Nlevel; level++)
2327 std::stringstream
string;
2329 filename +=
string.str();
2333 plot(level, Restriction_self_test_vectors_storage[level], filename);
2343 template<
unsigned DIM>
2348 std::string outputfile =
"RESLT/interpolation_self_test";
2351 for (
unsigned level = Nlevel - 1; level > 0; level--)
2354 Interpolation_matrices_storage_pt[level - 1]->multiply(
2355 Interpolation_self_test_vectors_storage[level],
2356 Interpolation_self_test_vectors_storage[level - 1]);
2359 for (
unsigned level = 0; level < Nlevel; level++)
2363 std::stringstream
string;
2365 filename +=
string.str();
2369 plot(level, Interpolation_self_test_vectors_storage[level], filename);
2378 template<
unsigned DIM>
2384 std::ofstream some_file;
2385 some_file.open(filename.c_str());
2389 Mg_hierarchy[hierarchy_level]->mg_bulk_mesh_pt();
2392 unsigned n_el = bulk_mesh_pt->
nelement();
2396 unsigned n_dim = bulk_mesh_pt->
node_pt(0)->
ndim();
2405 for (
unsigned e = 0;
e < n_el;
e++)
2415 for (
unsigned j = 0; j < nnod; j++)
2421 if (nod_pt->
nvalue() != 1)
2423 std::ostringstream error_stream;
2425 error_stream <<
"Sorry, not sure what to do here!" << nod_pt->
nvalue()
2429 error_stream <<
"The dimension is: " << n_dim << std::endl;
2432 for (
unsigned i = 0;
i < n_dim;
i++)
2434 error_stream << nod_pt->
x(
i) <<
" ";
2438 error_stream << std::endl;
2443 OOMPH_CURRENT_FUNCTION,
2444 OOMPH_EXCEPTION_LOCATION);
2448 for (
unsigned i = 0;
i < n_dim;
i++)
2450 some_file << nod_pt->
x(
i) <<
" ";
2458 some_file << input_vector[
e] << std::endl;
2466 if (hierarchy_level == 0)
2468 some_file << 0.0 << std::endl;
2474 some_file << input_vector[
e] << std::endl;
2482 double hang_sum = 0.0;
2487 unsigned nmaster = hang_info_pt->
nmaster();
2490 for (
unsigned i_master = 0; i_master < nmaster; i_master++)
2496 int master_jj = master_node_pt->
eqn_number(0);
2505 input_vector[master_jj];
2511 some_file << hang_sum << std::endl;
2524 template<
unsigned DIM>
2528 double t_mg_start = 0.0;
2529 if (!Suppress_v_cycle_output)
2536 unsigned finest_level = 0;
2539 V_cycle_counter = 0;
2542 double normalised_residual_norm = residual_norm(finest_level);
2543 if (!Suppress_v_cycle_output)
2545 oomph_info <<
"\nResidual on finest level for V-cycle: "
2546 << normalised_residual_norm << std::endl;
2553 while ((normalised_residual_norm > (this->Tolerance)) &&
2554 (V_cycle_counter != Nvcycle))
2556 if (!Suppress_v_cycle_output)
2559 oomph_info <<
"\nStarting V-cycle: " << V_cycle_counter << std::endl;
2564 for (
unsigned i = 0;
i < Nlevel - 1;
i++)
2572 X_mg_vectors_storage[
i].initialise(0.0);
2573 Residual_mg_vectors_storage[
i].initialise(0.0);
2582 restrict_residual(
i);
2593 for (
unsigned i = Nlevel - 1;
i > 0;
i--)
2597 interpolate_and_correct(
i);
2606 normalised_residual_norm = residual_norm(finest_level);
2610 if (Doc_convergence_history)
2612 if (!Output_file_stream.is_open())
2614 oomph_info << V_cycle_counter <<
" " << normalised_residual_norm
2619 Output_file_stream << V_cycle_counter <<
" "
2620 << normalised_residual_norm << std::endl;
2628 if (!Suppress_v_cycle_output)
2630 oomph_info <<
"Residual on finest level of V-cycle: "
2631 << normalised_residual_norm << std::endl;
2636 result = X_mg_vectors_storage[finest_level];
2639 if (!Suppress_v_cycle_output)
2645 if (!Suppress_all_output)
2648 if (normalised_residual_norm < (this->Tolerance))
2651 Has_been_solved =
true;
2656 if (!Suppress_v_cycle_output)
2660 double total_G_setup_time = double(t_mg_end - t_mg_start);
2661 oomph_info <<
"CPU time for MG solver [sec]: " << total_G_setup_time
A class for compressed row matrices. This is a distributable object.
int * row_start()
Access to C-style row_start array.
double * value()
Access to C-style value array.
unsigned long nrow() const
Return the number of rows of the matrix.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
unsigned nrow() const
access function to the number of global rows.
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 std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction")
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.
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
/////////////////////////////////////////////////////////////////////
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.
Base class for all linear iterative solvers. This merely defines standard interfaces for linear itera...
double Tolerance
Convergence tolerance.
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 clear()
clears the distribution
bool Doc_time
Boolean flag that indicates whether the time taken.
An interface to allow scalar MG to be used as a Preconditioner.
MGPreconditioner(const MGPreconditioner &)=delete
Broken copy constructor.
void setup()
Function to set up a preconditioner for the linear system.
MGPreconditioner(MGProblem *mg_problem_pt)
Constructor.
void operator=(const MGPreconditioner &)=delete
Broken assignment operator.
void clean_up_memory()
Clean up memory.
~MGPreconditioner()
Destructor (empty)
virtual void preconditioner_solve(const DoubleVector &rhs, DoubleVector &z)
Function applies MG to the vector r for a full solve.
MGProblem class; subclass of Problem.
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 ...
MGProblem()
Constructor. Initialise pointers to coarser and finer levels.
virtual MGProblem * make_new_problem()=0
This function needs to be implemented in the derived problem: Returns a pointer to a new object of th...
virtual ~MGProblem()
Destructor (empty)
/////////////////////////////////////////////////////// /////////////////////////////////////////////...
void set_self_test_vector()
Makes a vector which will be used in the self-test. Is currently set to make the entries of the vecto...
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. This is protected member data s...
void full_setup()
Do a full setup (assumes everything will be setup around the MGProblem pointer given in the construct...
Vector< DoubleVector > Rhs_mg_vectors_storage
Vector to store the RHS vectors (Rhs_mg). This is protected to allow the multigrid preconditioner to ...
void setup_mg_structures()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level.
void interpolation_self_test()
Make a self-test to make sure that the interpolation matrices are doing the same thing to interpolate...
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...
unsigned V_cycle_counter
Pointer to counter for V-cycles.
Vector< Smoother * > Post_smoothers_storage_pt
Vector to store the post-smoothers.
PostSmootherFactoryFctPt Post_smoother_factory_function_pt
Function to create post-smoothers.
Vector< DoubleVector > Residual_mg_vectors_storage
Vector to store the residual vectors.
bool Doc_everything
If this is set to true we document everything. In addition to outputting the information of the setup...
void setup_transfer_matrices()
Setup the transfer matrices on each level.
void enable_v_cycle_output()
Enable the output of the V-cycle timings and other output.
void setup_interpolation_matrices()
Setup the interpolation matrix on each level.
Smoother *(* PreSmootherFactoryFctPt)()
typedef for a function that returns a pointer to an object of the class Smoother to be used as the pr...
void post_smooth(const unsigned &level)
Post-smoother: Perform max_iter smoothing steps on the linear system Ax=b with current RHS vector,...
void set_post_smoother_factory_function(PostSmootherFactoryFctPt post_smoother_fn)
Access function to set the post-smoother creation function.
unsigned Nlevel
The number of levels in the multigrid heirachy.
void plot(const unsigned &hierarchy_level, const DoubleVector &input_vector, const std::string &filename)
Given a level in the hierarchy, an input vector and a filename this function will document the given ...
Vector< Smoother * > Pre_smoothers_storage_pt
Vector to store the pre-smoothers.
std::ostream * Stream_pt
Pointer to the output stream – defaults to std::cout. This is protected member data to allow the prec...
void set_restriction_matrices_as_interpolation_transposes()
Builds a CRDoubleMatrix on each level that is used to restrict the residual between levels....
MGSolver(MGProblem *mg_problem_pt)
Constructor: Set up default values for number of V-cycles and pre- and post-smoothing steps.
unsigned & max_iter()
Number of iterations.
void solve(Problem *const &problem_pt, DoubleVector &result)
Virtual function in the base class that needs to be implemented later but for now just leave it empty...
void mg_solve(DoubleVector &result)
Do the actual solve – this is called through the pure virtual solve function in the LinearSolver base...
void disable_output()
Suppress anything that can be suppressed, i.e. any timings. Things like mesh adaptation can not howev...
Smoother *(* PostSmootherFactoryFctPt)()
typedef for a function that returns a pointer to an object of the class Smoother to be used as the po...
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...
Vector< DoubleVector > Restriction_self_test_vectors_storage
Vector to store the result of restriction on each level (only required if the user wishes to document...
unsigned & npost_smooth()
Return the number of post-smoothing iterations (lvalue)
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...
void disable_smoother_and_superlu_doc_time()
Suppress the output of both smoothers and SuperLU.
void clean_up_memory()
Clean up anything that needs to be cleaned up.
void self_test()
Makes a vector, restricts it down the levels of the hierarchy and documents it at each level....
Vector< CRDoubleMatrix * > Restriction_matrices_storage_pt
Vector to store the restriction matrices.
void setup_mg_hierarchy()
Function to set up the hierachy of levels. Creates a vector of pointers to each MG level.
Vector< CRDoubleMatrix * > Mg_matrices_storage_pt
Vector to store the system matrices.
void setup_interpolation_matrices_unstructured()
Setup the interpolation matrix on each level (used for unstructured meshes)
void direct_solve()
Call the direct solver (SuperLU) to solve the problem exactly.
void setup_smoothers()
Function to set up all of the smoothers once the system matrices have been set up.
unsigned Npost_smooth
Number of post-smoothing steps.
void disable_v_cycle_output()
Disable all output from mg_solve apart from the number of V-cycles used to solve the problem.
~MGSolver()
Delete any dynamically allocated data.
unsigned Nvcycle
Maximum number of V-cycles (this is set as a protected variable so.
Vector< MGProblem * > Mg_hierarchy
Vector containing pointers to problems in hierarchy.
Vector< DoubleVector > Interpolation_self_test_vectors_storage
Vector to store the result of interpolation on each level (only required if the user wishes to docume...
Vector< CRDoubleMatrix * > Interpolation_matrices_storage_pt
Vector to store the interpolation matrices.
void enable_output()
Enable the output from anything that could have been suppressed.
void enable_doc_everything()
Enable the output from anything that could have been suppressed.
void pre_smooth(const unsigned &level)
Pre-smoother: Perform 'max_iter' smoothing steps on the linear system Ax=b with current RHS vector,...
bool Suppress_v_cycle_output
Indicates whether or not the V-cycle output should be suppressed. Needs to be protected member data f...
unsigned Npre_smooth
Number of pre-smoothing steps.
unsigned iterations() const
Number of iterations.
void restriction_self_test()
Make a self-test to make sure that the interpolation matrices are doing the same thing to restrict th...
unsigned & npre_smooth()
Return the number of pre-smoothing iterations (lvalue)
Vector< DoubleVector > X_mg_vectors_storage
Vector to store the solution vectors (X_mg)
void modify_restriction_matrices()
Normalise the rows of the restriction matrices to avoid amplifications when projecting to the coarser...
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...
void interpolate_and_correct(const unsigned &level)
Interpolate solution at current level onto next finer mesh and correct the solution x at that level.
double residual_norm(const unsigned &level)
Return norm of residual r=b-Ax and the residual vector itself on the level-th level.
bool Has_been_setup
Boolean variable to indicate whether or not the solver has been setup.
MGProblem * Mg_problem_pt
Pointer to the MG problem (deep copy). This is protected to provide access to the MG preconditioner.
bool Has_been_solved
Boolean variable to indicate whether or not the problem was successfully solved.
PreSmootherFactoryFctPt Pre_smoother_factory_function_pt
Function to create pre-smoothers.
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).
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...
virtual bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary,...
void position(Vector< double > &pos) const
Compute Vector of nodal positions either directly or via hanging node representation.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
bool is_hanging() const
Test whether the node is geometrically hanging.
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....
Preconditioner base class. Gives an interface to call all other preconditioners through and stores th...
////////////////////////////////////////////////////////////////// //////////////////////////////////...
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...
unsigned long ndof() const
Return the number of dofs.
virtual void actions_before_adapt()
Actions that are to be performed before a mesh adaptation. These might include removing any additiona...
Mesh *& mesh_pt()
Return a pointer to the global mesh.
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 ...
Base class for refineable meshes. Provides standardised interfaces for the following standard mesh ad...
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.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
const double Pi
50 digits from maple
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...