/* Copyright 2019, 2020 SINTEF Digital, Mathematics and Cybernetics. Copyright 2020 Equinor. This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #ifndef OPM_FLEXIBLE_SOLVER_IMPL_HEADER_INCLUDED #define OPM_FLEXIBLE_SOLVER_IMPL_HEADER_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { /// Create a sequential solver. template FlexibleSolver:: FlexibleSolver(Operator& op, const Opm::PropertyTree& prm, const std::function& weightsCalculator, std::size_t pressureIndex) { init(op, Dune::Amg::SequentialInformation(), prm, weightsCalculator, pressureIndex); } /// Create a parallel solver (if Comm is e.g. OwnerOverlapCommunication). template template FlexibleSolver:: FlexibleSolver(Operator& op, const Comm& comm, const Opm::PropertyTree& prm, const std::function& weightsCalculator, std::size_t pressureIndex) { init(op, comm, prm, weightsCalculator, pressureIndex); } template void FlexibleSolver:: apply(VectorType& x, VectorType& rhs, Dune::InverseOperatorResult& res) { linsolver_->apply(x, rhs, res); } template void FlexibleSolver:: apply(VectorType& x, VectorType& rhs, double reduction, Dune::InverseOperatorResult& res) { linsolver_->apply(x, rhs, reduction, res); } /// Access the contained preconditioner. template auto FlexibleSolver:: preconditioner() -> AbstractPrecondType& { return *preconditioner_; } template Dune::SolverCategory::Category FlexibleSolver:: category() const { return linearoperator_for_solver_->category(); } // Machinery for making sequential or parallel operators/preconditioners/scalar products. template template void FlexibleSolver:: initOpPrecSp(Operator& op, const Opm::PropertyTree& prm, const std::function weightsCalculator, const Comm& comm, std::size_t pressureIndex) { // Parallel case. linearoperator_for_solver_ = &op; auto child = prm.get_child_optional("preconditioner"); preconditioner_ = Opm::PreconditionerFactory::create(op, child ? *child : Opm::PropertyTree(), weightsCalculator, comm, pressureIndex); scalarproduct_ = Dune::createScalarProduct(comm, op.category()); } template void FlexibleSolver:: initOpPrecSp(Operator& op, const Opm::PropertyTree& prm, const std::function weightsCalculator, const Dune::Amg::SequentialInformation&, std::size_t pressureIndex) { // Sequential case. linearoperator_for_solver_ = &op; auto child = prm.get_child_optional("preconditioner"); preconditioner_ = Opm::PreconditionerFactory::create(op, child ? *child : Opm::PropertyTree(), weightsCalculator, pressureIndex); scalarproduct_ = std::make_shared>(); } template void FlexibleSolver:: initSolver(const Opm::PropertyTree& prm, const bool is_iorank) { const double tol = prm.get("tol", 1e-2); const int maxiter = prm.get("maxiter", 200); const int verbosity = is_iorank ? prm.get("verbosity", 0) : 0; const std::string solver_type = prm.get("solver", "bicgstab"); if (solver_type == "bicgstab") { linsolver_ = std::make_shared>(*linearoperator_for_solver_, *scalarproduct_, *preconditioner_, tol, // desired residual reduction factor maxiter, // maximum number of iterations verbosity); } else if (solver_type == "loopsolver") { linsolver_ = std::make_shared>(*linearoperator_for_solver_, *scalarproduct_, *preconditioner_, tol, // desired residual reduction factor maxiter, // maximum number of iterations verbosity); } else if (solver_type == "gmres") { int restart = prm.get("restart", 15); linsolver_ = std::make_shared>(*linearoperator_for_solver_, *scalarproduct_, *preconditioner_, tol,// desired residual reduction factor restart, maxiter, // maximum number of iterations verbosity); } else if (solver_type == "flexgmres") { int restart = prm.get("restart", 15); linsolver_ = std::make_shared>(*linearoperator_for_solver_, *scalarproduct_, *preconditioner_, tol,// desired residual reduction factor restart, maxiter, // maximum number of iterations verbosity); #if HAVE_SUITESPARSE_UMFPACK } else if (solver_type == "umfpack") { bool dummy = false; using MatrixType = std::remove_const_tgetmat())>>; linsolver_ = std::make_shared>(linearoperator_for_solver_->getmat(), verbosity, dummy); #endif } else { OPM_THROW(std::invalid_argument, "Properties: Solver " + solver_type + " not known."); } } // Main initialization routine. // Call with Comm == Dune::Amg::SequentialInformation to get a serial solver. template template void FlexibleSolver:: init(Operator& op, const Comm& comm, const Opm::PropertyTree& prm, const std::function weightsCalculator, std::size_t pressureIndex) { initOpPrecSp(op, prm, weightsCalculator, comm, pressureIndex); initSolver(prm, comm.communicator().rank() == 0); } } // namespace Dune // Macros to simplify explicit instantiation of FlexibleSolver for various block sizes. // Vectors and matrices. template using BV = Dune::BlockVector>; template using OBM = Dune::BCRSMatrix>; // Sequential operators. template using SeqOpM = Dune::MatrixAdapter, BV, BV>; template using SeqOpW = Opm::WellModelMatrixAdapter, BV, BV, false>; #if HAVE_MPI // Parallel communicator and operators. using Comm = Dune::OwnerOverlapCopyCommunication; template using ParOpM = Dune::OverlappingSchwarzOperator, BV, BV, Comm>; template using ParOpW = Opm::WellModelGhostLastMatrixAdapter, BV, BV, true>; // Note: we must instantiate the constructor that is a template. // This is only needed in the parallel case, since otherwise the Comm type is // not a template argument but always SequentialInformation. #define INSTANTIATE_FLEXIBLESOLVER_OP(Operator) \ template class Dune::FlexibleSolver; \ template Dune::FlexibleSolver::FlexibleSolver(Operator& op, \ const Comm& comm, \ const Opm::PropertyTree& prm, \ const std::function& weightsCalculator, \ std::size_t pressureIndex); #define INSTANTIATE_FLEXIBLESOLVER(N) \ INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpM); \ INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpW); \ INSTANTIATE_FLEXIBLESOLVER_OP(ParOpM); \ INSTANTIATE_FLEXIBLESOLVER_OP(ParOpW); #else // HAVE_MPI #define INSTANTIATE_FLEXIBLESOLVER_OP(Operator) \ template class Dune::FlexibleSolver; #define INSTANTIATE_FLEXIBLESOLVER(N) \ INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpM); \ INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpW); #endif // HAVE_MPI #endif // OPM_FLEXIBLE_SOLVER_IMPL_HEADER_INCLUDED