diff --git a/include/mfmg/dealii/amge_host.templates.hpp b/include/mfmg/dealii/amge_host.templates.hpp index 67afa589..adf65371 100644 --- a/include/mfmg/dealii/amge_host.templates.hpp +++ b/include/mfmg/dealii/amge_host.templates.hpp @@ -192,7 +192,8 @@ AMGe_host::compute_local_eigenvectors( { boost::property_tree::ptree lanczos_params; lanczos_params.put("num_eigenpairs", n_eigenvectors); - lanczos_params.put("tolerance", tolerance); + // lanczos_params.put("tolerance", tolerance); + lanczos_params.put("tolerance", 1e-6); lanczos_params.put("max_iterations", _eigensolver_params.get("max_iterations", 200)); lanczos_params.put("percent_overshoot", diff --git a/include/mfmg/dealii/dealii_utils.hpp b/include/mfmg/dealii/dealii_utils.hpp index e4c89201..15f5a4cf 100644 --- a/include/mfmg/dealii/dealii_utils.hpp +++ b/include/mfmg/dealii/dealii_utils.hpp @@ -79,6 +79,9 @@ void matrix_market_output_file( const std::string &filename, const dealii::TrilinosWrappers::SparseMatrix &matrix); +void matrix_market_output_file(const std::string &filename, + const dealii::SparseMatrix &matrix); + void matrix_market_output_file( const std::string &filename, const dealii::TrilinosWrappers::MPI::Vector &vector); diff --git a/include/mfmg/dealii/lanczos.hpp b/include/mfmg/dealii/lanczos.hpp index d2597081..9269b2a7 100644 --- a/include/mfmg/dealii/lanczos.hpp +++ b/include/mfmg/dealii/lanczos.hpp @@ -55,6 +55,11 @@ class Lanczos const int num_requested, double tol, std::vector const &evecs); + static bool + details_check_convergence_stupid(std::vector const &old_evals, + std::vector const &new_evals, + double tolerance); + static std::vector details_calc_evecs(const int num_requested, const int n, std::vector const &lanc_vectors, diff --git a/include/mfmg/dealii/lanczos.templates.hpp b/include/mfmg/dealii/lanczos.templates.hpp index 625e5446..76b9ab39 100644 --- a/include/mfmg/dealii/lanczos.templates.hpp +++ b/include/mfmg/dealii/lanczos.templates.hpp @@ -214,9 +214,19 @@ Lanczos::details_solve_lanczos( // Calculate eigenpairs of tridiagonal matrix for convergence test or at // last iteration - std::tie(evals, evecs_tridiag) = + std::vector iteration_evals; + std::tie(iteration_evals, evecs_tridiag) = details_calc_tridiag_epairs(t_maindiag, t_offdiag, num_requested); + // Stupid heuristic check + // Cause the regular may do "interesting" things when run long enough + if (evals.size() == num_requested && + details_check_convergence_stupid(evals, iteration_evals, tol)) + { + break; + } + evals = iteration_evals; + if (details_check_convergence(beta, dim_hessenberg, num_requested, tol, evecs_tridiag)) { @@ -241,7 +251,7 @@ Lanczos::details_solve_lanczos( evecs = details_calc_evecs(num_requested, it, lanc_vectors, evecs_tridiag); return std::make_tuple(evals, evecs); -} +} // namespace mfmg /// \brief Lanczos solver: calculate eigenpairs from tridiagonal of Lanczos /// coefficients @@ -323,6 +333,21 @@ bool Lanczos::details_check_convergence( return is_converged; } +/// \brief Lanczos solver: perform convergence check (stupid version) +template +bool Lanczos::details_check_convergence_stupid( + std::vector const &old_evals, std::vector const &new_evals, + double tolerance) +{ + ASSERT(old_evals.size() == new_evals.size(), "Size mismatch"); + + bool is_converged = false; + for (int i = 0; i < old_evals.size(); i++) + is_converged |= (std::abs(old_evals[i] / new_evals[i] - 1.0) < tolerance); + + return is_converged; +} + /// \brief Lanczos solver: calculate full (approx) eigenvectors from tridiag /// eigenvectors template diff --git a/source/dealii/dealii_utils.cc b/source/dealii/dealii_utils.cc index e4e4956f..5a3cf4db 100644 --- a/source/dealii/dealii_utils.cc +++ b/source/dealii/dealii_utils.cc @@ -70,6 +70,15 @@ void matrix_market_output_file( std::to_string(rv)); } +void matrix_market_output_file(const std::string &filename, + const dealii::SparseMatrix &matrix) +{ + dealii::TrilinosWrappers::SparseMatrix trilinos_matrix; + trilinos_matrix.reinit(matrix); + + matrix_market_output_file(filename, trilinos_matrix); +} + // TODO: write the map void matrix_market_output_file( const std::string &filename, diff --git a/tests/test_hierarchy.cc b/tests/test_hierarchy.cc index 011b8e29..c01c1ed6 100644 --- a/tests/test_hierarchy.cc +++ b/tests/test_hierarchy.cc @@ -73,9 +73,10 @@ double test(std::shared_ptr params) laplace._dof_handler, laplace._constraints, a, material_property); mfmg::Hierarchy hierarchy(comm, evaluator, params); - pcout << "Grid complexity : " << hierarchy.grid_complexity() << std::endl; - pcout << "Operator complexity: " << hierarchy.operator_complexity() - << std::endl; + // pcout << "Grid complexity : " << hierarchy.grid_complexity() << + // std::endl; pcout << "Operator complexity: " << + // hierarchy.operator_complexity() + // << std::endl; // We want to do 20 V-cycle iterations. The rhs of is zero. // Use D(istributed)Vector because deal has its own Vector class @@ -161,8 +162,9 @@ BOOST_DATA_TEST_CASE( bdata::make({"hyper_cube", "hyper_ball"}) * bdata::make({false, true}) * bdata::make({"None", "Reverse Cuthill_McKee"}) * bdata::make({"DealIIMeshEvaluator", - "DealIIMatrixFreeMeshEvaluator"}), - mesh, distort_random, reordering, mesh_evaluator_type) + "DealIIMatrixFreeMeshEvaluator"}) * + bdata::make({"lapack", "lanczos"}), + mesh, distort_random, reordering, mesh_evaluator_type, eigensolver) { // TODO investigate why there is large difference in convergence rate when // running in parallel. @@ -180,7 +182,7 @@ BOOST_DATA_TEST_CASE( params->put("smoother.type", "Chebyshev"); } - params->put("eigensolver.type", "lapack"); + params->put("eigensolver.type", eigensolver); params->put("agglomeration.nz", 2); params->put("laplace.n_refinements", 2); params->put("laplace.mesh", mesh); @@ -193,35 +195,51 @@ BOOST_DATA_TEST_CASE( // This is a gold standard test. Not the greatest but it makes sure we don't // break the code - std::map, double> ref_solution; - ref_solution[std::make_tuple("hyper_cube", false, "None")] = - is_matrix_free ? 0.1482630509 : 0.0491724046; - ref_solution[std::make_tuple("hyper_cube", false, - "Reverse Cuthill_McKee")] = - is_matrix_free ? 0.1482630509 : 0.0491724046; - ref_solution[std::make_tuple("hyper_cube", true, "None")] = - is_matrix_free ? 0.1575262224 : 0.0488984875; - ref_solution[std::make_tuple("hyper_cube", true, "Reverse Cuthill_McKee")] = - is_matrix_free ? 0.1575262224 : 0.0488984875; - ref_solution[std::make_tuple("hyper_ball", false, "None")] = - ref_solution[std::make_tuple("hyper_ball", false, - "Reverse Cuthill_McKee")] = - is_matrix_free ? 0.3022004744 : 0.1146629782; - ref_solution[std::make_tuple("hyper_ball", true, "None")] = - is_matrix_free ? 0.2977841482 : 0.1024334788; - ref_solution[std::make_tuple("hyper_ball", true, "Reverse Cuthill_McKee")] = - is_matrix_free ? 0.2977841482 : 0.1024334788; - - if (mesh == std::string("hyper_cube")) - BOOST_TEST( - conv_rate == - ref_solution[std::make_tuple(mesh, distort_random, reordering)], - tt::tolerance(1e-6)); - else - BOOST_TEST( - conv_rate == - ref_solution[std::make_tuple(mesh, distort_random, reordering)], - tt::tolerance(1e-6)); + // (geometry, distortion, reordering, eigensolver, matrix-free) + std::map, + double> + ref_solution; + // clang-format off + ref_solution[std::make_tuple("hyper_cube" , false , "None" , "lapack" , false)] = 0.0491724046; + ref_solution[std::make_tuple("hyper_cube" , false , "None" , "lapack" , true)] = 0.1482630509; + ref_solution[std::make_tuple("hyper_cube" , false , "Reverse Cuthill_McKee" , "lapack" , false)] = 0.0491724046; + ref_solution[std::make_tuple("hyper_cube" , false , "Reverse Cuthill_McKee" , "lapack" , true)] = 0.1482630509; + ref_solution[std::make_tuple("hyper_cube" , true , "None" , "lapack" , false)] = 0.0488984875; + ref_solution[std::make_tuple("hyper_cube" , true , "None" , "lapack" , true)] = 0.1575262224; + ref_solution[std::make_tuple("hyper_cube" , true , "Reverse Cuthill_McKee" , "lapack" , false)] = 0.0488984875; + ref_solution[std::make_tuple("hyper_cube" , true , "Reverse Cuthill_McKee" , "lapack" , true)] = 0.1575262224; + ref_solution[std::make_tuple("hyper_ball" , false , "None" , "lapack" , false)] = 0.1146629782; + ref_solution[std::make_tuple("hyper_ball" , false , "None" , "lapack" , true)] = 0.3022004744; + ref_solution[std::make_tuple("hyper_ball" , false , "Reverse Cuthill_McKee" , "lapack" , false)] = 0.1146629782; + ref_solution[std::make_tuple("hyper_ball" , false , "Reverse Cuthill_McKee" , "lapack" , true)] = 0.3022004744; + ref_solution[std::make_tuple("hyper_ball" , true , "None" , "lapack" , false)] = 0.1024334788; + ref_solution[std::make_tuple("hyper_ball" , true , "None" , "lapack" , true)] = 0.2977841482; + ref_solution[std::make_tuple("hyper_ball" , true , "Reverse Cuthill_McKee" , "lapack" , false)] = 0.1024334788; + ref_solution[std::make_tuple("hyper_ball" , true , "Reverse Cuthill_McKee" , "lapack" , true)] = 0.2977841482; + + ref_solution[std::make_tuple("hyper_cube" , false , "None" , "lanczos" , false)] = 0.0491724046; + ref_solution[std::make_tuple("hyper_cube" , false , "None" , "lanczos" , true)] = 0.1482630509; + ref_solution[std::make_tuple("hyper_cube" , false , "Reverse Cuthill_McKee" , "lanczos" , false)] = 0.0491724046; + ref_solution[std::make_tuple("hyper_cube" , false , "Reverse Cuthill_McKee" , "lanczos" , true)] = 0.1482630509; + ref_solution[std::make_tuple("hyper_cube" , true , "None" , "lanczos" , false)] = 0.0488968016; + ref_solution[std::make_tuple("hyper_cube" , true , "None" , "lanczos" , true)] = 0.1575200977; + ref_solution[std::make_tuple("hyper_cube" , true , "Reverse Cuthill_McKee" , "lanczos" , false)] = 0.0488968016; + ref_solution[std::make_tuple("hyper_cube" , true , "Reverse Cuthill_McKee" , "lanczos" , true)] = 0.1575200977; + ref_solution[std::make_tuple("hyper_ball" , false , "None" , "lanczos" , false)] = 0.0953745739; + ref_solution[std::make_tuple("hyper_ball" , false , "None" , "lanczos" , true)] = 0.3017812295; + ref_solution[std::make_tuple("hyper_ball" , false , "Reverse Cuthill_McKee" , "lanczos" , false)] = 0.0953745739; + ref_solution[std::make_tuple("hyper_ball" , false , "Reverse Cuthill_McKee" , "lanczos" , true)] = 0.3017812295; + ref_solution[std::make_tuple("hyper_ball" , true , "None" , "lanczos" , false)] = 0.0966058675; + ref_solution[std::make_tuple("hyper_ball" , true , "None" , "lanczos" , true)] = 0.2982453175; + ref_solution[std::make_tuple("hyper_ball" , true , "Reverse Cuthill_McKee" , "lanczos" , false)] = 0.0966058675; + ref_solution[std::make_tuple("hyper_ball" , true , "Reverse Cuthill_McKee" , "lanczos" , true)] = 0.2982453175; + // clang-format on + + BOOST_TEST( + conv_rate == + ref_solution[std::make_tuple(mesh, distort_random, reordering, + eigensolver, is_matrix_free)], + tt::tolerance(1e-6)); } } diff --git a/tests/test_restriction_matrix.cc b/tests/test_restriction_matrix.cc index 6e373dd2..8ba8c63e 100644 --- a/tests/test_restriction_matrix.cc +++ b/tests/test_restriction_matrix.cc @@ -21,6 +21,7 @@ #include #include +#include #include @@ -28,6 +29,8 @@ #include "main.cc" namespace utf = boost::unit_test; +namespace bdata = boost::unit_test::data; +namespace tt = boost::test_tools; template class DummyMeshEvaluator : public mfmg::DealIIMeshEvaluator @@ -279,7 +282,8 @@ class TestMeshEvaluator : public mfmg::DealIIMeshEvaluator // FIXME relaxed tolerance from 1e-14 to 1e-4 for this test to pass while using // ARPACK's regular mode instead of shift-and-invert -BOOST_AUTO_TEST_CASE(weight_sum, *utf::tolerance(1e-4)) +BOOST_DATA_TEST_CASE(weight_sum, bdata::make({"lapack", "lanczos"}), + eigensolver) { // Check that the weight sum is equal to one unsigned int constexpr dim = 2; @@ -295,6 +299,7 @@ BOOST_AUTO_TEST_CASE(weight_sum, *utf::tolerance(1e-4)) auto params = std::make_shared(); boost::property_tree::info_parser::read_info("hierarchy_input.info", *params); + params->put("eigensolver.type", eigensolver); params->put("eigensolver.number of eigenvectors", 1); auto agglomerate_ptree = params->get_child("agglomeration"); int n_eigenvectors = @@ -311,7 +316,8 @@ BOOST_AUTO_TEST_CASE(weight_sum, *utf::tolerance(1e-4)) TestMeshEvaluator evaluator(laplace._dof_handler, laplace._constraints, laplace._system_matrix); - mfmg::AMGe_host amge(comm, laplace._dof_handler); + mfmg::AMGe_host amge( + comm, laplace._dof_handler, params->get_child("eigensolver")); auto locally_relevant_global_diag = evaluator.get_diagonal(); @@ -334,6 +340,6 @@ BOOST_AUTO_TEST_CASE(weight_sum, *utf::tolerance(1e-4)) e[i] = 1.; e.compress(::dealii::VectorOperation::insert); restrictor_matrix.vmult(ee, e); - BOOST_TEST(ee.l1_norm() == 1.); + BOOST_TEST(ee.l1_norm() == 1., tt::tolerance(1e-4)); } }