diff --git a/opm/simulators/linalg/FlexibleSolver.hpp b/opm/simulators/linalg/FlexibleSolver.hpp index 2b1433ded..e1fb930e9 100644 --- a/opm/simulators/linalg/FlexibleSolver.hpp +++ b/opm/simulators/linalg/FlexibleSolver.hpp @@ -46,16 +46,27 @@ public: using VectorType = VectorTypeT; /// Create a sequential solver. - FlexibleSolver(const boost::property_tree::ptree& prm, const MatrixType& matrix) + FlexibleSolver(const boost::property_tree::ptree& prm, const MatrixType& matrix, + const std::function& weightsCalculator = std::function()) { - init(prm, matrix, Dune::Amg::SequentialInformation()); + init(prm, matrix, weightsCalculator, Dune::Amg::SequentialInformation()); } /// Create a parallel solver (if Comm is e.g. OwnerOverlapCommunication). template - FlexibleSolver(const boost::property_tree::ptree& prm, const MatrixType& matrix, const Comm& comm) + FlexibleSolver(const boost::property_tree::ptree& prm, + const typename std::enable_if::value,MatrixType>::type& matrix, + const Comm& comm) { - init(prm, matrix, comm); + init(prm, matrix, std::function(), comm); + } + + /// Create a parallel solver (if Comm is e.g. OwnerOverlapCommunication). + template + FlexibleSolver(const boost::property_tree::ptree& prm, const MatrixType& matrix, + const std::function& weightsCalculator, const Comm& comm) + { + init(prm, matrix, weightsCalculator, comm); } virtual void apply(VectorType& x, VectorType& rhs, Dune::InverseOperatorResult& res) override @@ -89,24 +100,28 @@ private: // Machinery for making sequential or parallel operators/preconditioners/scalar products. template - void initOpPrecSp(const MatrixType& matrix, const boost::property_tree::ptree& prm, const Comm& comm) + void initOpPrecSp(const MatrixType& matrix, const boost::property_tree::ptree& prm, + const std::function weightsCalculator, const Comm& comm) { // Parallel case. using ParOperatorType = Dune::OverlappingSchwarzOperator; auto linop = std::make_shared(matrix, comm); linearoperator_ = linop; preconditioner_ - = Opm::PreconditionerFactory::create(*linop, prm.get_child("preconditioner"), comm); + = Opm::PreconditionerFactory::create(*linop, prm.get_child("preconditioner"), + weightsCalculator, comm); scalarproduct_ = Dune::createScalarProduct(comm, linearoperator_->category()); } - void initOpPrecSp(const MatrixType& matrix, const boost::property_tree::ptree& prm, const Dune::Amg::SequentialInformation&) + void initOpPrecSp(const MatrixType& matrix, const boost::property_tree::ptree& prm, + const std::function weightsCalculator, const Dune::Amg::SequentialInformation&) { // Sequential case. using SeqOperatorType = Dune::MatrixAdapter; auto linop = std::make_shared(matrix); linearoperator_ = linop; - preconditioner_ = Opm::PreconditionerFactory::create(*linop, prm.get_child("preconditioner")); + preconditioner_ = Opm::PreconditionerFactory::create(*linop, prm.get_child("preconditioner"), + weightsCalculator); scalarproduct_ = std::make_shared>(); } @@ -155,9 +170,10 @@ private: // Main initialization routine. // Call with Comm == Dune::Amg::SequentialInformation to get a serial solver. template - void init(const boost::property_tree::ptree& prm, const MatrixType& matrix, const Comm& comm) + void init(const boost::property_tree::ptree& prm, const MatrixType& matrix, + const std::function weightsCalculator, const Comm& comm) { - initOpPrecSp(matrix, prm, comm); + initOpPrecSp(matrix, prm, weightsCalculator, comm); initSolver(prm); } diff --git a/opm/simulators/linalg/ISTLSolverEbosFlexible.hpp b/opm/simulators/linalg/ISTLSolverEbosFlexible.hpp index 3fb61e2f2..04a0cc853 100644 --- a/opm/simulators/linalg/ISTLSolverEbosFlexible.hpp +++ b/opm/simulators/linalg/ISTLSolverEbosFlexible.hpp @@ -151,7 +151,7 @@ public: // Never recreate solver. } - VectorType weights; + std::function weightsCalculator; if( prm_.get("preconditioner.type") == "cpr" || prm_.get("preconditioner.type") == "cprt" @@ -163,20 +163,21 @@ public: } if(prm_.get("preconditioner.weight_type") == "quasiimpes") { - if( not( recreate_solver || !solver_) ){ - // weighs will be created as default in the solver - weights = Opm::Amg::getQuasiImpesWeights( - mat.istlMatrix(), - prm_.get("preconditioner.pressure_var_index"), transpose); - } + // weighs will be created as default in the solver + weightsCalculator = + [&mat, this, transpose](){ + return Opm::Amg::getQuasiImpesWeights( + mat.istlMatrix(), + this->prm_.get("preconditioner.pressure_var_index"), + transpose); + }; }else if(prm_.get("preconditioner.weight_type") == "trueimpes" ){ - weights = - this->getTrueImpesWeights(b, prm_.get("preconditioner.pressure_var_index")); - if( recreate_solver || !solver_){ - // need weights for the constructor - prm_.put("preconditioner.weights",weights); - } + weightsCalculator = + [this, &b](){ + return this->getTrueImpesWeights(b, this->prm_.get("preconditioner.pressure_var_index")); + }; }else{ throw std::runtime_error("no such weights implemented for cpr"); } @@ -185,14 +186,14 @@ public: if (recreate_solver || !solver_) { if (isParallel()) { #if HAVE_MPI - solver_.reset(new SolverType(prm_, mat.istlMatrix(), *comm_)); + solver_.reset(new SolverType(prm_, mat.istlMatrix(), weightsCalculator, *comm_)); #endif } else { - solver_.reset(new SolverType(prm_, mat.istlMatrix())); + solver_.reset(new SolverType(prm_, mat.istlMatrix(), weightsCalculator)); } rhs_ = b; } else { - solver_->preconditioner().update(weights); + solver_->preconditioner().update(); rhs_ = b; } } diff --git a/opm/simulators/linalg/OwningBlockPreconditioner.hpp b/opm/simulators/linalg/OwningBlockPreconditioner.hpp index 7cc1a6593..7dcd2d384 100644 --- a/opm/simulators/linalg/OwningBlockPreconditioner.hpp +++ b/opm/simulators/linalg/OwningBlockPreconditioner.hpp @@ -63,9 +63,9 @@ public: } // The update() function does nothing for a wrapped preconditioner. - virtual void update(const X& w) override + virtual void update() override { - orig_precond_.update(w); + orig_precond_.update(); } private: diff --git a/opm/simulators/linalg/OwningTwoLevelPreconditioner.hpp b/opm/simulators/linalg/OwningTwoLevelPreconditioner.hpp index c998143bc..452872b37 100644 --- a/opm/simulators/linalg/OwningTwoLevelPreconditioner.hpp +++ b/opm/simulators/linalg/OwningTwoLevelPreconditioner.hpp @@ -84,17 +84,13 @@ public: using MatrixType = typename OperatorType::matrix_type; using PrecFactory = Opm::PreconditionerFactory; - OwningTwoLevelPreconditioner(const OperatorType& linearoperator, const pt& prm) + OwningTwoLevelPreconditioner(const OperatorType& linearoperator, const pt& prm, + const std::function weightsCalculator) : linear_operator_(linearoperator) , finesmoother_(PrecFactory::create(linearoperator, prm.get_child("finesmoother"))) , comm_(nullptr) - , weights_( - (prm.get("weight_type") != "quasiimpes") ? - prm.get("weights") : - Opm::Amg::getQuasiImpesWeights(linearoperator.getmat(), - prm.get("pressure_var_index"), - transpose) - ) + , weightsCalculator_(weightsCalculator) + , weights_(weightsCalculator()) , levelTransferPolicy_(dummy_comm_, weights_, prm.get("pressure_var_index")) , coarseSolverPolicy_(prm.get_child("coarsesolver")) , twolevel_method_(linearoperator, @@ -114,17 +110,13 @@ public: } } - OwningTwoLevelPreconditioner(const OperatorType& linearoperator, const pt& prm, const Communication& comm) + OwningTwoLevelPreconditioner(const OperatorType& linearoperator, const pt& prm, + const std::function weightsCalculator, const Communication& comm) : linear_operator_(linearoperator) , finesmoother_(PrecFactory::create(linearoperator, prm.get_child("finesmoother"), comm)) , comm_(&comm) - , weights_( - (prm.get("weight_type") != "quasiimpes") ? - prm.get("weights") : - Opm::Amg::getQuasiImpesWeights(linearoperator.getmat(), - prm.get("pressure_var_index"), - transpose) - ) + , weightsCalculator_(weightsCalculator) + , weights_(weightsCalculator()) , levelTransferPolicy_(*comm_, weights_, prm.get("pressure_var_index")) , coarseSolverPolicy_(prm.get_child("coarsesolver")) , twolevel_method_(linearoperator, @@ -161,9 +153,9 @@ public: twolevel_method_.post(x); } - virtual void update(const VectorType& weights) override + virtual void update() override { - weights_ = weights; + weights_ = weightsCalculator_(); updateImpl(comm_); } @@ -207,6 +199,7 @@ private: const OperatorType& linear_operator_; std::shared_ptr> finesmoother_; const Communication* comm_; + std::function weightsCalculator_; VectorType weights_; LevelTransferPolicy levelTransferPolicy_; CoarseSolverPolicy coarseSolverPolicy_; diff --git a/opm/simulators/linalg/ParallelOverlappingILU0.hpp b/opm/simulators/linalg/ParallelOverlappingILU0.hpp index 5a3563f29..c5f70e7c1 100644 --- a/opm/simulators/linalg/ParallelOverlappingILU0.hpp +++ b/opm/simulators/linalg/ParallelOverlappingILU0.hpp @@ -921,7 +921,7 @@ public: DUNE_UNUSED_PARAMETER(x); } - virtual void update(const Range& = Range()) override + virtual void update() override { // (For older DUNE versions the communicator might be // invalid if redistribution in AMG happened on the coarset level. diff --git a/opm/simulators/linalg/PreconditionerFactory.hpp b/opm/simulators/linalg/PreconditionerFactory.hpp index d7799ebff..e32733573 100644 --- a/opm/simulators/linalg/PreconditionerFactory.hpp +++ b/opm/simulators/linalg/PreconditionerFactory.hpp @@ -57,16 +57,30 @@ public: using PrecPtr = std::shared_ptr>; /// The type of creator functions passed to addCreator(). - using Creator = std::function; - using ParCreator = std::function; + using Creator = std::function&)>; + using ParCreator = std::function&, const Comm&)>; /// Create a new serial preconditioner and return a pointer to it. /// \param op operator to be preconditioned. /// \param prm parameters for the preconditioner, in particular its type. + /// \param weightsCalculator Calculator for weights used in CPR. /// \return (smart) pointer to the created preconditioner. - static PrecPtr create(const Operator& op, const boost::property_tree::ptree& prm) + static PrecPtr create(const Operator& op, const boost::property_tree::ptree& prm, + const std::function& weightsCalculator = std::function()) { - return instance().doCreate(op, prm); + return instance().doCreate(op, prm, weightsCalculator); + } + + /// Create a new parallel preconditioner and return a pointer to it. + /// \param op operator to be preconditioned. + /// \param prm parameters for the preconditioner, in particular its type. + /// \param comm communication object (typically OwnerOverlapCopyCommunication). + /// \param weightsCalculator Calculator for weights used in CPR. + /// \return (smart) pointer to the created preconditioner. + static PrecPtr create(const Operator& op, const boost::property_tree::ptree& prm, + const std::function& weightsCalculator, const Comm& comm) + { + return instance().doCreate(op, prm, weightsCalculator, comm); } /// Create a new parallel preconditioner and return a pointer to it. @@ -76,9 +90,8 @@ public: /// \return (smart) pointer to the created preconditioner. static PrecPtr create(const Operator& op, const boost::property_tree::ptree& prm, const Comm& comm) { - return instance().doCreate(op, prm, comm); + return instance().doCreate(op, prm, std::function(), comm); } - /// Add a creator for a serial preconditioner to the PreconditionerFactory. /// After the call, the user may obtain a preconditioner by /// calling create() with the given type string as a parameter @@ -154,44 +167,45 @@ private: using V = Vector; using P = boost::property_tree::ptree; using C = Comm; - doAddCreator("ILU0", [](const O& op, const P& prm, const C& comm) { + doAddCreator("ILU0", [](const O& op, const P& prm, const std::function&, const C& comm) { const double w = prm.get("relaxation"); return std::make_shared>( op.getmat(), comm, 0, w, Opm::MILU_VARIANT::ILU); }); - doAddCreator("ParOverILU0", [](const O& op, const P& prm, const C& comm) { + doAddCreator("ParOverILU0", [](const O& op, const P& prm, const std::function&, const C& comm) { const double w = prm.get("relaxation"); // Already a parallel preconditioner. Need to pass comm, but no need to wrap it in a BlockPreconditioner. return std::make_shared>( op.getmat(), comm, 0, w, Opm::MILU_VARIANT::ILU); }); - doAddCreator("ILUn", [](const O& op, const P& prm, const C& comm) { + doAddCreator("ILUn", [](const O& op, const P& prm, const std::function&, const C& comm) { const int n = prm.get("ilulevel"); const double w = prm.get("relaxation"); return std::make_shared>( op.getmat(), comm, n, w, Opm::MILU_VARIANT::ILU); }); - doAddCreator("Jac", [](const O& op, const P& prm, const C& comm) { + doAddCreator("Jac", [](const O& op, const P& prm, const std::function&, + const C& comm) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapBlockPreconditioner>>(comm, op.getmat(), n, w); }); - doAddCreator("GS", [](const O& op, const P& prm, const C& comm) { + doAddCreator("GS", [](const O& op, const P& prm, const std::function&, const C& comm) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapBlockPreconditioner>>(comm, op.getmat(), n, w); }); - doAddCreator("SOR", [](const O& op, const P& prm, const C& comm) { + doAddCreator("SOR", [](const O& op, const P& prm, const std::function&, const C& comm) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapBlockPreconditioner>>(comm, op.getmat(), n, w); }); - doAddCreator("SSOR", [](const O& op, const P& prm, const C& comm) { + doAddCreator("SSOR", [](const O& op, const P& prm, const std::function&, const C& comm) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapBlockPreconditioner>>(comm, op.getmat(), n, w); }); - doAddCreator("amg", [](const O& op, const P& prm, const C& comm) { + doAddCreator("amg", [](const O& op, const P& prm, const std::function&, const C& comm) { const std::string smoother = prm.get("smoother"); if (smoother == "ILU0") { using Smoother = Opm::ParallelOverlappingILU0; @@ -204,11 +218,13 @@ private: throw std::runtime_error(msg); } }); - doAddCreator("cpr", [](const O& op, const P& prm, const C& comm) { - return std::make_shared>(op, prm, comm); + doAddCreator("cpr", [](const O& op, const P& prm, const std::function weightsCalculator, const C& comm) { + assert(weightsCalculator); + return std::make_shared>(op, prm, weightsCalculator, comm); }); - doAddCreator("cprt", [](const O& op, const P& prm, const C& comm) { - return std::make_shared>(op, prm, comm); + doAddCreator("cprt", [](const O& op, const P& prm, const std::function weightsCalculator, const C& comm) { + assert(weightsCalculator); + return std::make_shared>(op, prm, weightsCalculator, comm); }); } @@ -221,43 +237,43 @@ private: using M = Matrix; using V = Vector; using P = boost::property_tree::ptree; - doAddCreator("ILU0", [](const O& op, const P& prm) { + doAddCreator("ILU0", [](const O& op, const P& prm, const std::function&) { const double w = prm.get("relaxation"); return std::make_shared>( op.getmat(), 0, w, Opm::MILU_VARIANT::ILU); }); - doAddCreator("ParOverILU0", [](const O& op, const P& prm) { + doAddCreator("ParOverILU0", [](const O& op, const P& prm, const std::function&) { const double w = prm.get("relaxation"); return std::make_shared>( op.getmat(), 0, w, Opm::MILU_VARIANT::ILU); }); - doAddCreator("ILUn", [](const O& op, const P& prm) { + doAddCreator("ILUn", [](const O& op, const P& prm, const std::function&) { const int n = prm.get("ilulevel"); const double w = prm.get("relaxation"); return std::make_shared>( op.getmat(), n, w, Opm::MILU_VARIANT::ILU); }); - doAddCreator("Jac", [](const O& op, const P& prm) { + doAddCreator("Jac", [](const O& op, const P& prm, const std::function&) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapPreconditioner>(op.getmat(), n, w); }); - doAddCreator("GS", [](const O& op, const P& prm) { + doAddCreator("GS", [](const O& op, const P& prm, const std::function&) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapPreconditioner>(op.getmat(), n, w); }); - doAddCreator("SOR", [](const O& op, const P& prm) { + doAddCreator("SOR", [](const O& op, const P& prm, const std::function&) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapPreconditioner>(op.getmat(), n, w); }); - doAddCreator("SSOR", [](const O& op, const P& prm) { + doAddCreator("SSOR", [](const O& op, const P& prm, const std::function&) { const int n = prm.get("repeats"); const double w = prm.get("relaxation"); return wrapPreconditioner>(op.getmat(), n, w); }); - doAddCreator("amg", [](const O& op, const P& prm) { + doAddCreator("amg", [](const O& op, const P& prm, const std::function&) { const std::string smoother = prm.get("smoother"); if (smoother == "ILU0") { #if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 7) @@ -288,18 +304,18 @@ private: throw std::runtime_error(msg); } }); - doAddCreator("famg", [](const O& op, const P& prm) { + doAddCreator("famg", [](const O& op, const P& prm, const std::function&) { auto crit = amgCriterion(prm); Dune::Amg::Parameters parms; parms.setNoPreSmoothSteps(1); parms.setNoPostSmoothSteps(1); return wrapPreconditioner>(op, crit, parms); }); - doAddCreator("cpr", [](const O& op, const P& prm) { - return std::make_shared>(op, prm); + doAddCreator("cpr", [](const O& op, const P& prm, const std::function& weightsCalculator) { + return std::make_shared>(op, prm, weightsCalculator); }); - doAddCreator("cprt", [](const O& op, const P& prm) { - return std::make_shared>(op, prm); + doAddCreator("cprt", [](const O& op, const P& prm, const std::function& weightsCalculator) { + return std::make_shared>(op, prm, weightsCalculator); }); } @@ -320,7 +336,8 @@ private: } // Actually creates the product object. - PrecPtr doCreate(const Operator& op, const boost::property_tree::ptree& prm) + PrecPtr doCreate(const Operator& op, const boost::property_tree::ptree& prm, + const std::function weightsCalculator) { const std::string& type = prm.get("type"); auto it = creators_.find(type); @@ -333,10 +350,11 @@ private: msg << std::endl; throw std::runtime_error(msg.str()); } - return it->second(op, prm); + return it->second(op, prm, weightsCalculator); } - PrecPtr doCreate(const Operator& op, const boost::property_tree::ptree& prm, const Comm& comm) + PrecPtr doCreate(const Operator& op, const boost::property_tree::ptree& prm, + const std::function weightsCalculator, const Comm& comm) { const std::string& type = prm.get("type"); auto it = parallel_creators_.find(type); @@ -350,7 +368,7 @@ private: msg << std::endl; throw std::runtime_error(msg.str()); } - return it->second(op, prm, comm); + return it->second(op, prm, weightsCalculator, comm); } // Actually adds the creator. diff --git a/opm/simulators/linalg/PreconditionerWithUpdate.hpp b/opm/simulators/linalg/PreconditionerWithUpdate.hpp index 01975277e..00132f31f 100644 --- a/opm/simulators/linalg/PreconditionerWithUpdate.hpp +++ b/opm/simulators/linalg/PreconditionerWithUpdate.hpp @@ -31,7 +31,7 @@ template class PreconditionerWithUpdate : public Preconditioner { public: - virtual void update(const X& w) = 0; + virtual void update() = 0; }; template @@ -69,7 +69,7 @@ public: } // The update() function does nothing for a wrapped preconditioner. - virtual void update(const X& /*w*/) override + virtual void update() override { } diff --git a/opm/simulators/linalg/PressureSolverPolicy.hpp b/opm/simulators/linalg/PressureSolverPolicy.hpp index 1073193e5..9f8030915 100644 --- a/opm/simulators/linalg/PressureSolverPolicy.hpp +++ b/opm/simulators/linalg/PressureSolverPolicy.hpp @@ -61,9 +61,9 @@ namespace Amg : linsolver_() { if (op.category() == Dune::SolverCategory::overlapping) { - linsolver_.reset(new Solver(prm, op.getmat(), comm)); + linsolver_.reset(new Solver(prm, op.getmat(), std::function(), comm)); } else { - linsolver_.reset(new Solver(prm, op.getmat())); + linsolver_.reset(new Solver(prm, op.getmat(), std::function())); } } @@ -84,8 +84,7 @@ namespace Amg void updatePreconditioner() { - X w; - linsolver_->preconditioner().update(w); + linsolver_->preconditioner().update(); } private: diff --git a/opm/simulators/linalg/amgcpr.hh b/opm/simulators/linalg/amgcpr.hh index 16b2ca0ea..301683cdb 100644 --- a/opm/simulators/linalg/amgcpr.hh +++ b/opm/simulators/linalg/amgcpr.hh @@ -239,9 +239,8 @@ namespace Dune /** * @brief Update the coarse solver and the hierarchies. */ - virtual void update(const X& w); - virtual void update(); + /** * @brief Check whether the coarse solver used is a direct solver. * @return True if the coarse level solver is a direct solver. @@ -469,11 +468,6 @@ namespace Dune update(); } - template - void AMGCPR::update(const X& /*w*/) - { - update(); - } template void AMGCPR::update() { diff --git a/tests/test_flexiblesolver.cpp b/tests/test_flexiblesolver.cpp index d7327d3f4..40bbc18c0 100644 --- a/tests/test_flexiblesolver.cpp +++ b/tests/test_flexiblesolver.cpp @@ -58,7 +58,19 @@ testSolver(const boost::property_tree::ptree& prm, const std::string& matrix_fil } readMatrixMarket(rhs, rhsfile); } - Dune::FlexibleSolver solver(prm, matrix); + bool transpose = false; + + if(prm.get("preconditioner.type") == "cprt"){ + transpose = true; + } + auto wc = [&matrix, &prm, transpose]() + { + return Opm::Amg::getQuasiImpesWeights(matrix, + prm.get("preconditioner.pressure_var_index"), + transpose); + }; + Dune::FlexibleSolver solver(prm, matrix, wc); Vector x(rhs.size()); Dune::InverseOperatorResult res; solver.apply(x, rhs, res); diff --git a/tests/test_preconditionerfactory.cpp b/tests/test_preconditionerfactory.cpp index 9ae0ad4f4..d1de9ce75 100644 --- a/tests/test_preconditionerfactory.cpp +++ b/tests/test_preconditionerfactory.cpp @@ -93,7 +93,19 @@ testPrec(const boost::property_tree::ptree& prm, const std::string& matrix_filen using Operator = Dune::MatrixAdapter; Operator op(matrix); using PrecFactory = Opm::PreconditionerFactory; - auto prec = PrecFactory::create(op, prm.get_child("preconditioner")); + bool transpose = false; + + if(prm.get("preconditioner.type") == "cprt"){ + transpose = true; + } + auto wc = [&matrix, &prm, transpose]() + { + return Opm::Amg::getQuasiImpesWeights(matrix, + prm.get("preconditioner.pressure_var_index"), + transpose); + }; + auto prec = PrecFactory::create(op, prm.get_child("preconditioner"), wc); Dune::BiCGSTABSolver solver(op, *prec, prm.get("tol"), prm.get("maxiter"), prm.get("verbosity")); Vector x(rhs.size()); Dune::InverseOperatorResult res; @@ -194,7 +206,7 @@ BOOST_AUTO_TEST_CASE(TestAddingPreconditioner) // Add preconditioner to factory for block size 1. - PF<1>::addCreator("nothing", [](const O<1>&, const pt::ptree&) { + PF<1>::addCreator("nothing", [](const O<1>&, const pt::ptree&, const std::function()>&) { return Dune::wrapPreconditioner>>(); }); @@ -209,7 +221,7 @@ BOOST_AUTO_TEST_CASE(TestAddingPreconditioner) } // Add preconditioner to factory for block size 3. - PF<3>::addCreator("nothing", [](const O<3>&, const pt::ptree&) { + PF<3>::addCreator("nothing", [](const O<3>&, const pt::ptree&, const std::function()>&) { return Dune::wrapPreconditioner>>(); });