DUNE-FEM (unstable)

cginverseoperator.hh
1 #ifndef DUNE_FEM_CGINVERSEOPERATOR_HH
2 #define DUNE_FEM_CGINVERSEOPERATOR_HH
3 
4 #include <limits>
5 #include <memory>
6 #include <type_traits>
7 
8 #include <dune/fem/io/parameter.hh>
9 #include <dune/fem/function/common/discretefunction.hh>
10 #include <dune/fem/operator/common/operator.hh>
11 #include <dune/fem/solver/diagonalpreconditioner.hh>
12 #include <dune/fem/solver/parameter.hh>
13 
14 namespace Dune
15 {
16 
17  namespace Fem
18  {
19 
20  // ConjugateGradientSolver
21  // -----------------------
22 
29  template< class Operator>
31  {
33 
34  public:
37 
42  typedef typename Dune::FieldTraits< RangeFieldType >::real_type RealType;
43 
48 
51 
52 
53  private:
54  static_assert( (std::is_same< DomainFunctionType, RangeFunctionType >::value),
55  "DomainFunctionType must equal RangeFunctionType." );
56 
57  public:
65  ConjugateGradientSolver ( const RealType &epsilon,
66  unsigned int maxIterations,
67  int errorMeasure,
68  bool verbose )
69  : epsilon_( epsilon ),
70  maxIterations_( maxIterations ),
71  errorMeasure_( errorMeasure ),
72  verbose_( verbose && Fem::Parameter::verbose() ),
73  averageCommTime_( 0.0 ),
74  realCount_( 0 )
75  {}
76  ConjugateGradientSolver ( const RealType &epsilon,
77  unsigned int maxIterations,
78  bool verbose,
79  const ParameterReader &parameter = Parameter::container() )
80  : epsilon_( epsilon ),
81  maxIterations_( maxIterations ),
82  errorMeasure_( 1 ),
83  verbose_( verbose && Fem::Parameter::verbose() ),
84  averageCommTime_( 0.0 ),
85  realCount_( 0 )
86  {}
87 
93  ConjugateGradientSolver ( RealType epsilon,
94  unsigned int maxIterations,
95  const ParameterReader &parameter = Parameter::container() )
96  : epsilon_( epsilon ),
97  maxIterations_( maxIterations ),
98  errorMeasure_( 1 ),
99  verbose_( parameter.getValue< bool >( "fem.solver.verbose", false ) ),
100  averageCommTime_( 0.0 ),
101  realCount_( 0 )
102  {}
103 
104  // ConjugateGradientSolver ( const ThisType & )=delete;
105 
117  void solve ( const OperatorType &op, const RangeFunctionType &b, DomainFunctionType &x ) const;
118 
131  void solve ( const OperatorType &op, const PreconditionerType &p,
132  const RangeFunctionType &b, DomainFunctionType &x ) const;
133 
135  unsigned int iterations () const
136  {
137  return realCount_;
138  }
139 
140  void setMaxIterations ( unsigned int maxIterations ) { maxIterations_ = maxIterations; }
141 
142 
144  double averageCommTime() const
145  {
146  return averageCommTime_;
147  }
148 
149  protected:
150  const RealType epsilon_;
151  unsigned int maxIterations_;
152  int errorMeasure_;
153  const bool verbose_;
154  mutable double averageCommTime_;
155  mutable unsigned int realCount_;
156  };
157 
158 
159  namespace Solver
160  {
161  // CGInverseOperator
162  // -----------------
163 
169  template< class DiscreteFunction >
171  : public Fem::Operator< DiscreteFunction, DiscreteFunction >
172  {
175 
176  public:
177  typedef typename BaseType::DomainFunctionType DomainFunctionType;
178  typedef typename BaseType::RangeFunctionType RangeFunctionType;
179 
182 
183  typedef typename OperatorType::RangeFieldType RangeFieldType;
184  typedef typename Dune::FieldTraits< RangeFieldType >::real_type RealType;
185 
186  // non-const version
187  using BaseType::finalize;
188 
189  private:
191 
192  public:
200  CGInverseOperator ( RealType redEps, RealType absLimit,
201  unsigned int maxIter, bool verbose,
202  const ParameterReader &parameter = Parameter::container() )
203  : solver_( absLimit, maxIter, verbose, parameter ),
204  parameter_( parameter )
205  {}
206 
207  CGInverseOperator ( const SolverParameter& param = SolverParameter(Parameter::container() ) )
208  : solver_( param.tolerance(),
209  param.maxIterations(),
210  param.errorMeasure(),
211  param.verbose() ),
212  parameter_( param )
213  {
214  }
215 
216 
223  CGInverseOperator ( RealType redEps, RealType absLimit,
224  unsigned int maxIter,
225  const ParameterReader &parameter = Parameter::container() )
226  : solver_( absLimit, maxIter, parameter ),
227  parameter_( parameter )
228  {}
229 
230  CGInverseOperator ( RealType redEps, RealType absLimit,
231  const ParameterReader &parameter = Parameter::container() )
232  : CGInverseOperator( redEps, absLimit, std::numeric_limits< unsigned int >::max(), parameter )
233  {}
234 
244  RealType redEps, RealType absLimit,
245  unsigned int maxIter, bool verbose,
246  const ParameterReader &parameter = Parameter::container() )
247  : CGInverseOperator( redEps, absLimit, maxIter, verbose, parameter )
248  {
249  bind( op );
250  }
251 
252 
261  RealType redEps, RealType absLimit,
262  unsigned int maxIter,
263  const ParameterReader &parameter = Parameter::container() )
264  : CGInverseOperator( redEps, absLimit, maxIter, parameter )
265  {
266  bind( op );
267  }
268 
269  CGInverseOperator ( const OperatorType &op,
270  RealType redEps, RealType absLimit,
271  const ParameterReader &parameter = Parameter::container() )
272  : CGInverseOperator( redEps, absLimit, parameter )
273  {
274  bind( op );
275  }
276 
287  const PreconditionerType &precond,
288  RealType redEps, RealType absLimit,
289  unsigned int maxIter, bool verbose,
290  const ParameterReader &parameter = Parameter::container() )
291  : CGInverseOperator( redEps, absLimit, maxIter, verbose )
292  {
293  bind( op, precond );
294  }
295 
305  const PreconditionerType &precond,
306  RealType redEps, RealType absLimit,
307  const ParameterReader &parameter = Parameter::container() )
308  : CGInverseOperator( redEps, absLimit, parameter )
309  {
310  bind( op, precond );
311  }
312 
313  CGInverseOperator ( const OperatorType &op,
314  const PreconditionerType &precond,
315  RealType redEps, RealType absLimit,
316  unsigned int maxIter,
317  const ParameterReader &parameter = Parameter::container() )
318  : CGInverseOperator( redEps, absLimit, maxIter, parameter )
319  {
320  bind( op, precond );
321  }
322 
323  void bind ( const OperatorType &op ) { operator_ = &op; preconditioner_ = nullptr; }
324  void bind ( const OperatorType &op, const PreconditionerType &precond )
325  {
326  operator_ = &op;
327  preconditioner_ = &precond;
328  }
329  void unbind () { operator_ = nullptr; preconditioner_ = nullptr; }
330 
339  virtual void operator()( const DomainFunctionType &arg, RangeFunctionType &dest ) const
340  {
341  prepare();
342  apply(arg,dest);
343  const_cast< ThisType& > (*this).finalize();
344  }
345 
346  template<typename... A>
347  inline void prepare(A... ) const
348  {}
349 
358  virtual void apply( const DomainFunctionType &arg, RangeFunctionType &dest ) const
359  {
360  assert(operator_);
361  if(preconditioner_)
362  solver_.solve( *operator_, *preconditioner_, arg, dest );
363  else
364  solver_.solve( *operator_, arg, dest );
365  }
366 
368  unsigned int iterations () const
369  {
370  return solver_.iterations();
371  }
372 
373  void setMaxIterations ( unsigned int maxIter ) { solver_.setMaxIterations( maxIter ); }
374 
376  double averageCommTime() const
377  {
378  return solver_.averageCommTime();
379  }
380 
381  SolverParameter& parameter () const
382  {
383  return parameter_;
384  }
385 
386  protected:
387  const OperatorType *operator_ = nullptr;
388  const PreconditionerType *preconditioner_ = nullptr;
389  SolverType solver_;
390  mutable SolverParameter parameter_;
391  };
392  }
393 
394  // CGInverseOperator
395  // -----------------
396 
404  template< class DiscreteFunction,
405  class Op = Fem::Operator< DiscreteFunction, DiscreteFunction > >
407  : public Fem::Solver::CGInverseOperator< DiscreteFunction >
408  {
410 
411  public:
412  using BaseType::bind;
413 
414  typedef SolverParameter SolverParameterType;
415  typedef typename BaseType::DomainFunctionType DomainFunctionType;
416  typedef typename BaseType::RangeFunctionType RangeFunctionType;
417 
418  typedef DomainFunctionType DestinationType;
419 
421  typedef Op OperatorType;
422 
423  typedef typename OperatorType::RangeFieldType RangeFieldType;
424  typedef typename Dune::FieldTraits< RangeFieldType >::real_type RealType;
425 
426  // Preconditioner is to approximate op^-1 !
428 
429  CGInverseOperator ( const SolverParameter& param = SolverParameter(Parameter::container()) )
430  : BaseType( param )
431  {}
432 
433 
441  CGInverseOperator ( RealType redEps, RealType absLimit,
442  unsigned int maxIter, bool verbose,
443  const ParameterReader &parameter = Parameter::container() )
444  : BaseType( redEps, absLimit, maxIter, verbose, parameter )
445  {}
446 
453  CGInverseOperator ( RealType redEps, RealType absLimit,
454  unsigned int maxIter,
455  const ParameterReader &parameter = Parameter::container() )
456  : BaseType( redEps, absLimit, maxIter, parameter )
457  {}
458 
459  CGInverseOperator ( RealType redEps, RealType absLimit,
460  const ParameterReader &parameter = Parameter::container() )
461  : BaseType( redEps, absLimit, parameter )
462  {}
463 
472  template< class LinearOperator, std::enable_if_t< std::is_base_of< OperatorType, LinearOperator >::value, int > = 0 >
474  RealType redEps, RealType absLimit,
475  unsigned int maxIter, bool verbose,
476  const ParameterReader &parameter = Parameter::container() )
477  : BaseType( redEps, absLimit, maxIter, verbose, parameter )
478  {
479  bind( op );
480  }
481 
489  template< class LinearOperator, std::enable_if_t< std::is_base_of< OperatorType, LinearOperator >::value, int > = 0 >
491  RealType redEps, RealType absLimit,
492  unsigned int maxIter,
493  const ParameterReader &parameter = Parameter::container() )
494  : BaseType( redEps, absLimit, maxIter, parameter )
495  {
496  bind( op );
497  }
498 
499  template< class LinearOperator, std::enable_if_t< std::is_base_of< OperatorType, LinearOperator >::value, int > = 0 >
500  CGInverseOperator ( const LinearOperator &op,
501  RealType redEps, RealType absLimit,
502  const ParameterReader &parameter = Parameter::container() )
503  : BaseType( redEps, absLimit, parameter )
504  {
505  bind( op );
506  }
507 
517  const PreconditioningType &precond,
518  RealType redEps, RealType absLimit,
519  unsigned int maxIter, bool verbose,
520  const ParameterReader &parameter = Parameter::container() )
521  : BaseType( op, precond, redEps, absLimit, maxIter, verbose, parameter )
522  {}
523 
533  const PreconditioningType &precond,
534  RealType redEps, RealType absLimit,
535  unsigned int maxIter,
536  const ParameterReader &parameter = Parameter::container() )
537  : BaseType( op, precond, redEps, absLimit, maxIter, parameter )
538  {}
539 
540  CGInverseOperator ( const OperatorType &op,
541  const PreconditioningType &precond,
542  RealType redEps, RealType absLimit,
543  const ParameterReader &parameter = Parameter::container() )
544  : BaseType( op, precond, redEps, absLimit, parameter )
545  {}
546 
547 
548  template< class LinearOperator, std::enable_if_t< std::is_base_of< OperatorType, LinearOperator >::value, int > = 0 >
549  void bind ( const LinearOperator &op )
550  {
551  BaseType::bind( op );
552  checkPreconditioning( op );
553  }
554 
555  void unbind ()
556  {
557  BaseType::unbind();
558  precondObj_.reset();
559  }
560 
561  protected:
562  template< class LinearOperator >
563  void checkPreconditioning( const LinearOperator &linearOp )
564  {
565  bool preconditioning = false;
566  if (!parameter_.parameter().exists(parameter_.keyPrefix()+"preconditioning.method") &&
567  parameter_.parameter().exists("fem.preconditioning"))
568  {
569  preconditioning = parameter_.parameter().template getValue< bool >( "fem.preconditioning", false );
570  std::cout << "WARNING: using deprecated parameter `fem.preconditioning` use "
571  << parameter_.keyPrefix() << "preconditioning.method instead\n";
572  }
573  else
574  preconditioning = parameter_.preconditionMethod(
575  {
576  SolverParameter::none, // no preconditioning
577  SolverParameter::jacobi // Jacobi preconditioning
578  });
579  if( preconditioning && std::is_base_of< AssembledOperator< DomainFunctionType, DomainFunctionType > ,LinearOperator > :: value )
580  {
581  // create diagonal preconditioner
582  precondObj_.reset( new DiagonalPreconditioner< DomainFunctionType, LinearOperator >( linearOp ) );
583  preconditioner_ = precondObj_.get();
584  }
585  }
586 
587  using BaseType::preconditioner_;
588  using BaseType::parameter_;
589  std::unique_ptr< PreconditioningType > precondObj_;
590  };
591 
592  // Implementation of ConjugateGradientSolver
593  // -----------------------------------------
594 
595  template< class Operator >
598  {
599 
600  RealType tolerance = (epsilon_ * epsilon_);
601  if (errorMeasure_ == 1)
602  tolerance *= b.normSquaredDofs( );
603 
604  averageCommTime_ = 0.0;
605 
606  RangeFunctionType h( b );
607  op( x, h );
608 
609  RangeFunctionType r( h );
610  r -= b;
611 
612  RangeFunctionType p( b );
613  p -= h;
614 
615  RealType prevResiduum = 0;
616  RealType residuum = r.normSquaredDofs( );
617 
618  for( realCount_ = 0; (residuum > tolerance) && (realCount_ < maxIterations_); ++realCount_ )
619  {
620  if( realCount_ > 0 )
621  {
622  assert( residuum/prevResiduum == residuum/prevResiduum );
623  p *= (residuum / prevResiduum);
624  p -= r;
625  }
626 
627  op( p, h );
628 
629  RangeFieldType pdoth = p.scalarProductDofs( h );
630  const RangeFieldType alpha = residuum / pdoth;
631  assert( alpha == alpha );
632  x.axpy( alpha, p );
633  r.axpy( alpha, h );
634 
635  prevResiduum = residuum;
636  residuum = r.normSquaredDofs( );
637 
638  double exchangeTime = h.space().communicator().exchangeTime();
639  if( verbose_ )
640  {
641  std::cout << "CG-Iteration: " << realCount_ << ", Residuum: " << std::sqrt(residuum)
642  << ", Tolerance: " << std::sqrt(tolerance) << std::endl;
643  // only for parallel apps
644  if( b.space().gridPart().comm().size() > 1 )
645  std::cout << "Communication needed: " << exchangeTime << " s" << std::endl;
646  }
647 
648  averageCommTime_ += exchangeTime;
649  }
650  }
651 
652 
653  template< class Operator >
655  ::solve ( const OperatorType &op, const PreconditionerType &precond, const RangeFunctionType &b, DomainFunctionType &x ) const
656  {
657  RealType tolerance = (epsilon_ * epsilon_);
658  if (errorMeasure_ == 1)
659  tolerance *= b.normSquaredDofs( );
660 
661  averageCommTime_ = 0.0;
662 
663  RangeFunctionType h( b );
664  //h=Ax
665  op( x, h );
666 
667  //r=Ax-b
668  RangeFunctionType r( h );
669  r -= b;
670 
671  //p=b-A*x <= r_0 Deufelhard
672  RangeFunctionType p( b );
673  p -= h;
674 
675  //q=B*p <=q Deuf
676  RangeFunctionType q ( b );
677  precond(p,q);
678 
679  RangeFunctionType s (q);
680 
681  RangeFieldType prevResiduum = 0; // note that these will be real_type but require scalar product evaluation
682  RangeFieldType residuum = p.scalarProductDofs( q );//<p,Bp>
683 
684  for( realCount_ = 0; (std::real(residuum) > tolerance) && (realCount_ < maxIterations_); ++realCount_ )
685  {
686  if( realCount_ > 0 )
687  {
688  assert( residuum/prevResiduum == residuum/prevResiduum );
689  const RangeFieldType beta=residuum/prevResiduum;
690  q*=beta;
691  q+=(s);
692  }
693 
694  op( q, h );
695 
696  RangeFieldType qdoth = q.scalarProductDofs( h );
697  const RangeFieldType alpha = residuum / qdoth;//<p,Bp>/<q,Aq>
698  assert( alpha == alpha );
699  x.axpy( alpha, q );
700 
701  p.axpy( -alpha, h );//r_k
702 
703  precond(p,s); //B*r_k
704 
705  prevResiduum = residuum;//<rk-1,B*rk-1>
706 
707  residuum = p.scalarProductDofs( s );//<rk,B*rk>
708 
709  double exchangeTime = h.space().communicator().exchangeTime();
710  if( verbose_ )
711  {
712  std::cout << "CG-Iteration: " << realCount_ << ", Residuum: " << std::sqrt(residuum)
713  << ", Tolerance: " << std::sqrt(tolerance) << std::endl;
714  // only for parallel apps
715  if( b.space().gridPart().comm().size() > 1 )
716  std::cout << "Communication needed: " << exchangeTime << " s" << std::endl;
717  }
718 
719  averageCommTime_ += exchangeTime;
720  }
721  }
722 
723  } // namespace Fem
724 
725 } // namespace Dune
726 
727 #endif // #ifndef DUNE_FEM_CGINVERSEOPERATOR_HH
Inverse operator base on CG method. Uses a runtime parameter fem.preconditioning which enables diagon...
Definition: cginverseoperator.hh:408
CGInverseOperator(RealType redEps, RealType absLimit, unsigned int maxIter, bool verbose, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:441
Op OperatorType
type of operator
Definition: cginverseoperator.hh:421
CGInverseOperator(const LinearOperator &op, RealType redEps, RealType absLimit, unsigned int maxIter, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:490
CGInverseOperator(RealType redEps, RealType absLimit, unsigned int maxIter, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:453
CGInverseOperator(const OperatorType &op, const PreconditioningType &precond, RealType redEps, RealType absLimit, unsigned int maxIter, bool verbose, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:516
CGInverseOperator(const LinearOperator &op, RealType redEps, RealType absLimit, unsigned int maxIter, bool verbose, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:473
CGInverseOperator(const OperatorType &op, const PreconditioningType &precond, RealType redEps, RealType absLimit, unsigned int maxIter, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:532
linear solver using the CG algorithm
Definition: cginverseoperator.hh:31
OperatorType::RangeFunctionType RangeFunctionType
type of the operator's range vectors
Definition: cginverseoperator.hh:47
ConjugateGradientSolver(RealType epsilon, unsigned int maxIterations, const ParameterReader &parameter=Parameter::container())
constructor
Definition: cginverseoperator.hh:93
unsigned int iterations() const
number of iterations needed for last solve
Definition: cginverseoperator.hh:135
void solve(const OperatorType &op, const RangeFunctionType &b, DomainFunctionType &x) const
solve
Definition: cginverseoperator.hh:597
double averageCommTime() const
return average communication time during last solve
Definition: cginverseoperator.hh:144
void solve(const OperatorType &op, const PreconditionerType &p, const RangeFunctionType &b, DomainFunctionType &x) const
solve
Definition: cginverseoperator.hh:655
Fem::Operator< RangeFunctionType, DomainFunctionType > PreconditionerType
type of the preconditioner, maps from the range of the operator (the dual space) in it's domain
Definition: cginverseoperator.hh:50
OperatorType::RangeFieldType RangeFieldType
field type of the operator's range vectors
Definition: cginverseoperator.hh:41
OperatorType::DomainFieldType DomainFieldType
field type of the operator's domain vectors
Definition: cginverseoperator.hh:39
OperatorType::DomainFunctionType DomainFunctionType
type of the operator's domain vectors
Definition: cginverseoperator.hh:45
Operator OperatorType
type of the operators to invert
Definition: cginverseoperator.hh:36
ConjugateGradientSolver(const RealType &epsilon, unsigned int maxIterations, int errorMeasure, bool verbose)
constructor
Definition: cginverseoperator.hh:65
Container for User Specified Parameters.
Definition: parameter.hh:191
Inverse operator base on CG method. This is the base class for the cg solver and does not imvolve any...
Definition: cginverseoperator.hh:172
CGInverseOperator(const OperatorType &op, RealType redEps, RealType absLimit, unsigned int maxIter, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:260
CGInverseOperator(RealType redEps, RealType absLimit, unsigned int maxIter, bool verbose, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:200
virtual void operator()(const DomainFunctionType &arg, RangeFunctionType &dest) const
application operator
Definition: cginverseoperator.hh:339
CGInverseOperator(const OperatorType &op, const PreconditionerType &precond, RealType redEps, RealType absLimit, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:304
CGInverseOperator(RealType redEps, RealType absLimit, unsigned int maxIter, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:223
unsigned int iterations() const
number of iterations needed for last solve
Definition: cginverseoperator.hh:368
virtual void apply(const DomainFunctionType &arg, RangeFunctionType &dest) const
application operator
Definition: cginverseoperator.hh:358
CGInverseOperator(const OperatorType &op, const PreconditionerType &precond, RealType redEps, RealType absLimit, unsigned int maxIter, bool verbose, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:286
double averageCommTime() const
return average communication time during last solve
Definition: cginverseoperator.hh:376
CGInverseOperator(const OperatorType &op, RealType redEps, RealType absLimit, unsigned int maxIter, bool verbose, const ParameterReader &parameter=Parameter::container())
constructor of CGInverseOperator
Definition: cginverseoperator.hh:243
A linear operator.
Definition: operators.hh:67
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
Dune namespace.
Definition: alignedallocator.hh:13
abstract affine-linear operator
Definition: operator.hh:87
abstract operator
Definition: operator.hh:34
virtual void finalize()
finalization of operator
Definition: operator.hh:61
DomainFunction DomainFunctionType
type of discrete function in the operator's domain
Definition: operator.hh:36
RangeFunction::RangeFieldType RangeFieldType
field type of the operator's range
Definition: operator.hh:43
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
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)