diff --git a/src/amdis/linearalgebra/istl/AMGPrecon.hpp b/src/amdis/linearalgebra/istl/AMGPrecon.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b282f5efd0da8dce98aef3c7e1334384b4e7c963 --- /dev/null +++ b/src/amdis/linearalgebra/istl/AMGPrecon.hpp @@ -0,0 +1,206 @@ +#pragma once + +#include <dune/istl/paamg/amg.hh> +#include <dune/istl/paamg/fastamg.hh> + +#include <amdis/linearalgebra/istl/ISTLPreconCreatorInterface.hpp> + +namespace AMDiS +{ + template <template <class...> class AMGSolver, class Mat, class Sol, class Rhs> + struct AMGTraits; + + template <class Mat, class Sol, class Rhs> + struct AMGTraits<Dune::Amg::AMG, Mat, Sol, Rhs> + { + using Operator = Dune::MatrixAdapter<Mat, Sol, Rhs>; + + template <class Smoother> + using Solver = Dune::Amg::AMG<Operator, Sol, Smoother>; + + template <class Smoother, class Criterion, class SmootherArgs> + static auto create(Operator const& fineOperator, Criterion const& criterion, SmootherArgs const& smootherArgs) + { + return std::make_unique<Solver<Smoother>>(fineOperator, criterion, smootherArgs); + } + }; + + template <class Mat, class Sol, class Rhs> + struct AMGTraits<Dune::Amg::FastAMG, Mat, Sol, Rhs> + { + using Operator = Dune::MatrixAdapter<Mat, Sol, Rhs>; + + template <class> + using Solver = Dune::Amg::FastAMG<Operator, Sol>; + + template <class Smoother, class Criterion, class SmootherArgs> + static auto create(Operator const& fineOperator, Criterion const& criterion, SmootherArgs const& /*smootherArgs*/) + { + return std::make_unique<Solver<Smoother>>(fineOperator, criterion, criterion); + } + }; + + + template <class Traits, class Smoother, class Mat, class Sol, class Rhs> + class AMGPrecon; + + template <template <class...> class AMGSolver, class Mat, class Sol, class Rhs> + class AMGPreconCreator + : public CreatorInterfaceName<ISTLPreconCreatorInterface<Mat, Sol, Rhs>> + { + using PreconCreatorBase = ISTLPreconCreatorInterface<Mat, Sol, Rhs>; + using Traits = AMGTraits<AMGSolver,Mat,Sol,Rhs>; + + template <class Smoother> + using Precon = AMGPrecon<Traits, Smoother, Mat, Sol, Rhs>; + + public: + std::unique_ptr<PreconCreatorBase> createWithString(std::string prefix) override + { + // get creator string for preconditioner + std::string smoother = "no"; + Parameters::get(prefix + "->smoother", smoother); + + if (smoother == "diag" || + smoother == "jacobi") + { + auto creator = typename Precon<Dune::SeqJac<Mat, Sol, Rhs>>::Creator{}; + return creator.createWithString(prefix); + } + // else if (smoother == "gs" || + // smoother == "hauss_seidel") + // { + // auto creator = typename Precon<Dune::SeqGS<Mat, Sol, Rhs>>::Creator{}; + // return creator.createWithString(prefix); + // } + else if (smoother == "sor") + { + auto creator = typename Precon<Dune::SeqSOR<Mat, Sol, Rhs>>::Creator{}; + return creator.createWithString(prefix); + } + else if (smoother == "ssor") { + auto creator = typename Precon<Dune::SeqSSOR<Mat, Sol, Rhs>>::Creator{}; + return creator.createWithString(prefix); + } + // else if (smoother == "richardson" || + // smoother == "default") { + // auto creator = typename Precon<Dune::Richardson<Sol, Rhs>>::Creator{}; + // return creator.createWithString(prefix); + // } + else { + error_exit("Unknown smoother type '{}' given for parameter '{}'", smoother, prefix + "->smoother"); + return nullptr; + } + } + }; + + + template <class Traits, class Smoother, class Mat, class Sol, class Rhs> + class AMGPrecon + : public ISTLPreconCreatorInterface<Mat, Sol, Rhs> + { + using Super = ISTLPreconCreatorInterface<Mat, Sol, Rhs>; + using Self = AMGPrecon; + + using PreconBase = Dune::Preconditioner<Sol, Rhs>; + + using LinOperator = typename Traits::Operator; + using SmootherArgs = typename Dune::Amg::SmootherTraits<Smoother>::Arguments; + + using Norm = std::conditional_t<std::is_arithmetic<typename Dune::FieldTraits<Mat>::field_type>::value, + Dune::Amg::FirstDiagonal, Dune::Amg::RowSum>; + // TODO: make criterion flexible + using Criterion = Dune::Amg::CoarsenCriterion<Dune::Amg::UnSymmetricCriterion<Mat,Norm>>; + + public: + struct Creator : CreatorInterfaceName<Super> + { + std::unique_ptr<Super> createWithString(std::string prefix) override + { + return std::make_unique<Self>(prefix); + } + }; + + AMGPrecon(std::string const& prefix) + { + initParameters(prefix); + } + + /// Implementes \ref ISTLPreconCreatorInterface::create + std::unique_ptr<PreconBase> create(Mat const& A) const override + { + linOperator_ = std::make_shared<LinOperator>(A); + criterion_ = std::make_shared<Criterion>(parameters_); + + return Traits::template create<Smoother>(*linOperator_, *criterion_, smootherArgs_); + } + + protected: + void initParameters(std::string const& prefix) + { + // The debugging level. If 0 no debugging output will be generated. + parameters_.setDebugLevel(Parameters::get<int>(prefix + "->debugLevel").value_or(2)); + // The number of presmoothing steps to apply + parameters_.setNoPreSmoothSteps(Parameters::get<std::size_t>(prefix + "->preSmoothSteps").value_or(2)); + // The number of postsmoothing steps to apply + parameters_.setNoPostSmoothSteps(Parameters::get<std::size_t>(prefix + "->postSmoothSteps").value_or(2)); + // Value of gamma; 1 for V-cycle, 2 for W-cycle + parameters_.setGamma(Parameters::get<std::size_t>(prefix + "->gamma").value_or(1)); + // Whether to use additive multigrid. + parameters_.setAdditive(Parameters::get<bool>(prefix + "->additive").value_or(false)); + + initCoarseningParameters(prefix + "->coarsening"); + initAggregationParameters(prefix + "->aggregation"); + initDependencyParameters(prefix + "->dependency"); + initSmootherParameters(prefix + "->smoother"); + } + + void initCoarseningParameters(std::string const& prefix) + { + // The maximum number of levels allowed in the hierarchy. + parameters_.setMaxLevel(Parameters::get<int>(prefix + "->maxLevel").value_or(100)); + // The maximum number of unknowns allowed on the coarsest level. + parameters_.setCoarsenTarget(Parameters::get<int>(prefix + "->coarsenTarget").value_or(1000)); + // The minimum coarsening rate to be achieved. + parameters_.setMinCoarsenRate(Parameters::get<double>(prefix + "->minCoarsenRate").value_or(1.2)); + // The damping factor to apply to the prologated correction. + parameters_.setProlongationDampingFactor(Parameters::get<double>(prefix + "->dampingFactor").value_or(1.6)); + } + + void initAggregationParameters(std::string const& prefix) + { + // Tthe maximal distance allowed between to nodes in a aggregate. + parameters_.setMaxDistance(Parameters::get<std::size_t>(prefix + "->maxDistance").value_or(2)); + // The minimum number of nodes a aggregate has to consist of. + parameters_.setMinAggregateSize(Parameters::get<std::size_t>(prefix + "->minAggregateSize").value_or(4)); + // The maximum number of nodes a aggregate is allowed to have. + parameters_.setMaxAggregateSize(Parameters::get<std::size_t>(prefix + "->maxAggregateSize").value_or(6)); + // The maximum number of connections a aggregate is allowed to have. + parameters_.setMaxConnectivity(Parameters::get<std::size_t>(prefix + "->maxConnectivity").value_or(15)); + // The maximum number of connections a aggregate is allowed to have. + parameters_.setSkipIsolated(Parameters::get<bool>(prefix + "->skipIsolated").value_or(false)); + } + + void initDependencyParameters(std::string const& prefix) + { + // The scaling value for marking connections as strong. + parameters_.setAlpha(Parameters::get<double>(prefix + "->alpha").value_or(1.0/3.0)); + // The threshold for marking nodes as isolated. + parameters_.setBeta(Parameters::get<double>(prefix + "->beta").value_or(1.e-5)); + } + + void initSmootherParameters(std::string const& prefix) + { + Parameters::get(prefix + "->iterations", smootherArgs_.iterations); + Parameters::get(prefix + "->relaxationFactor", smootherArgs_.relaxationFactor); + } + + private: + SmootherArgs smootherArgs_; + Dune::Amg::Parameters parameters_; + + mutable std::shared_ptr<Criterion> criterion_; + mutable std::shared_ptr<LinOperator> linOperator_; + }; + +} // end namespace AMDiS diff --git a/src/amdis/linearalgebra/istl/ISTLPreconCreatorInterface.hpp b/src/amdis/linearalgebra/istl/ISTLPreconCreatorInterface.hpp new file mode 100644 index 0000000000000000000000000000000000000000..29c5446b95168fec8fb65d97407019dde34a99fb --- /dev/null +++ b/src/amdis/linearalgebra/istl/ISTLPreconCreatorInterface.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <memory> + +#include <dune/istl/preconditioners.hh> + +namespace AMDiS +{ + template <class Mat, class Sol, class Rhs> + struct ISTLPreconCreatorInterface + { + virtual ~ISTLPreconCreatorInterface() = default; + + using PreconBase = Dune::Preconditioner<Sol, Rhs>; + virtual std::unique_ptr<PreconBase> create(Mat const& matrix) const = 0; + }; + +} // end namespace AMDiS \ No newline at end of file diff --git a/src/amdis/linearalgebra/istl/ISTLRunner.hpp b/src/amdis/linearalgebra/istl/ISTLRunner.hpp index e49d6a260de3a8ecfed90064bf22910a5e51130b..24df9b9b1d2227aabfb9951b25df13358b7f315e 100644 --- a/src/amdis/linearalgebra/istl/ISTLRunner.hpp +++ b/src/amdis/linearalgebra/istl/ISTLRunner.hpp @@ -5,7 +5,7 @@ #include <amdis/linearalgebra/RunnerInterface.hpp> #include <amdis/linearalgebra/SolverInfo.hpp> #include <amdis/linearalgebra/istl/Fwd.hpp> -#include <amdis/linearalgebra/istl/ISTL_Preconditioner.hpp> +#include <amdis/linearalgebra/istl/ISTLPreconCreatorInterface.hpp> namespace AMDiS { @@ -16,7 +16,7 @@ namespace AMDiS using LinOperator = Dune::MatrixAdapter<Matrix, VectorX, VectorB>; using BaseSolver = Dune::InverseOperator<VectorX, VectorB>; using BasePrecon = Dune::Preconditioner<VectorX, VectorB>; - using ISTLPrecon = ISTLPreconInterface<Matrix, VectorX, VectorB>; + using ISTLPreconCreator = ISTLPreconCreatorInterface<Matrix, VectorX, VectorB>; public: ISTLRunner(std::string const& prefix) @@ -64,10 +64,10 @@ namespace AMDiS // get creator string for preconditioner std::string preconName = "no"; std::string initFileStr = ""; - for (std::string postfix : {"left precon", "right precon", "precon->name"}) { + for (std::string postfix : {"left precon", "right precon", "precon", "precon->name"}) { Parameters::get(prefix + "->" + postfix, preconName); if (!preconName.empty() && preconName != "no") { - initFileStr = prefix + "->" + postfix; + initFileStr = postfix == "precon->name" ? prefix + "->precon" : prefix + "->" + postfix; break; } } @@ -75,14 +75,14 @@ namespace AMDiS if (preconName.empty() || preconName == "no") preconName = "default"; - auto* creator = named(CreatorMap<ISTLPrecon>::getCreator(preconName, initFileStr)); + auto* creator = named(CreatorMap<ISTLPreconCreator>::getCreator(preconName, initFileStr)); preconCreator_ = creator->createWithString(initFileStr); assert(preconCreator_); } private: ISTLSolverCreator<ISTLSolver> solverCreator_; - std::shared_ptr<ISTLPrecon> preconCreator_; + std::shared_ptr<ISTLPreconCreator> preconCreator_; std::shared_ptr<BasePrecon> precon_; std::shared_ptr<LinOperator> linOperator_; diff --git a/src/amdis/linearalgebra/istl/ISTL_Preconditioner.hpp b/src/amdis/linearalgebra/istl/ISTL_Preconditioner.hpp index d33bfa148bdb065abfb6e5a20c8c640007bbe461..923e1d006de12e9819af378e41d04fc00087ead9 100644 --- a/src/amdis/linearalgebra/istl/ISTL_Preconditioner.hpp +++ b/src/amdis/linearalgebra/istl/ISTL_Preconditioner.hpp @@ -3,30 +3,25 @@ #include <dune/istl/preconditioners.hh> #include <amdis/CreatorInterface.hpp> +#include <amdis/linearalgebra/istl/AMGPrecon.hpp> +#include <amdis/linearalgebra/istl/Fwd.hpp> +#include <amdis/linearalgebra/istl/ISTLPreconCreatorInterface.hpp> namespace AMDiS { - template <class Matrix, class VectorX, class VectorB> - struct ISTLPreconInterface - { - virtual ~ISTLPreconInterface() = default; - using PreconBase = Dune::Preconditioner<VectorX, VectorB>; - virtual std::unique_ptr<PreconBase> create(Matrix const& matrix) const = 0; - }; - template <class> struct Type {}; // creators for preconditioners, depending on matrix-type // --------------------------------------------------------------------------- template <class Precon, class Matrix> - struct ISTLPrecon - : public ISTLPreconInterface<Matrix, typename Precon::domain_type, typename Precon::range_type> + struct ISTLPreconCreator + : public ISTLPreconCreatorInterface<Matrix, typename Precon::domain_type, typename Precon::range_type> { - using VectorX = typename Precon::domain_type; - using VectorB = typename Precon::range_type; - using Super = ISTLPreconInterface<Matrix, VectorX, VectorB>; - using Self = ISTLPrecon; + using Sol = typename Precon::domain_type; + using Rhs = typename Precon::range_type; + using Super = ISTLPreconCreatorInterface<Matrix, Sol, Rhs>; + using Self = ISTLPreconCreator; struct Creator : CreatorInterfaceName<Super> { @@ -36,13 +31,13 @@ namespace AMDiS } }; - ISTLPrecon(std::string const& prefix) + ISTLPreconCreator(std::string const& prefix) { Parameters::get(prefix + "->relaxation", w_); Parameters::get(prefix + "->iterations", iter_); } - using PreconBase = Dune::Preconditioner<VectorX, VectorB>; + using PreconBase = Dune::Preconditioner<Sol, Rhs>; std::unique_ptr<PreconBase> create(Matrix const& A) const override { return createImpl(A, Type<Precon>{}); @@ -55,16 +50,16 @@ namespace AMDiS return std::make_unique<P>(A, iter_, w_); } - std::unique_ptr<Dune::SeqILU<Matrix, VectorX, VectorB>> - createImpl(Matrix const& A, Type<Dune::SeqILU<Matrix, VectorX, VectorB>>) const + std::unique_ptr<Dune::SeqILU<Matrix, Sol, Rhs>> + createImpl(Matrix const& A, Type<Dune::SeqILU<Matrix, Sol, Rhs>>) const { - return std::make_unique<Dune::SeqILU<Matrix, VectorX, VectorB>>(A, iter_, w_); + return std::make_unique<Dune::SeqILU<Matrix, Sol, Rhs>>(A, iter_, w_); } - std::unique_ptr<Dune::Richardson<VectorX, VectorB>> - createImpl(Matrix const& /*A*/, Type<Dune::Richardson<VectorX, VectorB>>) const + std::unique_ptr<Dune::Richardson<Sol, Rhs>> + createImpl(Matrix const& /*A*/, Type<Dune::Richardson<Sol, Rhs>>) const { - return std::make_unique<Dune::Richardson<VectorX, VectorB>>(w_); + return std::make_unique<Dune::Richardson<Sol, Rhs>>(w_); } double w_ = 1.0; @@ -81,37 +76,42 @@ namespace AMDiS * - *gmres*: Generalized minimal residula method, \see Dune::RestartedGMResSolver * - *umfpack*: external UMFPACK solver, \see Dune::UMFPack **/ - template <class Matrix, class VectorX, class VectorB> - class DefaultCreators<ISTLPreconInterface<Matrix, VectorX, VectorB>> + template <class Mat, class Sol, class Rhs> + class DefaultCreators<ISTLPreconCreatorInterface<Mat, Sol, Rhs>> { template <class Precon> using PreconCreator - = typename ISTLPrecon<Precon, Matrix>::Creator; + = typename ISTLPreconCreator<Precon, Mat>::Creator; - using Map = CreatorMap<ISTLPreconInterface<Matrix, VectorX, VectorB>>; + using Map = CreatorMap<ISTLPreconCreatorInterface<Mat, Sol, Rhs>>; public: static void init() { - auto jacobi = new PreconCreator<Dune::SeqJac<Matrix, VectorX, VectorB>>; + auto jacobi = new PreconCreator<Dune::SeqJac<Mat, Sol, Rhs>>; Map::addCreator("diag", jacobi); Map::addCreator("jacobi", jacobi); - auto gs = new PreconCreator<Dune::SeqGS<Matrix, VectorX, VectorB>>; + auto gs = new PreconCreator<Dune::SeqGS<Mat, Sol, Rhs>>; Map::addCreator("gs", gs); Map::addCreator("gauss_seidel", gs); - auto sor = new PreconCreator<Dune::SeqSOR<Matrix, VectorX, VectorB>>; + auto sor = new PreconCreator<Dune::SeqSOR<Mat, Sol, Rhs>>; Map::addCreator("sor", sor); - auto ssor = new PreconCreator<Dune::SeqSSOR<Matrix, VectorX, VectorB>>; + auto ssor = new PreconCreator<Dune::SeqSSOR<Mat, Sol, Rhs>>; Map::addCreator("ssor", ssor); - auto ilu = new PreconCreator<Dune::SeqILU<Matrix, VectorX, VectorB>>; + auto ilu = new PreconCreator<Dune::SeqILU<Mat, Sol, Rhs>>; Map::addCreator("ilu", ilu); Map::addCreator("ilu0", ilu); - auto richardson = new PreconCreator<Dune::Richardson<VectorX, VectorB>>; + auto amg = new AMGPreconCreator<Dune::Amg::AMG, Mat, Sol, Rhs>; + Map::addCreator("amg", amg); + auto fastamg = new AMGPreconCreator<Dune::Amg::FastAMG, Mat, Sol, Rhs>; + Map::addCreator("fastamg", fastamg); + + auto richardson = new PreconCreator<Dune::Richardson<Sol, Rhs>>; Map::addCreator("richardson", richardson); Map::addCreator("default", richardson); }