DUNE PDELab (2.7)

linesearch.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_PDELAB_SOLVER_LINESEARCH_HH
4#define DUNE_PDELAB_SOLVER_LINESEARCH_HH
5
6
7namespace Dune::PDELab
8{
9
10 class LineSearchError : public Exception {};
11
13 template <typename Domain>
15 {
16 public:
19
21 virtual void lineSearch(Domain&, const Domain&) = 0;
22
24 virtual void setParameters(const ParameterTree&) = 0;
25 };
26
27
29 template <typename Solver>
30 class LineSearchNone : public LineSearchInterface<typename Solver::Domain>
31 {
32 public:
33 using Domain = typename Solver::Domain;
34 using Real = typename Solver::Real;
35
36 LineSearchNone(Solver& solver) : _solver(solver) {}
37
39 virtual void lineSearch(Domain& solution, const Domain& correction) override
40 {
41 solution.axpy(-1.0, correction);
42 _solver.updateDefect(solution);
43 }
44
45 virtual void setParameters(const ParameterTree&) override {}
46
47 private:
48 Solver& _solver;
49 };
50
51
58 template <typename Solver>
59 class LineSearchHackbuschReusken : public LineSearchInterface<typename Solver::Domain>
60 {
61 public:
62 using Domain = typename Solver::Domain;
63 using Real = typename Solver::Real;
64
65 LineSearchHackbuschReusken(Solver& solver, bool forceAcceptBest = false) :
66 _solver(solver), _forceAcceptBest(forceAcceptBest) {}
67
69 virtual void lineSearch(Domain& solution, const Domain& correction) override
70 {
71 if ((_solver.result().defect < _solver.getAbsoluteLimit())){
72 solution.axpy(-1.0, correction);
73 _solver.updateDefect(solution);
74 return;
75 }
76
77 auto verbosity = _solver.getVerbosityLevel();
78
79 if (verbosity >= 4)
80 std::cout << " Performing line search..." << std::endl;
81 Real lambda = 1.0;
82 Real bestLambda = 0.0;
83 Real bestDefect = _solver.result().defect;
84 Real previousDefect = _solver.result().defect;
85 bool converged = false;
86
87 if (not _previousSolution)
88 _previousSolution = std::make_shared<Domain>(solution);
89 else
90 *_previousSolution = solution;
91
92 for (unsigned int iteration = 0; iteration < _lineSearchMaxIterations; ++iteration){
93 if (verbosity >= 4)
94 std::cout << " trying line search damping factor: "
95 << std::setw(12) << std::setprecision(4) << std::scientific
96 << lambda
97 << std::endl;
98
99 solution.axpy(-lambda, correction);
100 _solver.updateDefect(solution);
101 if (verbosity >= 4){
102 if (not std::isfinite(_solver.result().defect))
103 std::cout << " NaNs detected" << std::endl;
104 } // ignore NaNs and try again with lower lambda
105
106 if (_solver.result().defect <= (1.0 - lambda/4) * previousDefect){
107 if (verbosity >= 4)
108 std::cout << " line search converged" << std::endl;
109 converged = true;
110 break;
111 }
112
113 if (_solver.result().defect < bestDefect){
114 bestDefect = _solver.result().defect;
115 bestLambda = lambda;
116 }
117
118 lambda *= _lineSearchDampingFactor;
119 solution = *_previousSolution;
120 }
121
122 if (not converged){
123 if (verbosity >= 4)
124 std::cout << " max line search iterations exceeded" << std::endl;
125
126 if (not (_acceptBest or _forceAcceptBest)){
127 solution = *_previousSolution;
128 _solver.updateDefect(solution);
129 DUNE_THROW( LineSearchError,
130 "LineSearch::lineSearch(): line search failed, "
131 "max iteration count reached, "
132 "defect did not improve enough");
133 }
134 else{
135 if (bestLambda == 0.0){
136 solution = *_previousSolution;
137 _solver.updateDefect(solution);
138 DUNE_THROW(LineSearchError,
139 "LineSearch::lineSearch(): line search failed, "
140 "max iteration count reached, "
141 "defect did not improve in any of the iterations");
142 }
143 if (bestLambda != lambda){
144 solution = *_previousSolution;
145 solution.axpy(-bestLambda, correction);
146 _solver.updateDefect(solution);
147 converged = true;
148 }
149 }
150 }
151
152 if (converged)
153 if (verbosity >= 4)
154 std::cout << " line search damping factor: "
155 << std::setw(12) << std::setprecision(4) << std::scientific
156 << lambda << std::endl;
157 }
158
159
160 /* \brief Set parameters
161 *
162 * Possible parameters are:
163 *
164 * - MaxIterations: Maximum number of line search iterations.
165 *
166 * - DampingFactor: Multiplier to line search parameter after each iteration.
167 *
168 * - AcceptBest: Accept the best line search parameter if
169 * there was any improvement, even if the convergence criterion was not
170 * reached.
171 */
172 virtual void setParameters(const ParameterTree& parameterTree) override
173 {
174 _lineSearchMaxIterations = parameterTree.get<unsigned int>("MaxIterations",
175 _lineSearchMaxIterations);
176 _lineSearchDampingFactor = parameterTree.get<Real>("DampingFactor",
177 _lineSearchDampingFactor);
178 _acceptBest = parameterTree.get<bool>("AcceptBest", _acceptBest);
179 }
180
181 private:
182 Solver& _solver;
183 std::shared_ptr<Domain> _previousSolution;
184
185 // Line search parameters
186 unsigned int _lineSearchMaxIterations = 10;
187 Real _lineSearchDampingFactor = 0.5;
188 bool _acceptBest = false;
189 bool _forceAcceptBest;
190 };
191
193 enum class LineSearchStrategy
194 {
195 noLineSearch,
196 hackbuschReusken,
197 hackbuschReuskenAcceptBest
198 };
199
200 // we put this into an emty namespace, so that we don't violate the one-definition-rule
201 namespace {
208 inline
209 LineSearchStrategy lineSearchStrategyFromString (const std::string& name)
210 {
211 if (name == "noLineSearch")
212 return LineSearchStrategy::noLineSearch;
213 if (name == "hackbuschReusken")
214 return LineSearchStrategy::hackbuschReusken;
215 if (name == "hackbuschReuskenAcceptBest")
216 return LineSearchStrategy::hackbuschReuskenAcceptBest;
217 DUNE_THROW(Exception,"Unkown line search strategy: " << name);
218 }
219 }
220
221
232 template <typename Solver>
233 std::shared_ptr<LineSearchInterface<typename Solver::Domain>>
234 createLineSearch(Solver& solver, LineSearchStrategy strategy)
235 {
236 if (strategy == LineSearchStrategy::noLineSearch){
237 auto lineSearch = std::make_shared<LineSearchNone<Solver>> (solver);
238 return lineSearch;
239 }
240 if (strategy == LineSearchStrategy::hackbuschReusken){
241 auto lineSearch = std::make_shared<LineSearchHackbuschReusken<Solver>> (solver);
242 return lineSearch;
243 }
244 if (strategy == LineSearchStrategy::hackbuschReuskenAcceptBest){
245 auto lineSearch = std::make_shared<LineSearchHackbuschReusken<Solver>> (solver, true);
246 std::cout << "Warning: linesearch hackbuschReuskenAcceptBest is deprecated and will be removed after PDELab 2.7.\n"
247 << " Please use 'hackbuschReusken' and add the parameter 'LineSearchAcceptBest : true'";
248 return lineSearch;
249 }
250 DUNE_THROW(Exception,"Unkown line search strategy");
251 }
252
253} // namespace Dune::PDELab
254
255#endif
Hackbusch-Reusken line search.
Definition: linesearch.hh:60
virtual void setParameters(const ParameterTree &parameterTree) override
Set parameters.
Definition: linesearch.hh:172
virtual void lineSearch(Domain &solution, const Domain &correction) override
Do line search.
Definition: linesearch.hh:69
Abstract base class describing the line search interface.
Definition: linesearch.hh:15
virtual ~LineSearchInterface()
Every abstract base class should have a virtual destructor.
Definition: linesearch.hh:18
virtual void setParameters(const ParameterTree &)=0
Set parameters.
virtual void lineSearch(Domain &, const Domain &)=0
Do line search.
Class for simply updating the solution without line search.
Definition: linesearch.hh:31
virtual void lineSearch(Domain &solution, const Domain &correction) override
Do line search (in this case just update the solution)
Definition: linesearch.hh:39
virtual void setParameters(const ParameterTree &) override
Set parameters.
Definition: linesearch.hh:45
Hierarchical structure of string parameters.
Definition: parametertree.hh:35
std::string get(const std::string &key, const std::string &defaultValue) const
get value as string
Definition: parametertree.cc:183
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)