1#ifndef DUNE_FEM_NEWTONINVERSEOPERATOR_HH
2#define DUNE_FEM_NEWTONINVERSEOPERATOR_HH
17#include <dune/fem/common/staticlistofint.hh>
18#include <dune/fem/solver/parameter.hh>
19#include <dune/fem/io/parameter.hh>
20#include <dune/fem/operator/common/operator.hh>
21#include <dune/fem/operator/common/differentiableoperator.hh>
22#include <dune/fem/solver/inverseoperatorinterface.hh>
40 const double etaMax_ = 0.99;
41 const double gamma_ = 0.1;
42 mutable double previousEta_ = -1.0;
43 mutable double previousResidual_ = -1.0;
44 mutable double newtonTolerance_;
51 double nextLinearTolerance(
const double currentResidual)
const
55 if (previousEta_ >= 0.0)
57 const double etaA = gamma_ * currentResidual * currentResidual / (previousResidual_ * previousResidual_);
58 const double indicator = gamma_ * previousEta_ * previousEta_;
59 const double etaC = indicator < 0.1 ? std::min(etaA, etaMax_) :
std::
min(etaMax_,
std::
max(etaA, indicator));
60 eta = std::min(etaMax_, std::max(etaC, 0.5 * newtonTolerance_ / currentResidual));
62 previousResidual_ = currentResidual;
66 void setTolerance(
const double newtonTolerance) { newtonTolerance_ = newtonTolerance; }
72 template <
class SolverParam = SolverParameter>
73 struct NewtonParameter
74 :
public Dune::Fem::LocalParameter< NewtonParameter<SolverParam>, NewtonParameter<SolverParam> >
78 std::shared_ptr<SolverParam> baseParam_;
80 const std::string keyPrefix_;
82 ParameterReader parameter_;
84 void checkDeprecatedParameters()
const
86 const std::string newton(
"newton.");
87 const std::size_t pos = keyPrefix_.find( newton );
88 if( pos != std::string::npos )
90 DUNE_THROW(InvalidStateException,
"Keyprefix 'newton' is deprecated, replace with 'nonlinear'!");
93 const std::string params[]
94 = {
"tolerance",
"lineSearch",
"maxterations",
"linear",
"maxlinesearchiterations" };
95 for(
const auto& p : params )
97 std::string key(
"fem.solver.newton." );
99 if( parameter_.exists( key ) )
100 DUNE_THROW(InvalidStateException,
"Keyprefix 'newton' is deprecated, replace with 'nonlinear'!");
104 std::string replaceNonLinearWithLinear(
const std::string& keyPrefix )
const
106 if( keyPrefix.find(
"nonlinear" ) != std::string::npos )
108 return std::regex_replace(keyPrefix, std::regex(
"nonlinear"),
"linear" );
114 NewtonParameter(
const SolverParam& baseParameter,
const std::string keyPrefix =
"fem.solver.nonlinear." )
115 : baseParam_( static_cast< SolverParam* > (baseParameter.clone()) ),
116 keyPrefix_( keyPrefix ),
117 parameter_( baseParameter.parameter() )
119 checkDeprecatedParameters();
122 template <class Parameter, std::enable_if_t<!std::is_base_of<SolverParam,Parameter>::value && !std::is_same<Parameter,ParameterReader>::value,
int> i=0>
123 NewtonParameter(
const Parameter& solverParameter,
const std::string keyPrefix =
"fem.solver.nonlinear." )
124 : baseParam_( new SolverParam(solverParameter) ),
125 keyPrefix_( keyPrefix ),
126 parameter_( solverParameter.parameter() )
128 checkDeprecatedParameters();
131 template <class ParamReader, std::enable_if_t<!std::is_same<ParamReader,SolverParam>::value && std::is_same<ParamReader,ParameterReader>::value,
int> i=0>
132 NewtonParameter(
const ParamReader ¶meter,
const std::string keyPrefix =
"fem.solver.nonlinear." )
134 : baseParam_(
std::make_shared<SolverParam>( replaceNonLinearWithLinear(keyPrefix), parameter) ),
135 keyPrefix_( keyPrefix),
136 parameter_( parameter )
138 checkDeprecatedParameters();
141 const ParameterReader ¶meter ()
const {
return parameter_; }
142 const SolverParam& solverParameter ()
const {
return *baseParam_; }
143 const SolverParam& linear ()
const {
return *baseParam_; }
145 virtual void reset ()
151 maxLinearIterations_ = -1;
152 maxLineSearchIterations_ = -1;
156 virtual double tolerance ()
const
159 tolerance_ = parameter_.getValue<
double >( keyPrefix_ +
"tolerance", 1e-6 );
163 virtual void setTolerance (
const double tol )
169 virtual bool verbose ()
const
177 const bool v =
false;
178 verbose_ = parameter_.getValue<
bool >(keyPrefix_ +
"verbose", v ) ? 1 : 0 ;
183 virtual void setVerbose(
bool verb)
185 verbose_ = verb ? 1 : 0;
188 virtual int maxIterations ()
const
190 if(maxIterations_ < 0)
192 return maxIterations_;
195 virtual void setMaxIterations (
const int maxIter )
197 assert(maxIter >= 0);
198 maxIterations_ = maxIter;
203 virtual int maxLinearIterations ()
const
205 if(maxLinearIterations_ < 0)
206 maxLinearIterations_ = linear().maxIterations();
207 return maxLinearIterations_;
210 virtual void setMaxLinearIterations (
const int maxLinearIter )
212 assert(maxLinearIter >=0);
213 maxLinearIterations_ = maxLinearIter;
216 virtual int maxLineSearchIterations ()
const
218 if(maxLineSearchIterations_ < 0)
220 return maxLineSearchIterations_;
223 virtual void setMaxLineSearchIterations (
const int maxLineSearchIter )
225 assert( maxLineSearchIter >= 0);
226 maxLineSearchIterations_ = maxLineSearchIter;
230 LIST_OF_INT(LineSearchMethod,
234 virtual int lineSearch ()
const
236 if( parameter_.exists( keyPrefix_ +
"lineSearch" ) )
238 std::cout <<
"WARNING: using old parameter name '" << keyPrefix_ +
"lineSearch" <<
"',\n"
239 <<
"please switch to '" << keyPrefix_ +
"linesearch" <<
"' (all lower caps)!" <<std::endl;
240 return Forcing::to_id( parameter_.getEnum( keyPrefix_ +
"lineSearch", LineSearchMethod::names(),
LineSearchMethod::none ) );
242 return Forcing::to_id( parameter_.getEnum( keyPrefix_ +
"linesearch", LineSearchMethod::names(),
LineSearchMethod::none ) );
245 virtual void setLineSearch (
const int method )
247 Parameter::append( keyPrefix_ +
"linesearch", LineSearchMethod::to_string(method),
true );
255 virtual int forcing ()
const
257 if( parameter_.exists( keyPrefix_ +
"linear.tolerance.strategy" ) )
259 std::string keypref( keyPrefix_ );
260 std::string femsolver(
"fem.solver.");
261 size_t pos = keypref.find( femsolver );
262 if (pos != std::string::npos)
265 keypref.erase(pos, femsolver.length());
267 std::cout <<
"WARNING: using old parameter name '" << keypref +
"linear.tolerance.strategy" <<
"',\n"
268 <<
"please switch to '" << keypref +
"forcing" <<
"'!" <<std::endl;
269 return Forcing::to_id( parameter_.getEnum( keyPrefix_ +
"linear.tolerance.strategy", Forcing::names(),
Forcing::none ) );
271 return Forcing::to_id( parameter_.getEnum( keyPrefix_ +
"forcing", Forcing::names(),
Forcing::none ) );
274 virtual void setForcing (
const int strategy )
276 Parameter::append( keyPrefix_ +
"forcing", Forcing::to_string( strategy ),
true );
280 virtual bool simplified ()
const
282 return parameter_.getValue<
bool >( keyPrefix_ +
"simplified", 0 );
287 virtual bool forceNonLinear ()
const
290 v = parameter_.getValue<
bool >(keyPrefix_ +
"forcenonlinear", v );
295 mutable double tolerance_ = -1;
296 mutable int verbose_ = -1;
297 mutable int maxIterations_ = -1;
298 mutable int maxLinearIterations_ = -1;
299 mutable int maxLineSearchIterations_ = -1;
307 enum class NewtonFailure
312 IterationsExceeded = 2,
313 LinearIterationsExceeded = 3,
314 LineSearchFailed = 4,
315 TooManyIterations = 5,
316 TooManyLinearIterations = 6,
317 LinearSolverFailed = 7
341 template<
class JacobianOperator,
class LInvOp >
343 :
public Operator< typename JacobianOperator::RangeFunctionType, typename JacobianOperator::DomainFunctionType >
349 template <
class Obj,
bool defaultValue = false >
350 struct SelectPreconditioning
353 template <
typename T,
typename =
bool>
354 struct CheckMember :
public std::false_type { };
356 template <
typename T>
359 template <
class T,
bool>
362 static const bool value = defaultValue;
367 struct SelectValue< T, true >
369 static const bool value = T::preconditioningAvailable;
370 typedef typename T::PreconditionerType type;
373 static constexpr bool value = SelectValue< Obj, CheckMember< Obj >::value >::value;
374 typedef typename SelectValue< Obj, CheckMember< Obj >::value >::type type;
389 typedef typename SelectPreconditioning< LinearInverseOperatorType > :: type
PreconditionerType;
396 typedef NewtonParameter<typename LinearInverseOperatorType::SolverParameterType> ParameterType;
398 typedef std::function< bool (
const RangeFunctionType &w,
const RangeFunctionType &dw,
double residualNorm ) > ErrorMeasureType;
422 : verbose_( parameter.verbose() ),
423 maxLineSearchIterations_( parameter.maxLineSearchIterations() ),
424 jInv_(
std::move( jInv ) ),
425 parameter_(parameter),
426 lsMethod_( parameter.lineSearch() ),
427 finished_( [ epsilon ] ( const RangeFunctionType &w, const RangeFunctionType &dw, double res ) {
return res < epsilon; } ),
428 forcing_ ( parameter.forcing() ),
429 eisenstatWalker_ ( epsilon ),
432 if (forcing_ == ParameterType::Forcing::eisenstatwalker) {
433 if (parameter_.linear().errorMeasure() != LinearSolver::ToleranceCriteria::residualReduction) {
434 DUNE_THROW(
InvalidStateException,
"Parameter `nonlinear.linear.errormeasure` selecting the tolerance criteria in the linear solver must be `residualreduction` when using Eisenstat-Walker." );
468 const ParameterReader ¶meter = Parameter::container() )
480 void setErrorMeasure ( ErrorMeasureType finished ) { finished_ = std::move( finished ); }
486 void bind (
const OperatorType &op,
const PreconditionerType& preconditioner )
490 preconditioner_ = &preconditioner;
492 std::cerr <<
"WARNING: linear inverse operator does not support external preconditioning!" << std::endl;
495 void unbind () { op_ =
nullptr; preconditioner_ =
nullptr; }
497 virtual void operator() (
const DomainFunctionType &u, RangeFunctionType &w )
const;
499 int iterations ()
const {
return iterations_; }
500 void setMaxIterations (
int maxIterations ) { parameter_.setMaxIterations( maxIterations ); }
501 int linearIterations ()
const {
return linearIterations_; }
502 void setMaxLinearIterations (
int maxLinearIterations ) { parameter_.setMaxLinearIterations( maxLinearIterations ); }
503 void updateLinearTolerance ()
const {
504 if (forcing_ == ParameterType::Forcing::eisenstatwalker) {
505 double newTol = eisenstatWalker_.nextLinearTolerance( delta_ );
506 jInv_.parameter().setTolerance( newTol );
509 bool verbose()
const {
return verbose_ &&
Parameter::verbose( Parameter::solverStatistics ); }
510 double residual ()
const {
return delta_; }
512 NewtonFailure failed ()
const
517 return NewtonFailure::InvalidResidual;
518 else if( iterations_ >= parameter_.maxIterations() )
519 return NewtonFailure::TooManyIterations;
520 else if( linearIterations_ >= parameter_.maxLinearIterations() )
521 return NewtonFailure::TooManyLinearIterations;
522 else if( linearIterations_ < 0)
523 return NewtonFailure::LinearSolverFailed;
524 else if( !stepCompleted_ )
525 return NewtonFailure::LineSearchFailed;
527 return NewtonFailure::Success;
530 bool converged ()
const {
return failed() == NewtonFailure::Success; }
532 virtual int lineSearch(RangeFunctionType &w, RangeFunctionType &dw,
533 const DomainFunctionType &u, DomainFunctionType &residual)
const
535 double deltaOld = delta_;
536 delta_ = std::sqrt( residual.scalarProductDofs( residual ) );
539 if (failed() == NewtonFailure::InvalidResidual)
541 double test = dw.scalarProductDofs( dw );
544 delta_ = 2.*deltaOld;
547 int noLineSearch = (delta_ < deltaOld)?1:0;
548 int lineSearchIteration = 0;
549 const bool lsVerbose = verbose() &&
Parameter::verbose( Parameter::extendedStatistics );
550 while (delta_ >= deltaOld)
552 double deltaPrev = delta_;
555 std::cout <<
" line search:" << delta_ <<
">" << deltaOld << std::endl;
556 if (std::abs(delta_-deltaOld) < 1e-5*delta_)
559 (*op_)( w, residual );
561 delta_ = std::sqrt( residual.scalarProductDofs( residual ) );
562 if (std::abs(delta_-deltaPrev) < 1e-15)
564 if (failed() == NewtonFailure::InvalidResidual)
565 delta_ = 2.*deltaOld;
567 ++lineSearchIteration;
568 if( lineSearchIteration >= maxLineSearchIterations_ )
575 const std::vector<double>&
timing()
const {
return timing_; }
586 if( preconditioner_ )
588 jInv_.bind( jOp, *preconditioner_ );
598 template<
class ... Args>
608 const PreconditionerType* preconditioner_ =
nullptr;
611 const int maxLineSearchIterations_;
613 mutable DomainFieldType delta_;
614 mutable int iterations_;
615 mutable int linearIterations_;
617 mutable std::unique_ptr< JacobianOperatorType > jOp_;
618 ParameterType parameter_;
619 mutable int stepCompleted_;
621 ErrorMeasureType finished_;
623 EisenstatWalkerStrategy eisenstatWalker_;
625 mutable std::vector<double> timing_;
632 template<
class JacobianOperator,
class LInvOp >
633 inline void NewtonInverseOperator< JacobianOperator, LInvOp >
634 ::operator() (
const DomainFunctionType &u, RangeFunctionType &w )
const
637 std::fill(timing_.begin(), timing_.end(), 0.0 );
640 const bool nonlinear = op_->nonlinear() || parameter_.forceNonLinear();
643 DomainFunctionType residual( u );
644 RangeFunctionType dw( w );
647 double jacTime = 0.0;
648 JacobianOperatorType& jOp = jacobian(
"jacobianOperator", dw.space(), u.space(), parameter_.solverParameter() );
651 stepCompleted_ =
true;
653 linearIterations_ = 0;
655 (*op_)( w, residual );
657 delta_ = std::sqrt( residual.scalarProductDofs( residual ) );
658 updateLinearTolerance();
661 bool computeJacobian =
true;
662 const bool simplifiedNewton = parameter_.simplified();
664 const bool newtonVerbose = verbose() && nonlinear;
667 std::cout <<
"Start Newton: tol = " << parameter_.tolerance() <<
" (forcing = " << ParameterType::Forcing::to_string(forcing_) <<
" | linear tol = " << parameter_.linear().tolerance() <<
")"<<std::endl;
668 std::cout <<
"Newton iteration " << iterations_ <<
": |residual| = " << delta_;
673 std::cout << std::endl;
675 if( computeJacobian )
679 (*op_).jacobian( w, jOp );
682 computeJacobian = ! simplifiedNewton;
686 bindOperatorAndPreconditioner( jOp );
689 if ( parameter_.maxLinearIterations() - linearIterations_ <= 0 )
691 jInv_.setMaxIterations( parameter_.maxLinearIterations() - linearIterations_ );
694 jInv_( residual, dw );
696 if (jInv_.iterations() < 0)
698 linearIterations_ = jInv_.iterations();
701 linearIterations_ += jInv_.iterations();
709 (*op_)( w, residual );
713 int ls = lineSearch(w,dw,u,residual);
714 stepCompleted_ = ls >= 0;
715 updateLinearTolerance();
719 std::cout <<
"Newton iteration " << iterations_ <<
": |residual| = " << delta_ << std::flush;
721 if ( (finished_(w, dw, delta_)) || !converged())
725 std::cout << std::endl;
726 std::cout <<
"Linear iterations: " << linearIterations_ << std::endl;
736 std::cout << std::endl;
741 timing_[0] = allTimer.
elapsed();
742 timing_[1] = jacTime;
743 timing_[2] = timing_[0] - jacTime;
abstract differentiable operator
Definition: differentiableoperator.hh:29
Adaptive tolerance selection for linear solver.
Definition: newtoninverseoperator.hh:38
EisenstatWalkerStrategy(const double newtonTolerance)
Definition: newtoninverseoperator.hh:50
inverse operator based on a newton scheme
Definition: newtoninverseoperator.hh:344
NewtonInverseOperator(LinearInverseOperatorType jInv, const DomainFieldType &epsilon, const ParameterType ¶meter)
Definition: newtoninverseoperator.hh:421
Impl::SolverInfo SolverInfoType
performance info about last solver call
Definition: newtoninverseoperator.hh:401
static constexpr bool preconditioningAvailable
type of preconditioner for linear solver
Definition: newtoninverseoperator.hh:388
JacobianOperator JacobianOperatorType
type of operator's Jacobian
Definition: newtoninverseoperator.hh:379
NewtonInverseOperator(const ParameterType ¶meter=ParameterType(Parameter::container()))
Definition: newtoninverseoperator.hh:445
const std::vector< double > & timing() const
returns [overall, jacobian, solve] timings in seconds for last operator () call.
Definition: newtoninverseoperator.hh:575
SolverInfoType info() const
return performance information about last solver run */
Definition: newtoninverseoperator.hh:578
NewtonInverseOperator(const DomainFieldType &epsilon, const ParameterReader ¶meter=Parameter::container())
Definition: newtoninverseoperator.hh:467
void setErrorMeasure(ErrorMeasureType finished)
Definition: newtoninverseoperator.hh:480
DifferentiableOperator< JacobianOperatorType > OperatorType
type of operator to invert
Definition: newtoninverseoperator.hh:382
LInvOp LinearInverseOperatorType
type of linear inverse operator
Definition: newtoninverseoperator.hh:385
NewtonInverseOperator(const DomainFieldType &epsilon, const ParameterType ¶meter)
Definition: newtoninverseoperator.hh:456
static bool verbose()
obtain the cached value for fem.verbose with default verbosity level 2
Definition: parameter.hh:466
static void append(int &argc, char **argv)
add parameters from the command line RangeType gRight;
Definition: parameter.hh:219
Default exception if a function was called while the object is not in a valid state for that function...
Definition: exceptions.hh:281
A simple stop watch.
Definition: timer.hh:43
void reset() noexcept
Reset timer while keeping the running/stopped state.
Definition: timer.hh:57
double elapsed() const noexcept
Get elapsed user-time from last reset until now/last stop in seconds.
Definition: timer.hh:77
A few common exception classes.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
constexpr GeometryType none(unsigned int dim)
Returns a GeometryType representing a singular of dimension dim.
Definition: type.hh:471
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:506
Dune namespace.
Definition: alignedallocator.hh:13
abstract operator
Definition: operator.hh:34
DomainFunction DomainFunctionType
type of discrete function in the operator's domain
Definition: operator.hh:36
DomainFunction::RangeFieldType DomainFieldType
field type of the operator's domain
Definition: operator.hh:41
RangeFunction RangeFunctionType
type of discrete function in the operator's range
Definition: operator.hh:38