FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
nlsd.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
8#include <kernel/solver/base.hpp>
9#include <kernel/solver/iterative.hpp>
10#include <kernel/solver/linesearch.hpp>
11#include <kernel/solver/nloptls.hpp>
12#include <kernel/solver/nlopt_precond.hpp>
13
14#include <deque>
15namespace FEAT
16{
17 namespace Solver
18 {
31 template<typename Functional_, typename Filter_>
32 class NLSD : public NLOptLS<Functional_, Filter_>
33 {
34 public:
36 typedef Functional_ FunctionalType;
38 typedef Filter_ FilterType;
41
43 typedef typename Functional_::GradientType GradientType;
45 typedef typename Functional_::VectorTypeR VectorType;
47 typedef typename Functional_::DataType DataType;
48
53
54 protected:
56 std::shared_ptr<LinesearchType> _linesearch;
59 std::shared_ptr<PrecondType> _precond;
60
65
66 public:
68 std::deque<VectorType>* iterates;
69
70 public:
90 explicit NLSD(Functional_& functional_, Filter_& filter_,
91 std::shared_ptr<LinesearchType> linesearch_,
92 bool keep_iterates = false, std::shared_ptr<PrecondType> precond = nullptr) :
93 BaseClass("NLSD", functional_, filter_, precond),
94 _linesearch(linesearch_),
95 _precond(precond),
96 iterates(nullptr)
97 {
98 XASSERT(_linesearch != nullptr);
99
100 this->set_ls_iter_digits(Math::ilog10(_linesearch->get_max_iter()));
101
102 if(keep_iterates)
103 {
104 iterates = new std::deque<VectorType>;
105 }
106 }
107
130 explicit NLSD(const String& section_name, const PropertyMap* section,
131 Functional_& functional_, Filter_& filter_, std::shared_ptr<LinesearchType> linesearch_,
132 std::shared_ptr<PrecondType> precond = nullptr) :
133 BaseClass("NLSD", section_name, section, functional_, filter_, precond),
134 _linesearch(linesearch_),
135 _precond(precond),
136 iterates(nullptr)
137 {
138 XASSERT(_linesearch != nullptr);
139
140 this->set_ls_iter_digits(Math::ilog10(_linesearch->get_max_iter()));
141
142 auto keep_iterates_p = section->query("keep_iterates");
143 if(keep_iterates_p.second && std::stoul(keep_iterates_p.first) == 1)
144 {
145 iterates = new std::deque<VectorType>;
146 }
147 }
148
152 virtual ~NLSD()
153 {
154 if(iterates != nullptr)
155 {
156 delete iterates;
157 }
158 }
159
161 virtual void init_symbolic() override
162 {
164 // create three temporary vectors
165 _vec_r = this->_functional.create_vector_r();
166 _vec_p = this->_functional.create_vector_r();
167 _linesearch->init_symbolic();
168 }
169
171 virtual void done_symbolic() override
172 {
173 if(iterates != nullptr)
174 iterates->clear();
175
176 //this->_vec_tmp.clear();
177 this->_vec_p.clear();
178 this->_vec_r.clear();
179 _linesearch->done_symbolic();
181 }
182
184 virtual String name() const override
185 {
186 return "NLSD";
187 }
188
192 void set_keep_iterates(bool keep_iterates)
193 {
194 if(iterates != nullptr)
195 {
196 delete iterates;
197 }
198
199 if(keep_iterates)
200 {
201 iterates = new std::deque<VectorType>;
202 }
203 }
204
206 virtual Status apply(VectorType& vec_cor, const VectorType& vec_def) override
207 {
208 // Clear solution vector
209 vec_cor.format();
210
211 this->_functional.prepare(vec_cor, this->_filter);
212 this->_functional.eval_fval_grad(this->_fval, this->_vec_r);
213
214 // Copy back given defect
215 this->_vec_r.copy(vec_def);
216
217 if(this->_precond != nullptr)
218 {
219 this->_precond->prepare(vec_cor, this->_filter);
220 }
221
222 // apply
223 this->_status = _apply_intern(vec_cor);
224 this->plot_summary();
225 return this->_status;
226 }
227
229 virtual Status correct(VectorType& vec_sol, const VectorType& DOXY(vec_rhs)) override
230 {
231 this->_functional.prepare(vec_sol, this->_filter);
232 // Compute functional value and gradient
233 this->_functional.eval_fval_grad(this->_fval, this->_vec_r);
234 this->_vec_r.scale(this->_vec_r,DataType(-1));
235 this->_filter.filter_def(this->_vec_r);
236
237 if(this->_precond != nullptr)
238 {
239 this->_precond->prepare(vec_sol, this->_filter);
240 }
241
242 // apply
243 this->_status = _apply_intern(vec_sol);
244 this->plot_summary();
245 return this->_status;
246 }
247
248 protected:
263 {
264 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
265
266 // Reset member variables in the LineSearch
267 _linesearch->reset();
268
269 if(iterates != nullptr)
270 {
271 iterates->push_back(std::move(vec_sol.clone()));
272 }
273
274 // compute initial defect
275 Status status = this->_set_initial_defect(this->_vec_r, vec_sol);
276 if(status != Status::progress)
277 {
278 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
279 return status;
280 }
281
282 // The first direction has to be the steepest descent direction
283 this->_vec_p.copy(this->_vec_r);
284
285 // apply preconditioner to defect vector
286 if(!this->_apply_precond(this->_vec_p, this->_vec_r, this->_filter))
287 {
288 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
289 return Status::aborted;
290 }
291
292 // Compute initial eta = <d, r>
293 DataType eta(this->_vec_p.dot(this->_vec_r));
294
295 // If the preconditioned search direction is not a descent direction, reset it to steepest descent
296 // TODO: Correct the output of the preconditioner if it turns out to not have been positive definite
297 if(eta <= DataType(0))
298 {
299 this->_vec_p.copy(this->_vec_r);
300 }
301
302 // start iterating
303 while(status == Status::progress)
304 {
305 IterationStats stat(*this);
306
307 this->_fval_prev = this->_fval;
308
309 // Copy information to the linesearch
310 _linesearch->set_initial_fval(this->_fval);
311 _linesearch->set_grad_from_defect(this->_vec_r);
312 // If we are using a preconditioner, use the additional information about the preconditioned step length in the line search
313 if(this->_precond != nullptr)
314 {
315 _linesearch->set_dir_scaling(true);
316 }
317
318 // Call the linesearch to update vec_sol
319 status = _linesearch->correct(vec_sol, this->_vec_p);
320
321 // Copy back information from the linesearch
322 this->_fval = _linesearch->get_final_fval();
323 this->_ls_its = _linesearch->get_num_iter();
324 this->_steplength = _linesearch->get_rel_update();
325 _linesearch->get_defect_from_grad(this->_vec_r);
326
327 // Log iterates if necessary
328 if(iterates != nullptr)
329 {
330 iterates->push_back(vec_sol.clone());
331 }
332
333 // Compute defect norm. This also performs the convergence/divergence checks.
334 status = this->_set_new_defect(this->_vec_r, vec_sol);
335
336 if(status != Status::progress)
337 {
338 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
339 return status;
340 }
341
342 // Re-assemble preconditioner if necessary
343 if(this->_precond != nullptr)
344 {
345 this->_precond->prepare(vec_sol, this->_filter);
346 }
347
348 // apply preconditioner
349 if(!this->_apply_precond(_vec_p, _vec_r, this->_filter))
350 {
351 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
352 return Status::aborted;
353 }
354
355 // Compute new eta
356 eta = this->_vec_p.dot(this->_vec_r);
357
358 // If the preconditioned search direction is not a descent direction, reset it to steepest descent
359 // TODO: Correct the output of the preconditioner if it turns out to not have been positive definite
360 if(eta <= DataType(0))
361 {
362 this->_vec_p.copy(this->_vec_r);
363 }
364 }
365
366 // We should never come to this point
367 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::undefined, this->get_num_iter()));
368 return Status::undefined;
369 }
370
371 }; // class NLSD
372
394 template<typename Functional_, typename Filter_, typename Linesearch_>
395 inline std::shared_ptr<NLSD<Functional_, Filter_>> new_nlsd(
396 Functional_& functional, Filter_& filter, Linesearch_& linesearch, bool keep_iterates = false,
397 std::shared_ptr<NLOptPrecond<typename Functional_::VectorTypeL, Filter_>> precond = nullptr)
398 {
399 return std::make_shared<NLSD<Functional_, Filter_>>(functional, filter, linesearch,
400 keep_iterates, precond);
401 }
402
427 template<typename Functional_, typename Filter_, typename Linesearch_>
428 inline std::shared_ptr<NLSD<Functional_, Filter_>> new_nlsd(
429 const String& section_name, const PropertyMap* section,
430 Functional_& functional, Filter_& filter, Linesearch_& linesearch,
431 std::shared_ptr<NLOptPrecond<typename Functional_::VectorTypeL, Filter_>> precond = nullptr)
432 {
433 return std::make_shared<NLSD<Functional_, Filter_>>(section_name, section, functional, filter, linesearch,
434 precond);
435 }
436 } //namespace Solver
437} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
FEAT Kernel base header.
A class organizing a tree of key-value pairs.
std::pair< String, bool > query(String key_path) const
Queries a value by its key path.
Helper class for iteration statistics collection.
Definition: base.hpp:392
Index get_num_iter() const
Returns number of performed iterations.
Definition: iterative.hpp:462
Status _status
current status of the solver
Definition: iterative.hpp:213
virtual void plot_summary() const
Plot a summary of the last solver run.
Definition: iterative.hpp:627
Linesearch base class.
Definition: linesearch.hpp:34
Base class for line search based nonlinear optimizers.
Definition: nloptls.hpp:43
virtual Status _set_initial_defect(const VectorType &vec_def, const VectorType &vec_sol) override
Internal function: sets the initial defect vector.
Definition: nloptls.hpp:267
DataType _fval_prev
Functional value from the previous iteration.
Definition: nloptls.hpp:80
virtual Status _set_new_defect(const VectorType &vec_r, const VectorType &vec_sol) override
Internal function: sets the new defect norm.
Definition: nloptls.hpp:325
DataType _fval
Current functional value.
Definition: nloptls.hpp:78
Functional_ & _functional
Our nonlinear functional.
Definition: nloptls.hpp:66
virtual void set_ls_iter_digits(Index digits)
Sets the number of digits used to plot line search iteration numbers.
Definition: nloptls.hpp:258
Index _ls_its
The number of iterations the linesearch performed in the last iteration of this solver.
Definition: nloptls.hpp:86
Filter_ & _filter
The filter we apply to the gradient.
Definition: nloptls.hpp:68
DataType _steplength
The last step length of the line search.
Definition: nloptls.hpp:82
Abstract base class for preconditioners for nonlinear optimization.
Nonlinear Steepest Descent method for finding a minimum of an functional's gradient.
Definition: nlsd.hpp:33
std::shared_ptr< PrecondType > _precond
Definition: nlsd.hpp:59
NLOptPrecond< typename Functional_::VectorTypeL, Filter_ > PrecondType
Generic preconditioner.
Definition: nlsd.hpp:52
void set_keep_iterates(bool keep_iterates)
Sets the iterates deque according to a bool.
Definition: nlsd.hpp:192
virtual void done_symbolic() override
Symbolic finalization method.
Definition: nlsd.hpp:171
NLSD(const String &section_name, const PropertyMap *section, Functional_ &functional_, Filter_ &filter_, std::shared_ptr< LinesearchType > linesearch_, std::shared_ptr< PrecondType > precond=nullptr)
Constructor using a PropertyMap.
Definition: nlsd.hpp:130
virtual Status apply(VectorType &vec_cor, const VectorType &vec_def) override
Solver application method.
Definition: nlsd.hpp:206
NLSD(Functional_ &functional_, Filter_ &filter_, std::shared_ptr< LinesearchType > linesearch_, bool keep_iterates=false, std::shared_ptr< PrecondType > precond=nullptr)
Standard constructor.
Definition: nlsd.hpp:90
Filter_ FilterType
The filter type.
Definition: nlsd.hpp:38
Functional_ FunctionalType
The nonlinear functional type.
Definition: nlsd.hpp:36
virtual String name() const override
Returns a descriptive string.
Definition: nlsd.hpp:184
Linesearch< FunctionalType, FilterType > LinesearchType
The baseclass for all applicable linesearches.
Definition: nlsd.hpp:40
virtual Status correct(VectorType &vec_sol, const VectorType &vec_rhs) override
Solver correction method.
Definition: nlsd.hpp:229
virtual void init_symbolic() override
Symbolic initialization method.
Definition: nlsd.hpp:161
VectorType _vec_p
descend direction vector
Definition: nlsd.hpp:64
NLOptLS< Functional_, Filter_ > BaseClass
Our baseclass.
Definition: nlsd.hpp:50
virtual Status _apply_intern(VectorType &vec_sol)
Internal function, applies the solver.
Definition: nlsd.hpp:262
virtual ~NLSD()
Virtual destructor.
Definition: nlsd.hpp:152
Functional_::DataType DataType
Underlying floating point type.
Definition: nlsd.hpp:47
Functional_::GradientType GradientType
Type of the functional's gradient has.
Definition: nlsd.hpp:43
std::shared_ptr< LinesearchType > _linesearch
The linesearch used along the descent direction.
Definition: nlsd.hpp:56
VectorType _vec_r
defect vector
Definition: nlsd.hpp:62
Functional_::VectorTypeR VectorType
Input type for the gradient.
Definition: nlsd.hpp:45
std::deque< VectorType > * iterates
For debugging purposes, all iterates can be logged to here.
Definition: nlsd.hpp:68
bool _apply_precond(VectorType &vec_cor, const VectorType &vec_def, const Filter_ &filter)
Applies the preconditioner onto a defect vector.
Definition: iterative.hpp:1140
virtual void init_symbolic()
Symbolic initialization method.
Definition: base.hpp:227
virtual void done_symbolic()
Symbolic finalization method.
Definition: base.hpp:255
String class implementation.
Definition: string.hpp:47
T_ ilog10(T_ x)
Computes the integral base-10 logarithm of an integer, i.e. its number of non-zero decimal digits.
Definition: math.hpp:231
std::shared_ptr< NLSD< Functional_, Filter_ > > new_nlsd(Functional_ &functional, Filter_ &filter, Linesearch_ &linesearch, bool keep_iterates=false, std::shared_ptr< NLOptPrecond< typename Functional_::VectorTypeL, Filter_ > > precond=nullptr)
Creates a new NLSD solver object.
Definition: nlsd.hpp:395
Status
Solver status return codes enumeration.
Definition: base.hpp:47
@ progress
continue iteration (internal use only)
@ undefined
undefined status
@ aborted
premature abort (solver aborted due to internal errors or preconditioner failure)
FEAT namespace.
Definition: adjactor.hpp:12