From b60572ac3ddfcbd83b4e793d5d8fc782f8548793 Mon Sep 17 00:00:00 2001 From: Nils-Arne Dreier <n.dreier@uni-muenster.de> Date: Mon, 13 Sep 2021 14:49:46 +0200 Subject: [PATCH] simplify and cleanup solverfactory --- dune/istl/cholmod.hh | 28 ++-- dune/istl/common/registry.hh | 2 +- dune/istl/ldl.hh | 26 ++-- dune/istl/paamg/amg.hh | 28 ++-- dune/istl/preconditioners.hh | 11 +- dune/istl/solverfactory.hh | 251 ++++++++++++++--------------------- dune/istl/solverregistry.hh | 75 ++++++----- dune/istl/solvers.hh | 20 +-- dune/istl/spqr.hh | 25 ++-- dune/istl/superlu.hh | 25 ++-- dune/istl/umfpack.hh | 36 +++-- 11 files changed, 250 insertions(+), 277 deletions(-) diff --git a/dune/istl/cholmod.hh b/dune/istl/cholmod.hh index 87c29eb69..836584f8d 100644 --- a/dune/istl/cholmod.hh +++ b/dune/istl/cholmod.hh @@ -11,7 +11,7 @@ #include <dune/istl/bcrsmatrix.hh> #include <dune/istl/bvector.hh> #include<dune/istl/solver.hh> -#include <dune/istl/solverfactory.hh> +#include <dune/istl/solverregistry.hh> #include <dune/istl/foreach.hh> #include <vector> @@ -529,29 +529,31 @@ private: template<int k> struct isValidBlock<FieldVector<double,k>> : std::true_type{}; template<int k> struct isValidBlock<FieldVector<float,k>> : std::true_type{}; - template<class TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator()(TL /*tl*/, const M& mat, const Dune::ParameterTree& /*config*/, - std::enable_if_t<isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + template<class OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator()(OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& /*config*/, + std::enable_if_t<isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { - using D = typename Dune::TypeListElement<1, TL>::type; + using D = typename OpTraits::domain_type; + using M = typename OpTraits::matrix_type; + const M& mat = opTraits.getMatOrThrow(op); auto solver = std::make_shared<Dune::Cholmod<D>>(); solver->setMatrix(mat); return solver; } // second version with SFINAE to validate the template parameters of Cholmod - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& /*mat*/, const Dune::ParameterTree& /*config*/, - std::enable_if_t<!isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + template<class OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator()(OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& /*config*/, + std::enable_if_t<!isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { DUNE_THROW(UnsupportedType, "Unsupported Type in Cholmod"); } }; - DUNE_REGISTER_DIRECT_SOLVER("cholmod", Dune::CholmodCreator()); + DUNE_REGISTER_SOLVER("cholmod", Dune::CholmodCreator()); } /* namespace Dune */ diff --git a/dune/istl/common/registry.hh b/dune/istl/common/registry.hh index 33ddee83d..54dc9a296 100644 --- a/dune/istl/common/registry.hh +++ b/dune/istl/common/registry.hh @@ -53,7 +53,7 @@ namespace Dune { } /* - Register all creators from the registry in the Parameterizedobjectfactory An + Register all creators from the registry in the Parameterizedobjectfactory. An object of V is passed in the creator and should be used to determine the template arguments. */ diff --git a/dune/istl/ldl.hh b/dune/istl/ldl.hh index 0c2ed6bab..5e6de06b0 100644 --- a/dune/istl/ldl.hh +++ b/dune/istl/ldl.hh @@ -24,7 +24,7 @@ extern "C" #include <dune/istl/bccsmatrixinitializer.hh> #include <dune/istl/solvers.hh> #include <dune/istl/solvertype.hh> -#include <dune/istl/solverfactory.hh> +#include <dune/istl/solverregistry.hh> namespace Dune { /** @@ -374,30 +374,32 @@ namespace Dune { template<class F> struct isValidBlock : std::false_type{}; template<int k> struct isValidBlock<FieldVector<double,k>> : std::true_type{}; - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& mat, const Dune::ParameterTree& config, + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, std::enable_if_t< - isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { + using M = typename OpTraits::matrix_type; + const M& mat = opTraits.getMatOrThrow(op); int verbose = config.get("verbose", 0); return std::make_shared<Dune::LDL<M>>(mat,verbose); } // second version with SFINAE to validate the template parameters of LDL - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& /*mat*/, const Dune::ParameterTree& /*config*/, + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, std::enable_if_t< - !isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + !isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { DUNE_THROW(UnsupportedType, "Unsupported Type in LDL (only double and std::complex<double> supported)"); } }; - DUNE_REGISTER_DIRECT_SOLVER("ldl", Dune::LDLCreator()); + DUNE_REGISTER_SOLVER("ldl", Dune::LDLCreator()); } // end namespace Dune diff --git a/dune/istl/paamg/amg.hh b/dune/istl/paamg/amg.hh index 8cb6aa374..dcac8e745 100644 --- a/dune/istl/paamg/amg.hh +++ b/dune/istl/paamg/amg.hh @@ -16,6 +16,7 @@ #include <dune/istl/superlu.hh> #include <dune/istl/umfpack.hh> #include <dune/istl/solvertype.hh> +#include <dune/istl/solverregistry.hh> #include <dune/common/typetraits.hh> #include <dune/common/exceptions.hh> #include <dune/common/scalarvectorview.hh> @@ -1242,13 +1243,13 @@ namespace Dune DUNE_THROW(Dune::Exception, "Unknown smoother for AMG"); } - template<typename TL, typename OP> - std::shared_ptr<Dune::Preconditioner<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL tl, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, - std::enable_if_t<isValidBlockType<typename OP::matrix_type::block_type>::value,int> = 0) const + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::Preconditioner<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, + std::enable_if_t<isValidBlockType<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { - using field_type = typename OP::matrix_type::field_type; + using field_type = typename OpTraits::matrix_type::field_type; using real_type = typename FieldTraits<field_type>::real_type; if (!std::is_convertible<field_type, real_type>()) DUNE_THROW(UnsupportedType, "AMG needs field_type(" << @@ -1257,14 +1258,19 @@ namespace Dune className<real_type>() << ")."); std::string smoother = config.get("smoother", "ssor"); + // we can irgnore the OpTraits here. As the AMG can only work + // with actual matrices, the operator op must be of type + // MatrixAdapter or *SchwarzOperator. In any case these + // operators provide all necessary information about matrix, + // domain and range type return makeAMG(op, smoother, config); } - template<typename TL, typename OP> - std::shared_ptr<Dune::Preconditioner<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const std::shared_ptr<OP>& /*mat*/, const Dune::ParameterTree& /*config*/, - std::enable_if_t<!isValidBlockType<typename OP::matrix_type::block_type>::value,int> = 0) const + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::Preconditioner<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, + std::enable_if_t<!isValidBlockType<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { DUNE_THROW(UnsupportedType, "AMG needs a FieldMatrix as Matrix block_type"); } diff --git a/dune/istl/preconditioners.hh b/dune/istl/preconditioners.hh index edacb143d..f62daa81d 100644 --- a/dune/istl/preconditioners.hh +++ b/dune/istl/preconditioners.hh @@ -949,11 +949,12 @@ namespace Dune { //! \brief The relaxation factor to use. real_field_type _w; }; - DUNE_REGISTER_PRECONDITIONER("richardson", [](auto tl, const auto& /* mat */, const ParameterTree& config){ - using D = typename Dune::TypeListElement<1, decltype(tl)>::type; - using R = typename Dune::TypeListElement<2, decltype(tl)>::type; - return std::make_shared<Richardson<D,R>>(config); - }); + DUNE_REGISTER_PRECONDITIONER("richardson", [](auto opTraits, const auto& op, const ParameterTree& config){ + using OpTraits = std::decay_t<decltype(opTraits)>; + using D = typename OpTraits::domain_type; + using R = typename OpTraits::range_type; + return std::make_shared<Richardson<D,R>>(config); + }); /** diff --git a/dune/istl/solverfactory.hh b/dune/istl/solverfactory.hh index ba05aed95..3f6a5364b 100644 --- a/dune/istl/solverfactory.hh +++ b/dune/istl/solverfactory.hh @@ -11,9 +11,12 @@ #include <memory> #include <dune/common/parametertree.hh> +#include <dune/common/std/type_traits.hh> #include <dune/common/singleton.hh> +#include <dune/common/parameterizedobject.hh> -#include "solverregistry.hh" +#include <dune/istl/solverregistry.hh> +#include <dune/istl/common/registry.hh> #include <dune/istl/solver.hh> #include <dune/istl/schwarz.hh> #include <dune/istl/novlpschwarz.hh> @@ -23,92 +26,88 @@ namespace Dune{ @{ */ - // Direct solver factory: - template<class M, class X, class Y> - using DirectSolverSignature = std::shared_ptr<InverseOperator<X,Y>>(const M&, const ParameterTree&); - template<class M, class X, class Y> - using DirectSolverFactory = Singleton<ParameterizedObjectFactory<DirectSolverSignature<M,X,Y>>>; - // Preconditioner factory: - template<class M, class X, class Y> - using PreconditionerSignature = std::shared_ptr<Preconditioner<X,Y>>(const std::shared_ptr<M>&, const ParameterTree&); - template<class M, class X, class Y> - using PreconditionerFactory = Singleton<ParameterizedObjectFactory<PreconditionerSignature<M,X,Y>>>; + template<class OP> + using PreconditionerSignature = std::shared_ptr<Preconditioner<typename OP::domain_type,typename OP::range_type>>(const std::shared_ptr<OP>&, const ParameterTree&); + template<class OP> + using PreconditionerFactory = Singleton<ParameterizedObjectFactory<PreconditionerSignature<OP>>>; // Iterative solver factory - template<class X, class Y> - using IterativeSolverSignature = std::shared_ptr<InverseOperator<X,Y>>(const std::shared_ptr<LinearOperator<X,Y>>&, const std::shared_ptr<ScalarProduct<X>>&, const std::shared_ptr<Preconditioner<X,Y>>, const ParameterTree&); - template<class X, class Y> - using IterativeSolverFactory = Singleton<ParameterizedObjectFactory<IterativeSolverSignature<X,Y>>>; + template<class OP> + using SolverSignature = std::shared_ptr<InverseOperator<typename OP::domain_type,typename OP::range_type>>(const std::shared_ptr<OP>&, const ParameterTree&); + template<class OP> + using SolverFactory = Singleton<ParameterizedObjectFactory<SolverSignature<OP>>>; + + class NoAssembledOperator : public InvalidStateException{}; + + template<class Operator> + struct OperatorTraits{ + private: + template<class O> + using _matrix_type = typename O::matrix_type; + template<class O> + using _comm_type = typename O::communication_type; + public: + using domain_type = typename Operator::domain_type; + using range_type = typename Operator::range_type; + using operator_type = Operator; + using matrix_type = Std::detected_or_t<int, _matrix_type, Operator>; + static constexpr bool isAssembled = !std::is_same<matrix_type, int>::value; + using comm_type = Std::detected_or_t<int, _comm_type, Operator>; + static constexpr bool isParallel = !std::is_same<comm_type, int>::value; + + static const matrix_type& getMatOrThrow(std::shared_ptr<LinearOperator<domain_type, range_type>> op){ + std::shared_ptr<AssembledLinearOperator<matrix_type, domain_type, range_type>> aop + = std::dynamic_pointer_cast<AssembledLinearOperator<matrix_type, domain_type, range_type>>(op); + if(aop) + return aop->getmat(); + DUNE_THROW(NoAssembledOperator, "Could not obtain matrix from operator. Please pass in an AssembledLinearOperator."); + } + + static const comm_type& getCommOrThrow(std::shared_ptr<LinearOperator<domain_type, range_type>> op){ + std::shared_ptr<Operator> _op + = std::dynamic_pointer_cast<Operator>(op); + if constexpr (isParallel){ + return _op->getCommunication(); + }else{ + DUNE_THROW(NoAssembledOperator, "Could not obtain communication object from operator. Please pass in a parallel operator."); + } + } + + static std::shared_ptr<ScalarProduct<domain_type>> getScalarProduct(std::shared_ptr<LinearOperator<domain_type, range_type>> op) + { + if constexpr (isParallel){ + return createScalarProduct<domain_type>(getCommOrThrow(op), op->category()); + }else{ + return std::make_shared<SeqScalarProduct<domain_type>>(); + } + } + }; // initSolverFactories differs in different compilation units, so we have it // in an anonymous namespace namespace { - /** initializes the direct solvers, preconditioners and iterative solvers in - the factories with the corresponding Matrix and Vector types. + /** initializes the preconditioners and solvers in + the factories with the corresponding Operator and Vector types. @tparam O the assembled linear operator type */ template<class O> int initSolverFactories(){ - using M = typename O::matrix_type; - using X = typename O::range_type; - using Y = typename O::domain_type; - using TL = Dune::TypeList<M,X,Y>; - auto& dsfac=Dune::DirectSolverFactory<M,X,Y>::instance(); - addRegistryToFactory<TL>(dsfac, DirectSolverTag{}); - auto& pfac=Dune::PreconditionerFactory<O,X,Y>::instance(); - addRegistryToFactory<TL>(pfac, PreconditionerTag{}); - using TLS = Dune::TypeList<X,Y>; - auto& isfac=Dune::IterativeSolverFactory<X,Y>::instance(); - return addRegistryToFactory<TLS>(isfac, IterativeSolverTag{}); + using OpInfo = OperatorTraits<O>; + auto& pfac=Dune::PreconditionerFactory<O>::instance(); + addRegistryToFactory<OpInfo>(pfac, PreconditionerTag{}); + auto& isfac=Dune::SolverFactory<O>::instance(); + return addRegistryToFactory<OpInfo>(isfac, SolverTag{}); } } // end anonymous namespace - - template<class O, class Preconditioner> - std::shared_ptr<Preconditioner> wrapPreconditioner4Parallel(const std::shared_ptr<Preconditioner>& prec, - const O&) - { - return prec; - } - - template<class M, class X, class Y, class C, class Preconditioner> - std::shared_ptr<Preconditioner> - wrapPreconditioner4Parallel(const std::shared_ptr<Preconditioner>& prec, - const std::shared_ptr<OverlappingSchwarzOperator<M,X,Y,C> >& op) - { - return std::make_shared<BlockPreconditioner<X,Y,C,Preconditioner> >(prec, op->getCommunication()); - } - - template<class M, class X, class Y, class C, class Preconditioner> - std::shared_ptr<Preconditioner> - wrapPreconditioner4Parallel(const std::shared_ptr<Preconditioner>& prec, - const std::shared_ptr<NonoverlappingSchwarzOperator<M,X,Y,C> >& op) - { - return std::make_shared<NonoverlappingBlockPreconditioner<C,Preconditioner> >(prec, op->getCommunication()); - } - - template<class M, class X, class Y> - std::shared_ptr<ScalarProduct<X>> createScalarProduct(const std::shared_ptr<MatrixAdapter<M,X,Y> >&) - { - return std::make_shared<SeqScalarProduct<X>>(); - } - template<class M, class X, class Y, class C> - std::shared_ptr<ScalarProduct<X>> createScalarProduct(const std::shared_ptr<OverlappingSchwarzOperator<M,X,Y,C> >& op) - { - return createScalarProduct<X>(op->getCommunication(), op->category()); - } - - template<class M, class X, class Y, class C> - std::shared_ptr<ScalarProduct<X>> createScalarProduct(const std::shared_ptr<NonoverlappingSchwarzOperator<M,X,Y,C> >& op) - { - return createScalarProduct<X>(op->getCommunication(), op->category()); - } - /** - @brief Factory to assembly solvers configured by a `ParameterTree`. + \brief Instantiates an `InverseOperator` from an Operator and a + configuration given as a ParameterTree. + \param op Operator + \param config `ParameterTree` with configuration Example ini File that can be passed in to construct a CGSolver with a SSOR preconditioner: @@ -125,95 +124,39 @@ namespace Dune{ \endverbatim \tparam Operator type of the operator, necessary to deduce the matrix type etc. + */ template<class Operator> - class SolverFactory { - using Domain = typename Operator::domain_type; - using Range = typename Operator::range_type; - using Solver = Dune::InverseOperator<Domain,Range>; - using Preconditioner = Dune::Preconditioner<Domain, Range>; - - template<class O> - using _matrix_type = typename O::matrix_type; - using matrix_type = Std::detected_or_t<int, _matrix_type, Operator>; - static constexpr bool isAssembled = !std::is_same<matrix_type, int>::value; - - static const matrix_type* getmat(std::shared_ptr<Operator> op){ - std::shared_ptr<AssembledLinearOperator<matrix_type, Domain, Range>> aop - = std::dynamic_pointer_cast<AssembledLinearOperator<matrix_type, Domain, Range>>(op); - if(aop) - return &aop->getmat(); - return nullptr; - } - - public: - - /** @brief get a solver from the factory - */ - static std::shared_ptr<Solver> get(std::shared_ptr<Operator> op, - const ParameterTree& config, - std::shared_ptr<Preconditioner> prec = nullptr){ - std::string type = config.get<std::string>("type"); - std::shared_ptr<Solver> result; - const matrix_type* mat = getmat(op); - if(mat){ - if (DirectSolverFactory<matrix_type, Domain, Range>::instance().contains(type)) { - if(op->category()!=SolverCategory::sequential){ - DUNE_THROW(NotImplemented, "The solver factory does not support parallel direct solvers!"); - } - result = DirectSolverFactory<matrix_type, Domain, Range>::instance().create(type, *mat, config); - return result; - } - } - // if no direct solver is found it might be an iterative solver - if (!IterativeSolverFactory<Domain, Range>::instance().contains(type)) { - DUNE_THROW(Dune::InvalidStateException, "Solver not found in the factory."); - } - if(!prec){ - const ParameterTree& precConfig = config.sub("preconditioner"); - std::string prec_type = precConfig.get<std::string>("type"); - prec = PreconditionerFactory<Operator, Domain, Range>::instance().create(prec_type, op, precConfig); - if (prec->category() != op->category() && prec->category() == SolverCategory::sequential) - // try to wrap to a parallel preconditioner - prec = wrapPreconditioner4Parallel(prec, op); - } - std::shared_ptr<ScalarProduct<Domain>> sp = createScalarProduct(op); - result = IterativeSolverFactory<Domain, Range>::instance().create(type, op, sp, prec, config); - return result; - } - - /** - @brief Construct a Preconditioner for a given Operator - */ - static std::shared_ptr<Preconditioner> getPreconditioner(std::shared_ptr<Operator> op, - const ParameterTree& config){ - const matrix_type* mat = getmat(op); - if(mat){ - std::string prec_type = config.get<std::string>("type"); - return PreconditionerFactory<Operator, Domain, Range>::instance().create(prec_type, op, config); - }else{ - DUNE_THROW(InvalidStateException, "Could not obtain matrix from operator. Please pass in an AssembledLinearOperator."); - } - } - }; + std::shared_ptr<InverseOperator<typename Operator::domain_type, + typename Operator::range_type>> + getSolverFromFactory(std::shared_ptr<Operator> op, const ParameterTree& config){ + return SolverFactory<Operator>::instance(). + create(config.get<std::string>("type"),op, config); + } + class UnknownSolverCategory : public InvalidStateException{}; /** - \brief Instantiates an `InverseOperator` from an Operator and a - configuration given as a ParameterTree. - \param op Operator - \param config `ParameterTree` with configuration - \param prec Custom `Preconditioner` (optional). If not given it will be - created with the `PreconditionerFactory` and the configuration given in - subKey "preconditioner". - - */ + @brief Construct a Preconditioner for a given Operator + */ template<class Operator> - std::shared_ptr<InverseOperator<typename Operator::domain_type, - typename Operator::range_type>> getSolverFromFactory(std::shared_ptr<Operator> op, - const ParameterTree& config, - std::shared_ptr<Preconditioner<typename Operator::domain_type, - typename Operator::range_type>> prec = nullptr){ - return SolverFactory<Operator>::get(op, config, prec); + std::shared_ptr<Preconditioner<typename Operator::domain_type, + typename Operator::range_type>> + getPreconditionerFromFactory(std::shared_ptr<Operator> op, + const ParameterTree& config){ + using Domain = typename Operator::domain_type; + using Range = typename Operator::range_type; + std::string prec_type = config.get<std::string>("type"); + std::shared_ptr<Preconditioner<typename Operator::domain_type, + typename Operator::range_type>> prec = PreconditionerFactory<Operator>::instance().create(prec_type, op, config); + if constexpr (OperatorTraits<Operator>::isParallel){ + using Comm = typename OperatorTraits<Operator>::comm_type; + const Comm& comm = OperatorTraits<Operator>::getCommOrThrow(op); + if(op->category() == SolverCategory::overlapping && prec->category() == SolverCategory::sequential) + return std::make_shared<BlockPreconditioner<Domain,Range,Comm> >(prec, comm); + else if(op->category() == SolverCategory::nonoverlapping && prec->category() == SolverCategory::sequential) + return std::make_shared<NonoverlappingBlockPreconditioner<Comm, Preconditioner<Domain, Range>> >(prec, comm); + } + return prec; } /** diff --git a/dune/istl/solverregistry.hh b/dune/istl/solverregistry.hh index 390df0de2..4d9d57bdd 100644 --- a/dune/istl/solverregistry.hh +++ b/dune/istl/solverregistry.hh @@ -10,65 +10,70 @@ #include <dune/istl/preconditioner.hh> #include <dune/istl/solver.hh> -#define DUNE_REGISTER_DIRECT_SOLVER(name, ...) \ - DUNE_REGISTRY_PUT(DirectSolverTag, name, __VA_ARGS__) - #define DUNE_REGISTER_PRECONDITIONER(name, ...) \ DUNE_REGISTRY_PUT(PreconditionerTag, name, __VA_ARGS__) -#define DUNE_REGISTER_ITERATIVE_SOLVER(name, ...) \ - DUNE_REGISTRY_PUT(IterativeSolverTag, name, __VA_ARGS__) +#define DUNE_REGISTER_SOLVER(name, ...) \ + DUNE_REGISTRY_PUT(SolverTag, name, __VA_ARGS__) namespace Dune{ + /** @addtogroup ISTL_Factory @{ */ namespace { - struct DirectSolverTag {}; struct PreconditionerTag {}; - struct IterativeSolverTag {}; + struct SolverTag {}; } + template<template<class,class,class,int>class Preconditioner, int blockLevel=1> auto defaultPreconditionerBlockLevelCreator(){ - return [](auto typeList, const auto& matrix, const Dune::ParameterTree& config) - { - using Matrix = typename Dune::TypeListElement<0, decltype(typeList)>::type; - using Domain = typename Dune::TypeListElement<1, decltype(typeList)>::type; - using Range = typename Dune::TypeListElement<2, decltype(typeList)>::type; - std::shared_ptr<Dune::Preconditioner<Domain, Range>> preconditioner - = std::make_shared<Preconditioner<Matrix, Domain, Range, blockLevel>>(matrix, config); - return preconditioner; - }; + return [](auto opInfo, const auto& linearOperator, const Dune::ParameterTree& config) + { + using OpInfo = std::decay_t<decltype(opInfo)>; + using Matrix = typename OpInfo::matrix_type; + using Domain = typename OpInfo::domain_type; + using Range = typename OpInfo::range_type; + const Matrix& matrix = opInfo.getMatOrThrow(linearOperator); + std::shared_ptr<Dune::Preconditioner<Domain, Range>> preconditioner + = std::make_shared<Preconditioner<Matrix, Domain, Range, blockLevel>>(matrix, config); + return preconditioner; + }; } template<template<class,class,class>class Preconditioner> auto defaultPreconditionerCreator(){ - return [](auto typeList, const auto& matrix, const Dune::ParameterTree& config) - { - using Matrix = typename Dune::TypeListElement<0, decltype(typeList)>::type; - using Domain = typename Dune::TypeListElement<1, decltype(typeList)>::type; - using Range = typename Dune::TypeListElement<2, decltype(typeList)>::type; - std::shared_ptr<Dune::Preconditioner<Domain, Range>> preconditioner - = std::make_shared<Preconditioner<Matrix, Domain, Range>>(matrix, config); - return preconditioner; - }; + return [](auto opInfo, const auto& linearOperator, const Dune::ParameterTree& config) + { + using OpInfo = std::decay_t<decltype(opInfo)>; + using Matrix = typename OpInfo::matrix_type; + using Domain = typename OpInfo::domain_type; + using Range = typename OpInfo::range_type; + const Matrix& matrix = opInfo.getMatOrThrow(linearOperator); + std::shared_ptr<Dune::Preconditioner<Domain, Range>> preconditioner + = std::make_shared<Preconditioner<Matrix, Domain, Range>>(matrix, config); + return preconditioner; + }; } template<template<class...>class Solver> auto defaultIterativeSolverCreator(){ - return [](auto typeList, + return [](auto opInfo, const auto& linearOperator, - const auto& scalarProduct, - const auto& preconditioner, const Dune::ParameterTree& config) - { - using Domain = typename Dune::TypeListElement<0, decltype(typeList)>::type; - using Range = typename Dune::TypeListElement<1, decltype(typeList)>::type; - std::shared_ptr<Dune::InverseOperator<Domain, Range>> solver - = std::make_shared<Solver<Domain>>(linearOperator, scalarProduct, preconditioner, config); - return solver; - }; + { + using OpInfo = std::decay_t<decltype(opInfo)>; + using Operator = typename OpInfo::operator_type; + using Domain = typename OpInfo::domain_type; + using Range = typename OpInfo::range_type; + std::shared_ptr<Operator> _op = std::dynamic_pointer_cast<Operator>(linearOperator); + std::shared_ptr<Preconditioner<Domain,Range>> preconditioner = getPreconditionerFromFactory(_op, config.sub("preconditioner")); + std::shared_ptr<ScalarProduct<Range>> scalarProduct = opInfo.getScalarProduct(linearOperator); + std::shared_ptr<Dune::InverseOperator<Domain, Range>> solver + = std::make_shared<Solver<Domain>>(linearOperator, scalarProduct, preconditioner, config); + return solver; + }; } /* This exception is thrown, when the requested solver is in the factory but diff --git a/dune/istl/solvers.hh b/dune/istl/solvers.hh index 98dbc9fdf..cb09353ad 100644 --- a/dune/istl/solvers.hh +++ b/dune/istl/solvers.hh @@ -115,7 +115,7 @@ namespace Dune { using IterativeSolver<X,X>::_verbose; using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("loopsolver", defaultIterativeSolverCreator<Dune::LoopSolver>()); + DUNE_REGISTER_SOLVER("loopsolver", defaultIterativeSolverCreator<Dune::LoopSolver>()); // all these solvers are taken from the SUMO library @@ -186,7 +186,7 @@ namespace Dune { using IterativeSolver<X,X>::_verbose; using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("gradientsolver", defaultIterativeSolverCreator<Dune::GradientSolver>()); + DUNE_REGISTER_SOLVER("gradientsolver", defaultIterativeSolverCreator<Dune::GradientSolver>()); //! \brief conjugate gradient method template<class X> @@ -411,7 +411,7 @@ namespace Dune { using IterativeSolver<X,X>::_verbose; using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("cgsolver", defaultIterativeSolverCreator<Dune::CGSolver>()); + DUNE_REGISTER_SOLVER("cgsolver", defaultIterativeSolverCreator<Dune::CGSolver>()); // Ronald Kriemanns BiCG-STAB implementation from Sumo //! \brief Bi-conjugate Gradient Stabilized (BiCG-STAB) @@ -597,7 +597,7 @@ namespace Dune { template<class CountType> using Iteration = typename IterativeSolver<X,X>::template Iteration<CountType>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("bicgstabsolver", defaultIterativeSolverCreator<Dune::BiCGSTABSolver>()); + DUNE_REGISTER_SOLVER("bicgstabsolver", defaultIterativeSolverCreator<Dune::BiCGSTABSolver>()); /*! \brief Minimal Residual Method (MINRES) @@ -807,7 +807,7 @@ namespace Dune { using IterativeSolver<X,X>::_verbose; using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("minressolver", defaultIterativeSolverCreator<Dune::MINRESSolver>()); + DUNE_REGISTER_SOLVER("minressolver", defaultIterativeSolverCreator<Dune::MINRESSolver>()); /** \brief implements the Generalized Minimal Residual (GMRes) method @@ -1119,7 +1119,7 @@ namespace Dune { using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; int _restart; }; - DUNE_REGISTER_ITERATIVE_SOLVER("restartedgmressolver", defaultIterativeSolverCreator<Dune::RestartedGMResSolver>()); + DUNE_REGISTER_SOLVER("restartedgmressolver", defaultIterativeSolverCreator<Dune::RestartedGMResSolver>()); /** \brief implements the Flexible Generalized Minimal Residual (FGMRes) method (right preconditioned) @@ -1287,7 +1287,7 @@ private: using RestartedGMResSolver<X,Y>::_restart; using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("restartedflexiblegmressolver", defaultIterativeSolverCreator<Dune::RestartedFlexibleGMResSolver>()); + DUNE_REGISTER_SOLVER("restartedflexiblegmressolver", defaultIterativeSolverCreator<Dune::RestartedFlexibleGMResSolver>()); /** * @brief Generalized preconditioned conjugate gradient solver. @@ -1483,7 +1483,7 @@ private: using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; int _restart; }; - DUNE_REGISTER_ITERATIVE_SOLVER("generalizedpcgsolver", defaultIterativeSolverCreator<Dune::GeneralizedPCGSolver>()); + DUNE_REGISTER_SOLVER("generalizedpcgsolver", defaultIterativeSolverCreator<Dune::GeneralizedPCGSolver>()); /*! \brief Accelerated flexible conjugate gradient method @@ -1667,7 +1667,7 @@ private: using IterativeSolver<X,X>::_verbose; using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>; }; - DUNE_REGISTER_ITERATIVE_SOLVER("restartedfcgsolver", defaultIterativeSolverCreator<Dune::RestartedFCGSolver>()); + DUNE_REGISTER_SOLVER("restartedfcgsolver", defaultIterativeSolverCreator<Dune::RestartedFCGSolver>()); /*! \brief Complete flexible conjugate gradient method @@ -1730,7 +1730,7 @@ private: using RestartedFCGSolver<X>::_maxit; using RestartedFCGSolver<X>::_verbose; }; - DUNE_REGISTER_ITERATIVE_SOLVER("completefcgsolver", defaultIterativeSolverCreator<Dune::CompleteFCGSolver>()); + DUNE_REGISTER_SOLVER("completefcgsolver", defaultIterativeSolverCreator<Dune::CompleteFCGSolver>()); /** @} end documentation */ } // end namespace diff --git a/dune/istl/spqr.hh b/dune/istl/spqr.hh index 61c05510c..4e2d6b665 100644 --- a/dune/istl/spqr.hh +++ b/dune/istl/spqr.hh @@ -333,23 +333,26 @@ namespace Dune { struct SPQRCreator { template<class> struct isValidBlock : std::false_type{}; - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& mat, const Dune::ParameterTree& config, + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, std::enable_if_t< - isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { + using M = typename OpTraits::matrix_type; + const M& mat = opTraits.getMatOrThrow(op); int verbose = config.get("verbose", 0); return std::make_shared<Dune::SPQR<M>>(mat,verbose); } // second version with SFINAE to validate the template parameters of SPQR - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& /*mat*/, const Dune::ParameterTree& /*config*/, - std::enable_if_t<!isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, + std::enable_if_t< + !isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { DUNE_THROW(UnsupportedType, "Unsupported Type in SPQR (only double and std::complex<double> supported)"); @@ -358,7 +361,7 @@ namespace Dune { template<> struct SPQRCreator::isValidBlock<FieldVector<double,1>> : std::true_type{}; // std::complex is temporary disabled, because it fails if libc++ is used //template<> struct SPQRCreator::isValidMatrixBlock<FieldMatrix<std::complex<double>,1,1>> : std::true_type{}; - DUNE_REGISTER_DIRECT_SOLVER("spqr", Dune::SPQRCreator()); + DUNE_REGISTER_SOLVER("spqr", Dune::SPQRCreator()); } // end namespace Dune diff --git a/dune/istl/superlu.hh b/dune/istl/superlu.hh index 783e9d194..9ae8e6328 100644 --- a/dune/istl/superlu.hh +++ b/dune/istl/superlu.hh @@ -728,22 +728,25 @@ namespace Dune template<class> struct isValidBlock : std::false_type{}; template<int k> struct isValidBlock<Dune::FieldVector<double,k>> : std::true_type{}; template<int k> struct isValidBlock<Dune::FieldVector<std::complex<double>,k>> : std::true_type{}; - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& mat, const Dune::ParameterTree& config, - std::enable_if_t<isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type> > + operator() (OpTraits opTraits, const OP& op, const Dune::ParameterTree& config, + std::enable_if_t<isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { + using M = typename OpTraits::matrix_type; + const M& mat = opTraits.getMatOrThrow(op); int verbose = config.get("verbose", 0); return std::make_shared<Dune::SuperLU<M>>(mat,verbose); } // second version with SFINAE to validate the template parameters of SuperLU - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& /*mat*/, const Dune::ParameterTree& /*config*/, - std::enable_if_t<!isValidBlock<typename Dune::TypeListElement<1, TL>::type::block_type>::value,int> = 0) const + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const OP& op, const Dune::ParameterTree& config, + std::enable_if_t<!isValidBlock<typename OpTraits::matrix_type::block_type>::value,int> = 0) const { DUNE_THROW(UnsupportedType, "Unsupported Type in SuperLU (only double and std::complex<double> supported)"); @@ -752,7 +755,7 @@ namespace Dune template<> struct SuperLUCreator::isValidBlock<double> : std::true_type{}; template<> struct SuperLUCreator::isValidBlock<std::complex<double>> : std::true_type{}; - DUNE_REGISTER_DIRECT_SOLVER("superlu", SuperLUCreator()); + DUNE_REGISTER_SOLVER("superlu", SuperLUCreator()); } // end namespace DUNE // undefine macros from SuperLU's slu_util.h diff --git a/dune/istl/umfpack.hh b/dune/istl/umfpack.hh index 54cb264b0..17bda13d8 100644 --- a/dune/istl/umfpack.hh +++ b/dune/istl/umfpack.hh @@ -796,28 +796,36 @@ namespace Dune { struct UMFPackCreator { - template<class TL, class M,class=void> struct isValidBlock : std::false_type{}; - template<class TL, class M> struct isValidBlock<TL,M, + template<class OpTraits, class=void> struct isValidBlock : std::false_type{}; + template<class OpTraits> struct isValidBlock<OpTraits, std::enable_if_t< - std::is_same_v<Impl::UMFPackDomainType<M>, typename Dune::TypeListElement<1,TL>::type> - && std::is_same_v<Impl::UMFPackRangeType<M>, typename Dune::TypeListElement<2,TL>::type> + std::is_same_v<Impl::UMFPackDomainType<typename OpTraits::matrix_type>, typename OpTraits::domain_type> + && std::is_same_v<Impl::UMFPackRangeType<typename OpTraits::matrix_type>, typename OpTraits::range_type> >> : std::true_type {}; - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<Impl::UMFPackDomainType<M>,Impl::UMFPackRangeType<M>>> - operator() (TL /*tl*/, const M& mat, const Dune::ParameterTree& config, - std::enable_if_t<isValidBlock<TL, M>::value,int> = 0) const + template<typename OpTraits, typename OP> + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits opTraits, const std::shared_ptr<OP>& op, const Dune::ParameterTree& config, + std::enable_if_t< + isValidBlock<OpTraits>::value + && Simd::lanes<typename OpTraits::domain_type::field_type>() == 1,int> = 0) const { + using M = typename OpTraits::matrix_type; + const M& mat = opTraits.getMatOrThrow(op); int verbose = config.get("verbose", 0); return std::make_shared<Dune::UMFPack<M>>(mat,verbose); } // second version with SFINAE to validate the template parameters of UMFPack - template<typename TL, typename M> - std::shared_ptr<Dune::InverseOperator<typename Dune::TypeListElement<1, TL>::type, - typename Dune::TypeListElement<2, TL>::type>> - operator() (TL /*tl*/, const M& /*mat*/, const Dune::ParameterTree& /*config*/, - std::enable_if_t<!isValidBlock<TL, M>::value,int> = 0) const + template<typename OpTraits, typename OP> + std::shared_ptr<Dune::InverseOperator<typename OpTraits::domain_type, + typename OpTraits::range_type>> + operator() (OpTraits /*opTraits*/, const std::shared_ptr<OP>& /*op*/, const Dune::ParameterTree& /*config*/, + std::enable_if_t< + !isValidBlock<OpTraits>::value + || Simd::lanes<typename OpTraits::domain_type::field_type>() != 1,int> = 0) const { using D = typename Dune::TypeListElement<1,TL>::type; using R = typename Dune::TypeListElement<2,TL>::type; @@ -833,7 +841,7 @@ namespace Dune { ); } }; - DUNE_REGISTER_DIRECT_SOLVER("umfpack",Dune::UMFPackCreator()); + DUNE_REGISTER_SOLVER("umfpack",Dune::UMFPackCreator()); } // end namespace Dune #endif // HAVE_SUITESPARSE_UMFPACK -- GitLab