version 3.8
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
36
38
39template <class Solver, class Matrix>
40using SetMatrixDetector = decltype(std::declval<Solver>().setMatrix(std::declval<std::shared_ptr<Matrix>>()));
41
42template<class Solver, class Matrix>
43static constexpr bool linearSolverHasSetMatrix()
44{ return Dune::Std::is_detected<SetMatrixDetector, Solver, Matrix>::value; }
45
46} // end namespace Dumux::Detail::LinearPDESolver
47
48namespace Dumux {
49
60template <class Assembler, class LinearSolver,
61 class Comm = Dune::Communication<Dune::MPIHelper::MPICommunicator>>
62class LinearPDESolver : public PDESolver<Assembler, LinearSolver>
63{
65 using Scalar = typename Assembler::Scalar;
66 using JacobianMatrix = typename Assembler::JacobianMatrix;
67 using SolutionVector = typename Assembler::SolutionVector;
68 using ResidualVector = typename Assembler::ResidualType;
72 static constexpr bool assemblerExportsVariables = Detail::PDESolver::assemblerExportsVariables<Assembler>;
73
74public:
75 using typename ParentType::Variables;
76 using Communication = Comm;
77
81 LinearPDESolver(std::shared_ptr<Assembler> assembler,
82 std::shared_ptr<LinearSolver> linearSolver,
83 const Communication& comm = Dune::MPIHelper::getCommunication(),
84 const std::string& paramGroup = "")
86 , paramGroup_(paramGroup)
87 , reuseMatrix_(false)
88 , comm_(comm)
89 {
90 initParams_(paramGroup);
91
92 // set the linear system (matrix & residual) in the assembler
93 this->assembler().setLinearSystem();
94 }
95
99 LinearPDESolver(std::shared_ptr<Assembler> assembler,
100 std::shared_ptr<LinearSolver> linearSolver,
101 const std::string& paramGroup)
102 : LinearPDESolver(assembler, linearSolver, Dune::MPIHelper::getCommunication(), paramGroup)
103 {}
104
108 bool apply(Variables& vars) override
109 {
110 Dune::Timer assembleTimer(false);
111 Dune::Timer solveTimer(false);
112 Dune::Timer updateTimer(false);
113
114 if (verbose_ && enableDynamicOutput_)
115 std::cout << "Assemble: r(x^k) = dS/dt + div F - q; M = grad r"
116 << std::flush;
117
119 // assemble
121
122 // linearize the problem at the current solution
123 assembleTimer.start();
124 if (reuseMatrix_)
125 this->assembler().assembleResidual(vars);
126 else
127 this->assembler().assembleJacobianAndResidual(vars);
128 assembleTimer.stop();
129
131 // linear solve
133
134 // Clear the current line using an ansi escape
135 // sequence. for an explanation see
136 // http://en.wikipedia.org/wiki/ANSI_escape_code
137 const char clearRemainingLine[] = { 0x1b, '[', 'K', 0 };
138
139 if (verbose_ && enableDynamicOutput_)
140 std::cout << "\rSolve: M deltax^k = r"
141 << clearRemainingLine << std::flush;
142
143 // solve the resulting linear equation system
144 solveTimer.start();
145
146 // set the delta vector to zero
147 ResidualVector deltaU = LinearAlgebraNativeBackend::zeros(Backend::size(Backend::dofs(vars)));
148
149 // solve by calling the appropriate implementation depending on whether the linear solver
150 // is capable of handling MultiType matrices or not
151 bool converged = solveLinearSystem_(deltaU);
152 solveTimer.stop();
153
154 if (!converged)
155 return false;
156
158 // update
160 if (verbose_ && enableDynamicOutput_)
161 std::cout << "\rUpdate: x^(k+1) = x^k - deltax^k"
162 << clearRemainingLine << std::flush;
163
164 // update the current solution and secondary variables
165 updateTimer.start();
166 auto uCurrent = Backend::dofs(vars);
167 Backend::axpy(-1.0, deltaU, uCurrent);
168 Backend::update(vars, uCurrent);
169 if constexpr (!assemblerExportsVariables)
170 this->assembler().updateGridVariables(Backend::dofs(vars));
171 updateTimer.stop();
172
173 if (verbose_)
174 {
175 const auto elapsedTot = assembleTimer.elapsed() + solveTimer.elapsed() + updateTimer.elapsed();
176 if (enableDynamicOutput_)
177 std::cout << '\r';
178 std::cout << "Assemble/solve/update time: "
179 << assembleTimer.elapsed() << "(" << 100*assembleTimer.elapsed()/elapsedTot << "%)/"
180 << solveTimer.elapsed() << "(" << 100*solveTimer.elapsed()/elapsedTot << "%)/"
181 << updateTimer.elapsed() << "(" << 100*updateTimer.elapsed()/elapsedTot << "%)"
182 << "\n";
183 }
184
185 return true;
186 }
187
191 void solve(Variables& vars) override
192 {
193 bool converged = apply(vars);
194 if (!converged)
195 DUNE_THROW(NumericalProblem, "Linear solver didn't converge.\n");
196 }
197
202 void report(std::ostream& sout = std::cout) const
203 {}
204
209 Scalar suggestTimeStepSize(Scalar oldTimeStep) const
210 {
211 return oldTimeStep;
212 }
213
217 void setVerbose(bool val)
218 { verbose_ = val; }
219
223 bool verbose() const
224 { return verbose_ ; }
225
229 const std::string& paramGroup() const
230 { return paramGroup_; }
231
238 void reuseMatrix(bool reuse = true)
239 {
240 reuseMatrix_ = reuse;
241
242 if constexpr (Detail::LinearPDESolver::linearSolverHasSetMatrix<LinearSolver, JacobianMatrix>())
243 if (reuseMatrix_)
244 this->linearSolver().setMatrix(this->assembler().jacobian());
245 }
246
247private:
248
249 virtual bool solveLinearSystem_(ResidualVector& deltaU)
250 {
251 if constexpr (Detail::LinearPDESolver::linearSolverHasSetMatrix<LinearSolver, JacobianMatrix>())
252 {
253 if (reuseMatrix_)
254 return this->linearSolver().solve(deltaU, this->assembler().residual());
255 }
256 else
257 {
258 if (reuseMatrix_ && comm_.size() > 1)
259 DUNE_THROW(Dune::NotImplemented,
260 "Reuse matrix for parallel runs with a solver that doesn't support the setMatrix interface"
261 );
262 }
263
264 assert(this->checkSizesOfSubMatrices(this->assembler().jacobian()) && "Matrix blocks have wrong sizes!");
265
266 return this->linearSolver().solve(
267 this->assembler().jacobian(),
268 deltaU,
269 this->assembler().residual()
270 );
271 }
272
274 void initParams_(const std::string& group = "")
275 {
276 verbose_ = (Dune::MPIHelper::getCommunication().rank() == 0);
277 enableDynamicOutput_ = getParamFromGroup<bool>(group, "LinearPDESolver.EnableDynamicOutput", true);
278 }
279
281 bool verbose_;
282
284 bool enableDynamicOutput_;
285
287 std::string paramGroup_;
288
290 bool reuseMatrix_;
291
293 Communication comm_;
294};
295
296} // end namespace Dumux
297
298#endif
Definition: variablesbackend.hh:159
An implementation of a linear PDE solver.
Definition: linear/pdesolver.hh:63
LinearPDESolver(std::shared_ptr< Assembler > assembler, std::shared_ptr< LinearSolver > linearSolver, const std::string &paramGroup)
The Constructor.
Definition: linear/pdesolver.hh:99
bool verbose() const
Returns true if the solver ought to be chatty.
Definition: linear/pdesolver.hh:223
void reuseMatrix(bool reuse=true)
Set whether the matrix should be reused.
Definition: linear/pdesolver.hh:238
void solve(Variables &vars) override
Solve a linear PDE system.
Definition: linear/pdesolver.hh:191
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:81
Comm Communication
Definition: linear/pdesolver.hh:76
const std::string & paramGroup() const
Returns the parameter group.
Definition: linear/pdesolver.hh:229
Scalar suggestTimeStepSize(Scalar oldTimeStep) const
Suggest a new time-step size based on the old time-step size.
Definition: linear/pdesolver.hh:209
void report(std::ostream &sout=std::cout) const
output statistics / report
Definition: linear/pdesolver.hh:202
bool apply(Variables &vars) override
Solve a linear PDE system.
Definition: linear/pdesolver.hh:108
void setVerbose(bool val)
Specifies if the solver ought to be chatty.
Definition: linear/pdesolver.hh:217
Base class for linear solvers.
Definition: solver.hh:27
Exception thrown if a fixable numerical problem occurs.
Definition: exceptions.hh:27
A high-level interface for a PDESolver.
Definition: common/pdesolver.hh:61
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:148
const LinearSolver & linearSolver() const
Access the linear solver.
Definition: common/pdesolver.hh:133
const Assembler & assembler() const
Access the assembler.
Definition: common/pdesolver.hh:121
Detail::PDESolver::AssemblerVariables< Assembler > Variables
export the type of variables that represent a numerical solution
Definition: common/pdesolver.hh:71
Defines a high-level interface for a PDESolver.
Manages the handling of time dependent problems.
Some exceptions thrown in DuMux
A helper class that converts a Dune::MultiTypeBlockMatrix into a plain Dune::BCRSMatrix.
Definition: linear/pdesolver.hh:37
decltype(std::declval< Solver >().setMatrix(std::declval< std::shared_ptr< Matrix > >())) SetMatrixDetector
Definition: linear/pdesolver.hh:40
static constexpr bool linearSolverHasSetMatrix()
Definition: linear/pdesolver.hh:43
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.