diff --git a/.gitignore b/.gitignore index d896e231f34910cb510864a1956a5904a0a628ba..d4c8ca60f31914b314371580fa2e0d4928656d94 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ ltmain.sh am .libs/ .deps/ +*~ *.o test-driver build-cmake/ diff --git a/dune/istl/CMakeLists.txt b/dune/istl/CMakeLists.txt index 9209396cdbad0480d4c5e981485a79fb76e6b7e1..1f288b77a66664d1f13702b3358ab98664b02d02 100644 --- a/dune/istl/CMakeLists.txt +++ b/dune/istl/CMakeLists.txt @@ -28,12 +28,14 @@ install(FILES overlappingschwarz.hh owneroverlapcopy.hh pardiso.hh + preconditoner.hh preconditioners.hh repartition.hh scalarproducts.hh scaledidmatrix.hh schwarz.hh solvercategory.hh + solver.hh solvers.hh solvertype.hh superlu.hh diff --git a/dune/istl/Makefile.am b/dune/istl/Makefile.am index 8c2474f89520a2081897db6ccf5e9b719b9abe41..f36255c2653eb53d16d23bf2212efb7fbaa413c3 100644 --- a/dune/istl/Makefile.am +++ b/dune/istl/Makefile.am @@ -27,12 +27,14 @@ istl_HEADERS = basearray.hh \ overlappingschwarz.hh \ owneroverlapcopy.hh \ pardiso.hh \ + preconditioner.hh \ preconditioners.hh \ repartition.hh \ scalarproducts.hh \ scaledidmatrix.hh \ schwarz.hh \ solvercategory.hh \ + solver.hh \ solvers.hh \ solvertype.hh \ superlu.hh \ diff --git a/dune/istl/paamg/aggregates.hh b/dune/istl/paamg/aggregates.hh index 769a76023302dd692add7ea16b37a52a46743777..e5005386f6e59aea6e435a4f1d19dbf2a9e344bd 100644 --- a/dune/istl/paamg/aggregates.hh +++ b/dune/istl/paamg/aggregates.hh @@ -1504,8 +1504,9 @@ namespace Dune template<class G,class S> inline void Aggregate<G,S>::add(std::vector<Vertex>& vertices) { +#ifndef NDEBUG std::size_t oldsize = vertices_.size(); - +#endif typedef typename std::vector<Vertex>::iterator Iterator; typedef typename VertexSet::iterator SIterator; diff --git a/dune/istl/preconditioner.hh b/dune/istl/preconditioner.hh new file mode 100644 index 0000000000000000000000000000000000000000..79452c3e01e287d75c47c87cb940b9cb763f6064 --- /dev/null +++ b/dune/istl/preconditioner.hh @@ -0,0 +1,82 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_PRECONDITIONER_HH +#define DUNE_PRECONDITIONER_HH +namespace Dune { +/** + * @addtogroup ISTL_Prec + * @{ + */ + //===================================================================== + /*! \brief Base class for matrix free definition of preconditioners. + + Note that the operator, which is the basis for the preconditioning, + is supplied to the preconditioner from the outside in the + constructor or some other method. + + This interface allows the encapsulation of all parallelization + aspects into the preconditioners. + + \tparam X Type of the update + \tparam Y Type of the defect + + */ + //===================================================================== + template<class X, class Y> + class Preconditioner { + public: + //! \brief The domain type of the preconditioner. + typedef X domain_type; + //! \brief The range type of the preconditioner. + typedef Y range_type; + //! \brief The field type of the preconditioner. + typedef typename X::field_type field_type; + + /*! \brief Prepare the preconditioner. + + A solver solves a linear operator equation A(x)=b by applying + one or several steps of the preconditioner. The method pre() + is called before the first apply operation. + b and x are right hand side and solution vector of the linear + system respectively. It may. e.g., scale the system, allocate memory or + compute a (I)LU decomposition. + Note: The ILU decomposition could also be computed in the constructor + or with a separate method of the derived method if several + linear systems with the same matrix are to be solved. + + \param x The left hand side of the equation. + \param b The right hand side of the equation. + */ + virtual void pre (X& x, Y& b) = 0; + + /*! \brief Apply one step of the preconditioner to the system A(v)=d. + + On entry v=0 and d=b-A(x) (although this might not be + computed in that way. On exit v contains the update, i.e + one step computes \f$ v = M^{-1} d \f$ where \f$ M \f$ is the + approximate inverse of the operator \f$ A \f$ characterizing + the preconditioner. + \param[out] v The update to be computed + \param d The current defect. + */ + virtual void apply (X& v, const Y& d) = 0; + + /*! \brief Clean up. + + This method is called after the last apply call for the + linear system to be solved. Memory may be deallocated safely + here. x is the solution of the linear equation. + + \param x The right hand side of the equation. + */ + virtual void post (X& x) = 0; + + // every abstract base class has a virtual destructor + virtual ~Preconditioner () {} + }; + +/** + * @} + */ +} +#endif diff --git a/dune/istl/preconditioners.hh b/dune/istl/preconditioners.hh index 5cb894beeeae3c30d85b6ef7fc795e467bbe8657..7db4c775b31281a20405f9c317a0f11539760086 100644 --- a/dune/istl/preconditioners.hh +++ b/dune/istl/preconditioners.hh @@ -9,6 +9,8 @@ #include <iomanip> #include <string> +#include "preconditioner.hh" +#include "solver.hh" #include "solvercategory.hh" #include "istlexception.hh" #include "matrixutils.hh" @@ -54,75 +56,55 @@ namespace Dune { */ - //===================================================================== - /*! \brief Base class for matrix free definition of preconditioners. - - Note that the operator, which is the basis for the preconditioning, - is supplied to the preconditioner from the outside in the - constructor or some other method. - - This interface allows the encapsulation of all parallelization - aspects into the preconditioners. - - \tparam X Type of the update - \tparam Y Type of the defect + /** + * @brief Turns an InverseOperator into a Preconditioner. + * @tparam O The type of the inverse operator to wrap. */ - //===================================================================== - template<class X, class Y> - class Preconditioner { + template<class O, int c> + class InverseOperator2Preconditioner : + public Preconditioner<typename O::domain_type, typename O::range_type> + { public: //! \brief The domain type of the preconditioner. - typedef X domain_type; + typedef typename O::domain_type domain_type; //! \brief The range type of the preconditioner. - typedef Y range_type; + typedef typename O::range_type range_type; //! \brief The field type of the preconditioner. - typedef typename X::field_type field_type; - - /*! \brief Prepare the preconditioner. + typedef typename range_type::field_type field_type; + typedef O InverseOperator; - A solver solves a linear operator equation A(x)=b by applying - one or several steps of the preconditioner. The method pre() - is called before the first apply operation. - b and x are right hand side and solution vector of the linear - system respectively. It may. e.g., scale the system, allocate memory or - compute a (I)LU decomposition. - Note: The ILU decomposition could also be computed in the constructor - or with a separate method of the derived method if several - linear systems with the same matrix are to be solved. - - \param x The left hand side of the equation. - \param b The right hand side of the equation. - */ - virtual void pre (X& x, Y& b) = 0; - - /*! \brief Apply one step of the preconditioner to the system A(v)=d. + // define the category + enum { + //! \brief The category the preconditioner is part of. + category=c + }; - On entry v=0 and d=b-A(x) (although this might not be - computed in that way. On exit v contains the update, i.e - one step computes \f$ v = M^{-1} d \f$ where \f$ M \f$ is the - approximate inverse of the operator \f$ A \f$ characterizing - the preconditioner. - \param[out] v The update to be computed - \param d The current defect. + /** + * @brief Construct the preconditioner from the solver + * @param inverse_operator The inverse operator to wrap. */ - virtual void apply (X& v, const Y& d) = 0; + InverseOperator2Preconditioner(InverseOperator& inverse_operator) + : inverse_operator_(inverse_operator) + {} - /*! \brief Clean up. + void pre(domain_type&,range_type&) + {} - This method is called after the last apply call for the - linear system to be solved. Memory may be deallocated safely - here. x is the solution of the linear equation. + void apply(domain_type& v, const range_type& d) + { + InverseOperatorResult res; + range_type copy(d); + inverse_operator_.apply(v, copy, res); + } - \param x The right hand side of the equation. - */ - virtual void post (X& x) = 0; + void post(domain_type&) + {} - // every abstract base class has a virtual destructor - virtual ~Preconditioner () {} + private: + InverseOperator& inverse_operator_; }; - //===================================================================== // Implementation of this interface for sequential ISTL-preconditioners //===================================================================== diff --git a/dune/istl/solver.hh b/dune/istl/solver.hh new file mode 100644 index 0000000000000000000000000000000000000000..8ace9496b486558c489567bdfbbf8af0e844c7f0 --- /dev/null +++ b/dune/istl/solver.hh @@ -0,0 +1,157 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: + +#ifndef DUNE_SOLVER_HH +#define DUNE_SOLVER_HH + +#include <iomanip> +#include <ostream> + +namespace Dune +{ +/** + * @addtogroup ISTL_Solvers + * @{ + */ +/** \file + + \brief Define general, extensible interface for inverse operators. + + Implementation here covers only inversion of linear operators, + but the implementation might be used for nonlinear operators + as well. + */ + /** + \brief Statistics about the application of an inverse operator + + The return value of an application of the inverse + operator delivers some important information about + the iteration. + */ + struct InverseOperatorResult + { + /** \brief Default constructor */ + InverseOperatorResult () + { + clear(); + } + + /** \brief Resets all data */ + void clear () + { + iterations = 0; + reduction = 0; + converged = false; + conv_rate = 1; + elapsed = 0; + } + + /** \brief Number of iterations */ + int iterations; + + /** \brief Reduction achieved: \f$ \|b-A(x^n)\|/\|b-A(x^0)\|\f$ */ + double reduction; + + /** \brief True if convergence criterion has been met */ + bool converged; + + /** \brief Convergence rate (average reduction per step) */ + double conv_rate; + + /** \brief Elapsed time in seconds */ + double elapsed; + }; + + + //===================================================================== + /*! + \brief Abstract base class for all solvers. + + An InverseOperator computes the solution of \f$ A(x)=b\f$ where + \f$ A : X \to Y \f$ is an operator. + Note that the solver "knows" which operator + to invert and which preconditioner to apply (if any). The + user is only interested in inverting the operator. + InverseOperator might be a Newton scheme, a Krylov subspace method, + or a direct solver or just anything. + */ + template<class X, class Y> + class InverseOperator { + public: + //! \brief Type of the domain of the operator to be inverted. + typedef X domain_type; + + //! \brief Type of the range of the operator to be inverted. + typedef Y range_type; + + /** \brief The field type of the operator. */ + typedef typename X::field_type field_type; + + /** + \brief Apply inverse operator, + + \warning Note: right hand side b may be overwritten! + + \param x The left hand side to store the result in. + \param b The right hand side + \param res Object to store the statistics about applying the operator. + */ + virtual void apply (X& x, Y& b, InverseOperatorResult& res) = 0; + + /*! + \brief apply inverse operator, with given convergence criteria. + + \warning Right hand side b may be overwritten! + + \param x The left hand side to store the result in. + \param b The right hand side + \param reduction The minimum defect reduction to achieve. + \param res Object to store the statistics about applying the operator. + */ + virtual void apply (X& x, Y& b, double reduction, InverseOperatorResult& res) = 0; + + //! \brief Destructor + virtual ~InverseOperator () {} + + protected: + // spacing values + enum { iterationSpacing = 5 , normSpacing = 16 }; + + //! helper function for printing header of solver output + void printHeader(std::ostream& s) const + { + s << std::setw(iterationSpacing) << " Iter"; + s << std::setw(normSpacing) << "Defect"; + s << std::setw(normSpacing) << "Rate" << std::endl; + } + + //! helper function for printing solver output + template <class DataType> + void printOutput(std::ostream& s, + const double iter, + const DataType& norm, + const DataType& norm_old) const + { + const DataType rate = norm/norm_old; + s << std::setw(iterationSpacing) << iter << " "; + s << std::setw(normSpacing) << norm << " "; + s << std::setw(normSpacing) << rate << std::endl; + } + + //! helper function for printing solver output + template <class DataType> + void printOutput(std::ostream& s, + const double iter, + const DataType& norm) const + { + s << std::setw(iterationSpacing) << iter << " "; + s << std::setw(normSpacing) << norm << std::endl; + } + }; + +/** + * @} + */ +} + +#endif diff --git a/dune/istl/solvers.hh b/dune/istl/solvers.hh index 64be4dd674a1959bee6a2804937cfccf3462abe6..27f191824ae9bd1a87ea5341fa65415e937d470f 100644 --- a/dune/istl/solvers.hh +++ b/dune/istl/solvers.hh @@ -9,11 +9,13 @@ #include <iostream> #include <iomanip> #include <string> +#include <vector> #include "istlexception.hh" #include "operators.hh" -#include "preconditioners.hh" #include "scalarproducts.hh" +#include "solver.hh" +#include "preconditioner.hh" #include <dune/common/timer.hh> #include <dune/common/ftraits.hh> #include <dune/common/shared_ptr.hh> @@ -30,143 +32,14 @@ namespace Dune { /** \file - \brief Define general, extensible interface for inverse operators. + \brief Implementations of the inverse operator interface. - Implementation here covers only inversion of linear operators, - but the implementation might be used for nonlinear operators - as well. + This file provides various preconditioned Krylov methods. */ - /** - \brief Statistics about the application of an inverse operator - - The return value of an application of the inverse - operator delivers some important information about - the iteration. - */ - struct InverseOperatorResult - { - /** \brief Default constructor */ - InverseOperatorResult () - { - clear(); - } - - /** \brief Resets all data */ - void clear () - { - iterations = 0; - reduction = 0; - converged = false; - conv_rate = 1; - elapsed = 0; - } - - /** \brief Number of iterations */ - int iterations; - - /** \brief Reduction achieved: \f$ \|b-A(x^n)\|/\|b-A(x^0)\|\f$ */ - double reduction; - - /** \brief True if convergence criterion has been met */ - bool converged; - - /** \brief Convergence rate (average reduction per step) */ - double conv_rate; - - /** \brief Elapsed time in seconds */ - double elapsed; - }; - - - //===================================================================== - /*! - \brief Abstract base class for all solvers. - - An InverseOperator computes the solution of \f$ A(x)=b\f$ where - \f$ A : X \to Y \f$ is an operator. - Note that the solver "knows" which operator - to invert and which preconditioner to apply (if any). The - user is only interested in inverting the operator. - InverseOperator might be a Newton scheme, a Krylov subspace method, - or a direct solver or just anything. - */ - template<class X, class Y> - class InverseOperator { - public: - //! \brief Type of the domain of the operator to be inverted. - typedef X domain_type; - - //! \brief Type of the range of the operator to be inverted. - typedef Y range_type; - - /** \brief The field type of the operator. */ - typedef typename X::field_type field_type; - - /** - \brief Apply inverse operator, - \warning Note: right hand side b may be overwritten! - \param x The left hand side to store the result in. - \param b The right hand side - \param res Object to store the statistics about applying the operator. - */ - virtual void apply (X& x, Y& b, InverseOperatorResult& res) = 0; - - /*! - \brief apply inverse operator, with given convergence criteria. - - \warning Right hand side b may be overwritten! - - \param x The left hand side to store the result in. - \param b The right hand side - \param reduction The minimum defect reduction to achieve. - \param res Object to store the statistics about applying the operator. - */ - virtual void apply (X& x, Y& b, double reduction, InverseOperatorResult& res) = 0; - - //! \brief Destructor - virtual ~InverseOperator () {} - - protected: - // spacing values - enum { iterationSpacing = 5 , normSpacing = 16 }; - - //! helper function for printing header of solver output - void printHeader(std::ostream& s) const - { - s << std::setw(iterationSpacing) << " Iter"; - s << std::setw(normSpacing) << "Defect"; - s << std::setw(normSpacing) << "Rate" << std::endl; - } - - //! helper function for printing solver output - template <class DataType> - void printOutput(std::ostream& s, - const double iter, - const DataType& norm, - const DataType& norm_old) const - { - const DataType rate = norm/norm_old; - s << std::setw(iterationSpacing) << iter << " "; - s << std::setw(normSpacing) << norm << " "; - s << std::setw(normSpacing) << rate << std::endl; - } - - //! helper function for printing solver output - template <class DataType> - void printOutput(std::ostream& s, - const double iter, - const DataType& norm) const - { - s << std::setw(iterationSpacing) << iter << " "; - s << std::setw(normSpacing) << norm << std::endl; - } - }; - - - //===================================================================== + //===================================================================== // Implementation of this interface //===================================================================== @@ -302,6 +175,9 @@ namespace Dune { } } + //correct i which is wrong if convergence was not achieved. + i=std::min(_maxit,i); + // print if (_verbose==1) this->printOutput(std::cout,i,def); @@ -437,6 +313,9 @@ namespace Dune { } } + //correct i which is wrong if convergence was not achieved. + i=std::min(_maxit,i); + if (_verbose==1) // printing for non verbose this->printOutput(std::cout,i,def); @@ -598,6 +477,9 @@ namespace Dune { rholast = rho; // remember rho for recurrence } + //correct i which is wrong if convergence was not achieved. + i=std::min(_maxit,i); + if (_verbose==1) // printing for non verbose this->printOutput(std::cout,i,def); @@ -864,6 +746,9 @@ namespace Dune { norm_old = norm; } // end for + //correct i which is wrong if convergence was not achieved. + it=std::min((double)_maxit,it); + if (_verbose==1) // printing for non verbose this->printOutput(std::cout,it,norm); @@ -1110,6 +995,9 @@ namespace Dune { } } + //correct i which is wrong if convergence was not achieved. + i=std::min(_maxit,i); + if (_verbose==1) // printing for non verbose this->printOutput(std::cout,i,def); @@ -1369,6 +1257,9 @@ namespace Dune { res.converged = false; } + //correct i which is wrong if convergence was not achieved. + j=std::min(_maxit,j); + if (_verbose > 1) // print { this->printOutput(std::cout,j,norm,norm_old); diff --git a/dune/istl/test/CMakeLists.txt b/dune/istl/test/CMakeLists.txt index 9ea18d131f35caf6627856c9ca6fe91b1618ad86..60b3dfed0e2f741925ed79f5d91883128ed061e3 100644 --- a/dune/istl/test/CMakeLists.txt +++ b/dune/istl/test/CMakeLists.txt @@ -4,6 +4,7 @@ set(NORMALTEST bcrsbuildtest dotproducttest iotest + inverseoperator2prectest matrixiteratortest matrixtest matrixutilstest @@ -50,6 +51,7 @@ add_executable(matrixiteratortest "matrixiteratortest.cc") add_executable(mmtest mmtest.cc) add_executable(mv "mv.cc") add_executable(iotest "iotest.cc") +add_executable(inverseoperator2prectest "inverseoperator2prectest.cc") add_executable(scaledidmatrixtest "scaledidmatrixtest.cc") add_executable(seqmatrixmarkettest "matrixmarkettest.cc") #set_target_properties(seqmatrixmarkettest PROPERTIES COMPILE_FLAGS diff --git a/dune/istl/test/Makefile.am b/dune/istl/test/Makefile.am index f6d05b0759018b6c76029f1cea5d699b6b976cba..c0de4632f4cd9f65b52592e50e483bed7f994cd0 100644 --- a/dune/istl/test/Makefile.am +++ b/dune/istl/test/Makefile.am @@ -23,6 +23,7 @@ NORMALTESTS = basearraytest \ complexrhstest \ dotproducttest \ iotest \ + inverseoperator2prectest \ matrixiteratortest \ matrixtest \ matrixutilstest \ @@ -103,6 +104,8 @@ mv_SOURCES = mv.cc iotest_SOURCES = iotest.cc +inverseoperator2prectest_SOURCES = inverseoperator2prectest.cc + scaledidmatrixtest_SOURCES = scaledidmatrixtest.cc if MPI diff --git a/dune/istl/test/complexrhstest.cc b/dune/istl/test/complexrhstest.cc index 0ab63b801d4d9edce19d30c757587ddd3b2edff2..d1a9ee073e530c9afed72a7842a7985123b934cd 100644 --- a/dune/istl/test/complexrhstest.cc +++ b/dune/istl/test/complexrhstest.cc @@ -29,6 +29,7 @@ #include <dune/istl/bvector.hh> #include <dune/istl/operators.hh> #include <dune/istl/solvers.hh> +#include <dune/istl/preconditioners.hh> #include "laplacian.hh" #if HAVE_SUPERLU diff --git a/dune/istl/test/inverseoperator2prectest.cc b/dune/istl/test/inverseoperator2prectest.cc new file mode 100644 index 0000000000000000000000000000000000000000..595b137432cce8d933c273cb915622b569c46821 --- /dev/null +++ b/dune/istl/test/inverseoperator2prectest.cc @@ -0,0 +1,61 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#include "config.h" +#include<dune/istl/bvector.hh> +#include<dune/istl/superlu.hh> +#include<dune/istl/preconditioners.hh> +#include<dune/istl/solvers.hh> +#include<dune/istl/operators.hh> +#include <dune/common/fmatrix.hh> +#include <dune/common/fvector.hh> +#include <laplacian.hh> + +int main(int argc, char** argv) +{ + const int BS=1; + int N=100; + + if(argc>1) + N = atoi(argv[1]); + std::cout<<"testing for N="<<N<<" BS="<<1<<std::endl; + + typedef Dune::FieldMatrix<double,BS,BS> MatrixBlock; + typedef Dune::BCRSMatrix<MatrixBlock> BCRSMat; + typedef Dune::FieldVector<double,BS> VectorBlock; + typedef Dune::BlockVector<VectorBlock> BVector; + typedef Dune::MatrixAdapter<BCRSMat,BVector,BVector> Operator; + + BCRSMat mat; + Operator fop(mat); + BVector b(N*N), x(N*N); + + setupLaplacian(mat,N); + b=0; + x=100; + + Dune::InverseOperatorResult res, res1; + x=1; + mat.mv(x, b); + x=0; + Dune::SeqJac<BCRSMat,BVector,BVector> prec0(mat, 1,1.0); + const int category = Dune::SeqJac<BCRSMat,BVector,BVector>::category; + Dune::LoopSolver<BVector> solver0(fop, prec0, 1e-3,10,0); + Dune::InverseOperator2Preconditioner<Dune::LoopSolver<BVector>,category > + prec(solver0); + Dune::LoopSolver<BVector> solver(fop, prec, 1e-8,10,2); + solver.apply(x,b,res); + + x=1; + mat.mv(x, b); + x=0; + std::cout<<"solver1"<<std::endl; + Dune::LoopSolver<BVector> solver1(fop, prec0, 1e-8,100,2); + solver1.apply(x,b,res1); + + if(res1.iterations!=res.iterations*10) + { + std::cerr<<"Convergence rates do not match!"<<std::endl; + return 1; + } + return 0; +}