FlexibleSolver_impl.hpp
Go to the documentation of this file.
1/*
2 Copyright 2019, 2020 SINTEF Digital, Mathematics and Cybernetics.
3 Copyright 2020 Equinor.
4
5 This file is part of the Open Porous Media project (OPM).
6
7 OPM is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 OPM is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with OPM. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#ifndef OPM_FLEXIBLE_SOLVER_IMPL_HEADER_INCLUDED
22#define OPM_FLEXIBLE_SOLVER_IMPL_HEADER_INCLUDED
23
24#include <opm/common/ErrorMacros.hpp>
25#include <opm/common/TimingMacros.hpp>
26#include <opm/simulators/linalg/matrixblock.hh>
27#include <opm/simulators/linalg/ilufirstelement.hh>
32
33#include <dune/common/fmatrix.hh>
34#include <dune/istl/bcrsmatrix.hh>
35#include <dune/istl/solvers.hh>
36#include <dune/istl/umfpack.hh>
37#include <dune/istl/owneroverlapcopy.hh>
38#include <dune/istl/paamg/pinfo.hh>
39
40#if HAVE_CUDA
42#endif
43
44namespace Dune
45{
47 template <class Operator>
49 FlexibleSolver(Operator& op,
50 const Opm::PropertyTree& prm,
51 const std::function<VectorType()>& weightsCalculator,
52 std::size_t pressureIndex)
53 {
54 init(op, Dune::Amg::SequentialInformation(), prm, weightsCalculator,
55 pressureIndex);
56 }
57
59 template <class Operator>
60 template <class Comm>
62 FlexibleSolver(Operator& op,
63 const Comm& comm,
64 const Opm::PropertyTree& prm,
65 const std::function<VectorType()>& weightsCalculator,
66 std::size_t pressureIndex)
67 {
68 init(op, comm, prm, weightsCalculator, pressureIndex);
69 }
70
71 template <class Operator>
72 void
75 {
76 if (direct_solver_) {
77 recreateDirectSolver();
78 }
79 linsolver_->apply(x, rhs, res);
80 }
81
82 template <class Operator>
83 void
85 apply(VectorType& x, VectorType& rhs, double reduction, Dune::InverseOperatorResult& res)
86 {
87 if (direct_solver_) {
88 recreateDirectSolver();
89 }
90 linsolver_->apply(x, rhs, reduction, res);
91 }
92
94 template <class Operator>
95 auto
98 {
99 return *preconditioner_;
100 }
101
102 template <class Operator>
103 Dune::SolverCategory::Category
105 category() const
106 {
107 return linearoperator_for_solver_->category();
108 }
109
110 // Machinery for making sequential or parallel operators/preconditioners/scalar products.
111 template <class Operator>
112 template <class Comm>
113 void
115 initOpPrecSp(Operator& op,
116 const Opm::PropertyTree& prm,
117 const std::function<VectorType()> weightsCalculator,
118 const Comm& comm,
119 std::size_t pressureIndex)
120 {
121 // Parallel case.
122 linearoperator_for_solver_ = &op;
123 auto child = prm.get_child_optional("preconditioner");
125 child ? *child : Opm::PropertyTree(),
126 weightsCalculator,
127 comm,
128 pressureIndex);
129 scalarproduct_ = Dune::createScalarProduct<VectorType, Comm>(comm, op.category());
130 }
131
132 template <class Operator>
133 void
134 FlexibleSolver<Operator>::
135 initOpPrecSp(Operator& op,
136 const Opm::PropertyTree& prm,
137 const std::function<VectorType()> weightsCalculator,
138 const Dune::Amg::SequentialInformation&,
139 std::size_t pressureIndex)
140 {
141 // Sequential case.
142 linearoperator_for_solver_ = &op;
143 auto child = prm.get_child_optional("preconditioner");
145 child ? *child : Opm::PropertyTree(),
146 weightsCalculator,
147 pressureIndex);
148 scalarproduct_ = std::make_shared<Dune::SeqScalarProduct<VectorType>>();
149 }
150
151 template <class Operator>
152 void
153 FlexibleSolver<Operator>::
154 initSolver(const Opm::PropertyTree& prm, const bool is_iorank)
155 {
156 const double tol = prm.get<double>("tol", 1e-2);
157 const int maxiter = prm.get<int>("maxiter", 200);
158 const int verbosity = is_iorank ? prm.get<int>("verbosity", 0) : 0;
159 const std::string solver_type = prm.get<std::string>("solver", "bicgstab");
160 if (solver_type == "bicgstab") {
161 linsolver_ = std::make_shared<Dune::BiCGSTABSolver<VectorType>>(*linearoperator_for_solver_,
162 *scalarproduct_,
163 *preconditioner_,
164 tol, // desired residual reduction factor
165 maxiter, // maximum number of iterations
166 verbosity);
167 } else if (solver_type == "loopsolver") {
168 linsolver_ = std::make_shared<Dune::LoopSolver<VectorType>>(*linearoperator_for_solver_,
169 *scalarproduct_,
170 *preconditioner_,
171 tol, // desired residual reduction factor
172 maxiter, // maximum number of iterations
173 verbosity);
174 } else if (solver_type == "gmres") {
175 int restart = prm.get<int>("restart", 15);
176 linsolver_ = std::make_shared<Dune::RestartedGMResSolver<VectorType>>(*linearoperator_for_solver_,
177 *scalarproduct_,
178 *preconditioner_,
179 tol,// desired residual reduction factor
180 restart,
181 maxiter, // maximum number of iterations
182 verbosity);
183 } else if (solver_type == "flexgmres") {
184 int restart = prm.get<int>("restart", 15);
185 linsolver_ = std::make_shared<Dune::RestartedFlexibleGMResSolver<VectorType>>(*linearoperator_for_solver_,
186 *scalarproduct_,
187 *preconditioner_,
188 tol,// desired residual reduction factor
189 restart,
190 maxiter, // maximum number of iterations
191 verbosity);
192#if HAVE_SUITESPARSE_UMFPACK
193 } else if (solver_type == "umfpack") {
194 using MatrixType = std::remove_const_t<std::remove_reference_t<decltype(linearoperator_for_solver_->getmat())>>;
195 linsolver_ = std::make_shared<Dune::UMFPack<MatrixType>>(linearoperator_for_solver_->getmat(), verbosity, false);
196 direct_solver_ = true;
197#endif
198#if HAVE_CUDA
199 } else if (solver_type == "cubicgstab") {
201 *linearoperator_for_solver_,
202 *scalarproduct_,
203 preconditioner_,
204 tol, // desired residual reduction factor
205 maxiter, // maximum number of iterations
206 verbosity));
207#endif
208 } else {
209 OPM_THROW(std::invalid_argument,
210 "Properties: Solver " + solver_type + " not known.");
211 }
212 }
213
214
215 // For now, the only direct solver we support is UMFPACK from SuiteSparse.
216 // When the matrix is updated (keeping sparsity pattern) it is possible to
217 // exploit separation of symbolic and numeric factorization, but we do not
218 // do so at this point. For complete generality, the solver abstract class
219 // Dune::InverseOperator<> should be extended with an update() function.
220 template <class Operator>
221 void
222 FlexibleSolver<Operator>::
223 recreateDirectSolver()
224 {
225#if HAVE_SUITESPARSE_UMFPACK
226 using MatrixType = std::remove_const_t<std::remove_reference_t<decltype(linearoperator_for_solver_->getmat())>>;
227 linsolver_ = std::make_shared<Dune::UMFPack<MatrixType>>(linearoperator_for_solver_->getmat(), 0, false);
228#else
229 OPM_THROW(std::logic_error, "Direct solver specified, but the FlexibleSolver class was not compiled with SuiteSparse support.");
230#endif
231 }
232
233
234 // Main initialization routine.
235 // Call with Comm == Dune::Amg::SequentialInformation to get a serial solver.
236 template <class Operator>
237 template <class Comm>
238 void
239 FlexibleSolver<Operator>::
240 init(Operator& op,
241 const Comm& comm,
242 const Opm::PropertyTree& prm,
243 const std::function<VectorType()> weightsCalculator,
244 std::size_t pressureIndex)
245 {
246 initOpPrecSp(op, prm, weightsCalculator, comm, pressureIndex);
247 initSolver(prm, comm.communicator().rank() == 0);
248 }
249
250} // namespace Dune
251
252
253// Macros to simplify explicit instantiation of FlexibleSolver for various block sizes.
254
255// Vectors and matrices.
256template <int N>
257using BV = Dune::BlockVector<Dune::FieldVector<double, N>>;
258template <int N>
259using OBM = Dune::BCRSMatrix<Opm::MatrixBlock<double, N, N>>;
260
261// Sequential operators.
262template <int N>
263using SeqOpM = Dune::MatrixAdapter<OBM<N>, BV<N>, BV<N>>;
264template <int N>
266
267#if HAVE_MPI
268
269// Parallel communicator and operators.
270using Comm = Dune::OwnerOverlapCopyCommunication<int, int>;
271template <int N>
272using ParOpM = Dune::OverlappingSchwarzOperator<OBM<N>, BV<N>, BV<N>, Comm>;
273template <int N>
275
276// Note: we must instantiate the constructor that is a template.
277// This is only needed in the parallel case, since otherwise the Comm type is
278// not a template argument but always SequentialInformation.
279
280#define INSTANTIATE_FLEXIBLESOLVER_OP(Operator) \
281template class Dune::FlexibleSolver<Operator>; \
282template Dune::FlexibleSolver<Operator>::FlexibleSolver(Operator& op, \
283 const Comm& comm, \
284 const Opm::PropertyTree& prm, \
285 const std::function<typename Operator::domain_type()>& weightsCalculator, \
286 std::size_t pressureIndex);
287#define INSTANTIATE_FLEXIBLESOLVER(N) \
288INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpM<N>); \
289INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpW<N>); \
290INSTANTIATE_FLEXIBLESOLVER_OP(ParOpM<N>); \
291INSTANTIATE_FLEXIBLESOLVER_OP(ParOpW<N>);
292
293#else // HAVE_MPI
294
295#define INSTANTIATE_FLEXIBLESOLVER_OP(Operator) \
296template class Dune::FlexibleSolver<Operator>;
297
298#define INSTANTIATE_FLEXIBLESOLVER(N) \
299INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpM<N>); \
300INSTANTIATE_FLEXIBLESOLVER_OP(SeqOpW<N>);
301
302#endif // HAVE_MPI
303
304
305
306#endif // OPM_FLEXIBLE_SOLVER_IMPL_HEADER_INCLUDED
Dune::OverlappingSchwarzOperator< OBM< N >, BV< N >, BV< N >, Comm > ParOpM
Definition: FlexibleSolver_impl.hpp:272
Dune::BlockVector< Dune::FieldVector< double, N > > BV
Definition: FlexibleSolver_impl.hpp:257
Dune::OwnerOverlapCopyCommunication< int, int > Comm
Definition: FlexibleSolver_impl.hpp:270
Dune::BCRSMatrix< Opm::MatrixBlock< double, N, N > > OBM
Definition: FlexibleSolver_impl.hpp:259
Dune::MatrixAdapter< OBM< N >, BV< N >, BV< N > > SeqOpM
Definition: FlexibleSolver_impl.hpp:263
Definition: FlexibleSolver.hpp:45
virtual Dune::SolverCategory::Category category() const override
Definition: FlexibleSolver_impl.hpp:105
virtual void apply(VectorType &x, VectorType &rhs, Dune::InverseOperatorResult &res) override
Definition: FlexibleSolver_impl.hpp:74
typename Operator::domain_type VectorType
Definition: FlexibleSolver.hpp:47
FlexibleSolver(Operator &op, const Opm::PropertyTree &prm, const std::function< VectorType()> &weightsCalculator, std::size_t pressureIndex)
Create a sequential solver.
Definition: FlexibleSolver_impl.hpp:49
AbstractPrecondType & preconditioner()
Access the contained preconditioner.
Definition: FlexibleSolver_impl.hpp:97
static PrecPtr create(const Operator &op, const PropertyTree &prm, const std::function< Vector()> &weightsCalculator={}, std::size_t pressureIndex=std::numeric_limits< std::size_t >::max())
Definition: PreconditionerFactory_impl.hpp:702
Definition: PropertyTree.hpp:37
T get(const std::string &key) const
std::optional< PropertyTree > get_child_optional(const std::string &key) const
Adapter to combine a matrix and another linear operator into a combined linear operator.
Definition: WellOperators.hpp:224
Adapter to combine a matrix and another linear operator into a combined linear operator.
Definition: WellOperators.hpp:134
Wraps a CUDA solver to work with CPU data.
Definition: SolverAdapter.hpp:51
Definition: SupportsFaceTag.hpp:27
Dune::InverseOperatorResult InverseOperatorResult
Definition: BdaBridge.hpp:32