version 3.7
linear/pdesolver.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_LINEAR_PDE_SOLVER_HH
13#define DUMUX_LINEAR_PDE_SOLVER_HH
14
15#include <cmath>
16#include <memory>
17#include <iostream>
18#include <type_traits>
19
20#include <dune/common/timer.hh>
21#include <dune/common/exceptions.hh>
22#include <dune/common/parallel/mpicommunication.hh>
23#include <dune/common/parallel/mpihelper.hh>
24#include <dune/common/std/type_traits.hh>
25#include <dune/istl/bvector.hh>
26#include <dune/istl/multitypeblockvector.hh>
27
34
35// remove after deprecated code is removed (after 3.7)
36#define DUMUX_SUPPRESS_LINEAR_SOLVER_ACCEPTS_MULTITYPEMATRIX_WARNING
38#undef DUMUX_SUPPRESS_LINEAR_SOLVER_ACCEPTS_MULTITYPEMATRIX_WARNING
39
41
43
44template <class Solver, class Matrix>
45using SetMatrixDetector = decltype(std::declval<Solver>().setMatrix(std::declval<std::shared_ptr<Matrix>>()));
46
47template<class Solver, class Matrix>
48static constexpr bool linearSolverHasSetMatrix()
49{ return Dune::Std::is_detected<SetMatrixDetector, Solver, Matrix>::value; }
50
51} // end namespace Dumux::Detail::LinearPDESolver
52
53namespace Dumux {
54
65template <class Assembler, class LinearSolver,
66 class Comm = Dune::Communication<Dune::MPIHelper::MPICommunicator>>
67class LinearPDESolver : public PDESolver<Assembler, LinearSolver>
68{
70 using Scalar = typename Assembler::Scalar;
71 using JacobianMatrix = typename Assembler::JacobianMatrix;
72 using SolutionVector = typename Assembler::SolutionVector;
73 using ResidualVector = typename Assembler::ResidualType;
77 static constexpr bool assemblerExportsVariables = Detail::PDESolver::assemblerExportsVariables<Assembler>;
78
79public:
80 using typename ParentType::Variables;
81 using Communication = Comm;
82
86 LinearPDESolver(std::shared_ptr<Assembler> assembler,
87 std::shared_ptr<LinearSolver> linearSolver,
88 const Communication& comm = Dune::MPIHelper::getCommunication(),
89 const std::string& paramGroup = "")
91 , paramGroup_(paramGroup)
92 , reuseMatrix_(false)
93 , comm_(comm)
94 {
95 initParams_(paramGroup);
96
97 // set the linear system (matrix & residual) in the assembler
98 this->assembler().setLinearSystem();
99 }
100
104 LinearPDESolver(std::shared_ptr<Assembler> assembler,
105 std::shared_ptr<LinearSolver> linearSolver,
106 const std::string& paramGroup)
107 : LinearPDESolver(assembler, linearSolver, Dune::MPIHelper::getCommunication(), paramGroup)
108 {}
109
113 void solve(Variables& vars) override
114 {
115 Dune::Timer assembleTimer(false);
116 Dune::Timer solveTimer(false);
117 Dune::Timer updateTimer(false);
118
119 if (verbose_ && enableDynamicOutput_)
120 std::cout << "Assemble: r(x^k) = dS/dt + div F - q; M = grad r"
121 << std::flush;
122
124 // assemble
126
127 // linearize the problem at the current solution
128 assembleTimer.start();
129 if (reuseMatrix_)
130 this->assembler().assembleResidual(vars);
131 else
132 this->assembler().assembleJacobianAndResidual(vars);
133 assembleTimer.stop();
134
136 // linear solve
138
139 // Clear the current line using an ansi escape
140 // sequence. for an explanation see
141 // http://en.wikipedia.org/wiki/ANSI_escape_code
142 const char clearRemainingLine[] = { 0x1b, '[', 'K', 0 };
143
144 if (verbose_ && enableDynamicOutput_)
145 std::cout << "\rSolve: M deltax^k = r"
146 << clearRemainingLine << std::flush;
147
148 // solve the resulting linear equation system
149 solveTimer.start();
150
151 // set the delta vector to zero
152 ResidualVector deltaU = LinearAlgebraNativeBackend::zeros(Backend::size(Backend::dofs(vars)));
153
154 // solve by calling the appropriate implementation depending on whether the linear solver
155 // is capable of handling MultiType matrices or not
156 bool converged = solveLinearSystem_(deltaU);
157 solveTimer.stop();
158
159 if (!converged)
160 DUNE_THROW(NumericalProblem, "Linear solver didn't converge.\n");
161
163 // update
165 if (verbose_ && enableDynamicOutput_)
166 std::cout << "\rUpdate: x^(k+1) = x^k - deltax^k"
167 << clearRemainingLine << std::flush;
168
169 // update the current solution and secondary variables
170 updateTimer.start();
171 auto uCurrent = Backend::dofs(vars);
172 Backend::axpy(-1.0, deltaU, uCurrent);
173 Backend::update(vars, uCurrent);
174 if constexpr (!assemblerExportsVariables)
175 this->assembler().updateGridVariables(Backend::dofs(vars));
176 updateTimer.stop();
177
178 if (verbose_)
179 {
180 const auto elapsedTot = assembleTimer.elapsed() + solveTimer.elapsed() + updateTimer.elapsed();
181 if (enableDynamicOutput_)
182 std::cout << '\r';
183 std::cout << "Assemble/solve/update time: "
184 << assembleTimer.elapsed() << "(" << 100*assembleTimer.elapsed()/elapsedTot << "%)/"
185 << solveTimer.elapsed() << "(" << 100*solveTimer.elapsed()/elapsedTot << "%)/"
186 << updateTimer.elapsed() << "(" << 100*updateTimer.elapsed()/elapsedTot << "%)"
187 << "\n";
188 }
189 }
190
195 void report(std::ostream& sout = std::cout) const
196 {}
197
202 Scalar suggestTimeStepSize(Scalar oldTimeStep) const
203 {
204 return oldTimeStep;
205 }
206
210 void setVerbose(bool val)
211 { verbose_ = val; }
212
216 bool verbose() const
217 { return verbose_ ; }
218
222 const std::string& paramGroup() const
223 { return paramGroup_; }
224
231 void reuseMatrix(bool reuse = true)
232 {
233 reuseMatrix_ = reuse;
234
235 if constexpr (Detail::LinearPDESolver::linearSolverHasSetMatrix<LinearSolver, JacobianMatrix>())
236 if (reuseMatrix_)
237 this->linearSolver().setMatrix(this->assembler().jacobian());
238 }
239
240private:
241
242 virtual bool solveLinearSystem_(ResidualVector& deltaU)
243 {
244 if constexpr (Detail::LinearPDESolver::linearSolverHasSetMatrix<LinearSolver, JacobianMatrix>())
245 {
246 if (reuseMatrix_)
247 return this->linearSolver().solve(deltaU, this->assembler().residual());
248 }
249 else
250 {
251 if (reuseMatrix_ && comm_.size() > 1)
252 DUNE_THROW(Dune::NotImplemented,
253 "Reuse matrix for parallel runs with a solver that doesn't support the setMatrix interface"
254 );
255 }
256
257 return solveLinearSystemImpl_(this->linearSolver(),
258 this->assembler().jacobian(),
259 deltaU,
260 this->assembler().residual());
261 }
262
272 template<class V = ResidualVector>
273 typename std::enable_if_t<!isMultiTypeBlockVector<V>(), bool>
274 solveLinearSystemImpl_(LinearSolver& ls,
275 JacobianMatrix& A,
276 ResidualVector& x,
277 ResidualVector& b)
278 {
279 return ls.solve(A, x, b);
280 }
281
282
292 template<class LS = LinearSolver, class V = ResidualVector>
293 typename std::enable_if_t<linearSolverAcceptsMultiTypeMatrix<LS>() &&
294 isMultiTypeBlockVector<V>(), bool>
295 solveLinearSystemImpl_(LinearSolver& ls,
296 JacobianMatrix& A,
297 ResidualVector& x,
298 ResidualVector& b)
299 {
300 assert(this->checkSizesOfSubMatrices(A) && "Sub-blocks of MultiTypeBlockMatrix have wrong sizes!");
301 return ls.solve(A, x, b);
302 }
303
314 template<class LS = LinearSolver, class V = ResidualVector>
315 [[deprecated("After 3.7 LinearPDESolver will no longer support conversion of multitype matrices for solvers that don't support this feature!")]]
316 typename std::enable_if_t<!linearSolverAcceptsMultiTypeMatrix<LS>() &&
317 isMultiTypeBlockVector<V>(), bool>
318 solveLinearSystemImpl_(LinearSolver& ls,
319 JacobianMatrix& A,
320 ResidualVector& x,
321 ResidualVector& b)
322 {
323 assert(this->checkSizesOfSubMatrices(A) && "Sub-blocks of MultiTypeBlockMatrix have wrong sizes!");
324
325 // create the bcrs matrix the IterativeSolver backend can handle
327
328 // get the new matrix sizes
329 const std::size_t numRows = M.N();
330 assert(numRows == M.M());
331
332 // create the vector the IterativeSolver backend can handle
334 assert(bTmp.size() == numRows);
335
336 // create a blockvector to which the linear solver writes the solution
337 using VectorBlock = typename Dune::FieldVector<Scalar, 1>;
338 using BlockVector = typename Dune::BlockVector<VectorBlock>;
339 BlockVector y(numRows);
340
341 // solve
342 const bool converged = ls.solve(M, y, bTmp);
343
344 // copy back the result y into x
345 if(converged)
347
348 return converged;
349 }
350
352 void initParams_(const std::string& group = "")
353 {
354 verbose_ = (Dune::MPIHelper::getCommunication().rank() == 0);
355 enableDynamicOutput_ = getParamFromGroup<bool>(group, "LinearPDESolver.EnableDynamicOutput", true);
356 }
357
359 bool verbose_;
360
362 bool enableDynamicOutput_;
363
365 std::string paramGroup_;
366
368 bool reuseMatrix_;
369
371 Communication comm_;
372};
373
374} // end namespace Dumux
375
376#endif
Definition: variablesbackend.hh:159
An implementation of a linear PDE solver.
Definition: linear/pdesolver.hh:68
LinearPDESolver(std::shared_ptr< Assembler > assembler, std::shared_ptr< LinearSolver > linearSolver, const std::string &paramGroup)
The Constructor.
Definition: linear/pdesolver.hh:104
bool verbose() const
Returns true if the solver ought to be chatty.
Definition: linear/pdesolver.hh:216
void reuseMatrix(bool reuse=true)
Set whether the matrix should be reused.
Definition: linear/pdesolver.hh:231
void solve(Variables &vars) override
Solve a linear PDE system.
Definition: linear/pdesolver.hh:113
LinearPDESolver(std::shared_ptr< Assembler > assembler, std::shared_ptr< LinearSolver > linearSolver, const Communication &comm=Dune::MPIHelper::getCommunication(), const std::string &paramGroup="")
The Constructor.
Definition: linear/pdesolver.hh:86
Comm Communication
Definition: linear/pdesolver.hh:81
const std::string & paramGroup() const
Returns the parameter group.
Definition: linear/pdesolver.hh:222
Scalar suggestTimeStepSize(Scalar oldTimeStep) const
Suggest a new time-step size based on the old time-step size.
Definition: linear/pdesolver.hh:202
void report(std::ostream &sout=std::cout) const
output statistics / report
Definition: linear/pdesolver.hh:195
void setVerbose(bool val)
Specifies if the solver ought to be chatty.
Definition: linear/pdesolver.hh:210
Base class for linear solvers.
Definition: solver.hh:27
static auto multiTypeToBCRSMatrix(const MultiTypeBlockMatrix &A)
Converts the matrix to a type the IterativeSolverBackend can handle.
Definition: matrixconverter.hh:46
Exception thrown if a fixable numerical problem occurs.
Definition: exceptions.hh:27
A high-level interface for a PDESolver.
Definition: common/pdesolver.hh:61
LinearSolver LinearSolver
Definition: common/pdesolver.hh:68
bool checkSizesOfSubMatrices(const Dune::MultiTypeBlockMatrix< FirstRow, Args... > &matrix) const
Helper function to assure the MultiTypeBlockMatrix's sub-blocks have the correct sizes.
Definition: common/pdesolver.hh:137
const LinearSolver & linearSolver() const
Access the linear solver.
Definition: common/pdesolver.hh:122
const Assembler & assembler() const
Access the assembler.
Definition: common/pdesolver.hh:110
Detail::PDESolver::AssemblerVariables< Assembler > Variables
export the type of variables that represent a numerical solution
Definition: common/pdesolver.hh:71
Manages the handling of time dependent problems.
Definition: common/timeloop.hh:56
static void retrieveValues(MultiTypeBlockVector &x, const BlockVector &y)
Copies the entries of a Dune::BlockVector to a Dune::MultiTypeBlockVector.
Definition: matrixconverter.hh:229
static auto multiTypeToBlockVector(const MultiTypeBlockVector &b)
Converts a Dune::MultiTypeBlockVector to a plain 1x1 Dune::BlockVector.
Definition: matrixconverter.hh:203
Defines a high-level interface for a PDESolver.
Manages the handling of time dependent problems.
Some exceptions thrown in DuMux
Trait checking if linear solvers accept Dune::MultiTypeBlockMatrix or we need to convert the matrix.
A helper class that converts a Dune::MultiTypeBlockMatrix into a plain Dune::BCRSMatrix.
Definition: linear/pdesolver.hh:42
decltype(std::declval< Solver >().setMatrix(std::declval< std::shared_ptr< Matrix > >())) SetMatrixDetector
Definition: linear/pdesolver.hh:45
static constexpr bool linearSolverHasSetMatrix()
Definition: linear/pdesolver.hh:48
Definition: adapt.hh:17
Definition: common/pdesolver.hh:24
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Backends for operations on different solution vector types or more generic variable classes to be use...
Type traits to be used with vector types.