From db914f1c783a3f1595908114a00de0db04aa9306 Mon Sep 17 00:00:00 2001 From: Bernd Flemisch <bernd@iws.uni-stuttgart.de> Date: Wed, 12 Dec 2012 17:13:58 +0000 Subject: [PATCH] implicit branch: copy AMGBackend from devel. Copy and modify the necessary PDELab backend files. git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/branches/implicit@9821 2fb0f335-1f38-0410-981e-8018bf24f1b0 --- dumux/linear/amgbackend.hh | 246 +++++ dumux/linear/istlvectorbackend.hh | 262 +++++ dumux/linear/novlpistlsolverbackend.hh | 1346 ++++++++++++++++++++++++ dumux/linear/ovlpistlsolverbackend.hh | 1000 ++++++++++++++++++ dumux/linear/seqistlsolverbackend.hh | 743 +++++++++++++ 5 files changed, 3597 insertions(+) create mode 100644 dumux/linear/amgbackend.hh create mode 100644 dumux/linear/istlvectorbackend.hh create mode 100644 dumux/linear/novlpistlsolverbackend.hh create mode 100644 dumux/linear/ovlpistlsolverbackend.hh create mode 100644 dumux/linear/seqistlsolverbackend.hh diff --git a/dumux/linear/amgbackend.hh b/dumux/linear/amgbackend.hh new file mode 100644 index 0000000000..aebb85536f --- /dev/null +++ b/dumux/linear/amgbackend.hh @@ -0,0 +1,246 @@ +/***************************************************************************** + * Copyright (C) 2011 by Andreas Lauser * + * Institute for Modelling Hydraulic and Environmental Systems * + * University of Stuttgart, Germany * + * email: <givenname>.<name>@iws.uni-stuttgart.de * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief Provides a linear solver for the stabilized BiCG method with + * an ILU-0 preconditioner. + */ +#ifndef DUMUX_AMGBACKEND_HH +#define DUMUX_AMGBACKEND_HH + +#include <dumux/linear/boxlinearsolver.hh> +#include <dumux/boxmodels/pdelab/pdelabadapter.hh> +#include <dumux/boxmodels/pdelab/pdelabboxistlvectorbackend.hh> +#include <dune/pdelab/backend/novlpistlsolverbackend.hh> +#include <dune/pdelab/backend/ovlpistlsolverbackend.hh> +#include <dune/pdelab/backend/seqistlsolverbackend.hh> + +namespace Dumux { + +namespace Properties +{ +NEW_PROP_TAG(GridOperator); +} + +template <class Matrix, class Vector> +void scaleLinearSystem(Matrix& matrix, Vector& rhs) +{ + typename Matrix::RowIterator row = matrix.begin(); + for(; row != matrix.end(); ++row) + { + typedef typename Matrix::size_type size_type; + size_type rowIdx = row.index(); + + typedef typename Matrix::block_type MatrixBlock; + MatrixBlock diagonal = matrix[rowIdx][rowIdx]; + diagonal.invert(); + + typedef typename Vector::block_type VectorBlock; + const VectorBlock b = rhs[rowIdx]; + diagonal.mv(b, rhs[rowIdx]); + + typename Matrix::ColIterator col = row->begin(); + for (; col != row->end(); ++col) + col->leftmultiply(diagonal); + } +} + +template <class TypeTag> +class AMGBackend +{ + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef Dune::PDELab::ISTLBackend_NOVLP_BCGS_AMG_SSOR<GridOperator> Imp; +public: + + AMGBackend(const Problem& problem) + : problem_(problem) + {} + + template<class Matrix, class Vector> + bool solve(Matrix& A, Vector& x, Vector& b) + { + imp_ = new Imp(problem_.gridFunctionSpace(), + GET_PROP_VALUE(TypeTag, LinearSolverMaxIterations), + GET_PROP_VALUE(TypeTag, LinearSolverVerbosity)); + + static const double residReduction = GET_PROP_VALUE(TypeTag, LinearSolverResidualReduction); + imp_->apply(A, x, b, residReduction); + + result_.converged = imp_->result().converged; + result_.iterations = imp_->result().iterations; + result_.elapsed = imp_->result().elapsed; + result_.reduction = imp_->result().reduction; + result_.conv_rate = imp_->result().conv_rate; + + delete imp_; + + return result_.converged; + } + + const Dune::InverseOperatorResult& result() const + { + return result_; + } + +private: + const Problem& problem_; + Imp *imp_; + Dune::InverseOperatorResult result_; +}; + +template <class TypeTag> +class CCAMGBackend +{ + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef Dune::PDELab::ISTLBackend_BCGS_AMG_SSOR<GridOperator> Imp; +public: + + CCAMGBackend(const Problem& problem) + : problem_(problem) + {} + + template<class Matrix, class Vector> + bool solve(Matrix& A, Vector& x, Vector& b) + { + imp_ = new Imp(problem_.gridFunctionSpace(), + GET_PROP_VALUE(TypeTag, LinearSolverMaxIterations), + GET_PROP_VALUE(TypeTag, LinearSolverVerbosity)); + + static const double residReduction = GET_PROP_VALUE(TypeTag, LinearSolverResidualReduction); + imp_->apply(A, x, b, residReduction); + + result_.converged = imp_->result().converged; + result_.iterations = imp_->result().iterations; + result_.elapsed = imp_->result().elapsed; + result_.reduction = imp_->result().reduction; + result_.conv_rate = imp_->result().conv_rate; + + delete imp_; + + return result_.converged; + } + + const Dune::InverseOperatorResult& result() const + { + return result_; + } + +private: + const Problem& problem_; + Imp *imp_; + Dune::InverseOperatorResult result_; +}; + +template <class TypeTag> +class SeqAMGBackend +{ + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef Dune::PDELab::ISTLBackend_SEQ_BCGS_AMG_SSOR<GridOperator> Imp; +public: + + SeqAMGBackend(const Problem& problem) + : problem_(problem) + {} + + template<class Matrix, class Vector> + bool solve(Matrix& A, Vector& x, Vector& b) + { + imp_ = new Imp( + GET_PROP_VALUE(TypeTag, LinearSolverMaxIterations), + GET_PROP_VALUE(TypeTag, LinearSolverVerbosity)); + + static const double residReduction = GET_PROP_VALUE(TypeTag, LinearSolverResidualReduction); + imp_->apply(A, x, b, residReduction); + + result_.converged = imp_->result().converged; + result_.iterations = imp_->result().iterations; + result_.elapsed = imp_->result().elapsed; + result_.reduction = imp_->result().reduction; + result_.conv_rate = imp_->result().conv_rate; + + delete imp_; + + return result_.converged; + } + + const Dune::InverseOperatorResult& result() const + { + return result_; + } + +private: + const Problem& problem_; + Imp *imp_; + Dune::InverseOperatorResult result_; +}; + +template <class TypeTag> +class ScaledSeqAMGBackend +{ + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef Dune::PDELab::ISTLBackend_SEQ_BCGS_AMG_SSOR<GridOperator> Imp; +public: + + ScaledSeqAMGBackend(const Problem& problem) + : problem_(problem) + {} + + template<class Matrix, class Vector> + bool solve(Matrix& A, Vector& x, Vector& b) + { + scaleLinearSystem(A, b); + + imp_ = new Imp( + GET_PROP_VALUE(TypeTag, LinearSolverMaxIterations), + GET_PROP_VALUE(TypeTag, LinearSolverVerbosity)); + + static const double residReduction = GET_PROP_VALUE(TypeTag, LinearSolverResidualReduction); + imp_->apply(A, x, b, residReduction); + + result_.converged = imp_->result().converged; + result_.iterations = imp_->result().iterations; + result_.elapsed = imp_->result().elapsed; + result_.reduction = imp_->result().reduction; + result_.conv_rate = imp_->result().conv_rate; + + delete imp_; + + return result_.converged; + } + + const Dune::InverseOperatorResult& result() const + { + return result_; + } + +private: + const Problem& problem_; + Imp *imp_; + Dune::InverseOperatorResult result_; +}; + +} // namespace Dumux + +#endif diff --git a/dumux/linear/istlvectorbackend.hh b/dumux/linear/istlvectorbackend.hh new file mode 100644 index 0000000000..cdbdde0705 --- /dev/null +++ b/dumux/linear/istlvectorbackend.hh @@ -0,0 +1,262 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +/***************************************************************************** + * This file is based on the file of DUNE-PDELab with the same name, * + * http://www.dune-project.org/pdelab/. * + * Some changes are made such that the backends work for the vectors and * + * matrices used in Dumux. * + *****************************************************************************/ +#ifndef DUNE_ISTLVECTORBACKEND_HH +#define DUNE_ISTLVECTORBACKEND_HH + +#include<vector> + +#include <dune/common/fvector.hh> +#include <dune/istl/bvector.hh> +#include <dune/pdelab/backend/backendselector.hh> +#include <dune/pdelab/backend/istlmatrixbackend.hh> + +namespace Dumux { + + template<int> class ISTLVectorBackend; + + template<typename T, typename E, int BLOCKSIZE> + class ISTLBlockVectorContainer + { + public: + typedef E ElementType; + typedef Dune::BlockVector< Dune::FieldVector<E,BLOCKSIZE> > ContainerType; + typedef ContainerType BaseT; + typedef typename ContainerType::field_type field_type; + typedef typename ContainerType::iterator iterator; + typedef typename ContainerType::const_iterator const_iterator; + typedef typename ContainerType::block_type block_type; + typedef typename ContainerType::size_type size_type; + typedef ISTLVectorBackend<BLOCKSIZE> Backend; + + ISTLBlockVectorContainer () + {} + ISTLBlockVectorContainer (const T& t_) : container(t_.globalSize()/BLOCKSIZE) + {} + ISTLBlockVectorContainer (const T& t_, const E& e) : container(t_.globalSize()/BLOCKSIZE) + { + container=e; + } + + size_type N() const + { + return container.N(); + } + + + ISTLBlockVectorContainer& operator= (const E& e) + { + container=e; + return *this; + } + + ISTLBlockVectorContainer& operator*= (const E& e) + { + container*=e; + return *this; + } + + + ISTLBlockVectorContainer& operator+= (const E& e) + { + container+=e; + return *this; + } + + ISTLBlockVectorContainer& operator+= (const ISTLBlockVectorContainer& e) + { + container+=e; + return *this; + } + + ISTLBlockVectorContainer& operator-= (const ISTLBlockVectorContainer& e) + { + container-=e; + return *this; + } + + block_type& operator[](std::size_t i) + { + return container[i]; + } + + const block_type& operator[](std::size_t i) const + { + return container[i]; + } + + typename Dune::template FieldTraits<E>::real_type two_norm() const + { + return container.two_norm(); + } + + typename Dune::template FieldTraits<E>::real_type two_norm2() const + { + return container.two_norm2(); + } + + typename Dune::template FieldTraits<E>::real_type one_norm() const + { + return container.one_norm(); + } + + typename Dune::template FieldTraits<E>::real_type infinity_norm() const + { + return container.infinity_norm(); + } + + E operator*(const ISTLBlockVectorContainer& y) const + { + return container*y.base(); + } + + E dot(const ISTLBlockVectorContainer& y) const + { + return container.dot(y.base()); + } + + ISTLBlockVectorContainer& axpy(const E& a, const ISTLBlockVectorContainer& y) + { + container.axpy(a, y); + return *this; + } + + // for debugging and AMG access + ContainerType& base () + { + return container; + } + + const ContainerType& base () const + { + return container; + } + + operator ContainerType&() + { + return container; + } + + operator const ContainerType&() const + { + return container; + } + + iterator begin() + { + return container.begin(); + } + + + const_iterator begin() const + { + return container.begin(); + } + + iterator end() + { + return container.end(); + } + + + const_iterator end() const + { + return container.end(); + } + + size_t flatsize() const + { + return container.size()*BLOCKSIZE; + } + + size_t size() const + { + return container.size(); + } + + void resize(size_t n) + { + container.resize(n); + } + + template<typename X> + void std_copy_to (std::vector<X>& x) const + { + size_t n = flatsize(); + x.resize(n); + for (size_t i=0; i<n; i++) + x[i] = container[i/BLOCKSIZE][i%BLOCKSIZE]; + } + + template<typename X> + void std_copy_from (const std::vector<X>& x) + { + //test if x has the same size as the container + assert (x.size() == flatsize()); + for (size_t i=0; i<flatsize(); i++) + container[i/BLOCKSIZE][i%BLOCKSIZE] = x[i]; + } + + private: + Dune::BlockVector< Dune::FieldVector<E,BLOCKSIZE> > container; + }; + + + //! ISTL backend for FunctionSpace + template<int BLOCKSIZE=1> + class ISTLVectorBackend + { + public: + enum{ + //! \brief export the block size + BlockSize = BLOCKSIZE + }; + + //export Matrix Backend Type + typedef ISTLBCRSMatrixBackend<BLOCKSIZE,BLOCKSIZE> MatrixBackend; + + //! container construction + + // extract type of container element + template<class C> + struct Value + { + typedef typename C::field_type Type; + }; + + //! The size type + typedef typename Dune::BlockVector< Dune::FieldVector<float,BLOCKSIZE> >::size_type size_type; + + // get const_reference to container element + // note: this method does not depend on T! + template<typename C> + static const typename C::field_type& access (const C& c, size_type i) + { + return c.base()[i/BLOCKSIZE][i%BLOCKSIZE]; + } + + // get non const_reference to container element + // note: this method does not depend on T! + template<typename C> + static typename C::field_type& access (C& c, size_type i) + { + return c.base()[i/BLOCKSIZE][i%BLOCKSIZE]; + } + }; + + template<int BLOCKSIZE,typename T, typename E> + struct BackendVectorSelectorHelper<ISTLVectorBackend<BLOCKSIZE>, T, E> + { + typedef ISTLBlockVectorContainer<T,E,BLOCKSIZE> Type; + }; + + + +} // namespace Dumux + +#endif diff --git a/dumux/linear/novlpistlsolverbackend.hh b/dumux/linear/novlpistlsolverbackend.hh new file mode 100644 index 0000000000..da5f1d4bdd --- /dev/null +++ b/dumux/linear/novlpistlsolverbackend.hh @@ -0,0 +1,1346 @@ +// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=8 sw=2 sts=2: +/***************************************************************************** + * This file is based on the file of DUNE-PDELab with the same name, * + * http://www.dune-project.org/pdelab/. * + * Some changes are made such that the backends work for the vectors and * + * matrices used in Dumux. * + *****************************************************************************/ +#ifndef DUNE_NOVLPISTLSOLVERBACKEND_HH +#define DUNE_NOVLPISTLSOLVERBACKEND_HH + +#include <cstddef> + +#include <dune/common/deprecated.hh> +#include <dune/common/mpihelper.hh> + +#include <dune/grid/common/gridenums.hh> + +#include <dune/istl/io.hh> +#include <dune/istl/operators.hh> +#include <dune/istl/owneroverlapcopy.hh> +#include <dune/istl/paamg/amg.hh> +#include <dune/istl/paamg/pinfo.hh> +#include <dune/istl/preconditioners.hh> +#include <dune/istl/scalarproducts.hh> +#include <dune/istl/solvercategory.hh> +#include <dune/istl/solvers.hh> +#include <dune/istl/superlu.hh> + +#include <dune/pdelab/backend/parallelistlhelper.hh> + +#include "istlvectorbackend.hh" +#include "seqistlsolverbackend.hh" + +namespace Dumux { + + //! \addtogroup Backend + //! \ingroup PDELab + //! \{ + + //======================================================== + // Generic support for nonoverlapping grids + //======================================================== + + //! Operator for the non-overlapping parallel case + /** + * Calculate \f$y:=Ax\f$. + * + * \tparam GFS The GridFunctionSpace the vectors apply to. + * \tparam M Type of the matrix. Should be one of the ISTL matrix types. + * \tparam X Type of the vectors the matrix is applied to. + * \tparam Y Type of the result vectors. + */ + template<class GFS, class M, class X, class Y> + class NonoverlappingOperator : public Dune::AssembledLinearOperator<M,X,Y> + { + public: + //! export type of matrix + typedef M matrix_type; + //! export type of vectors the matrix is applied to + typedef X domain_type; + //! export type of result vectors + typedef Y range_type; + //! export type of the entries for x + typedef typename X::field_type field_type; + + //redefine the category, that is the only difference + enum {category=Dune::SolverCategory::nonoverlapping}; + + //! Construct a non-overlapping operator + /** + * \param gfs_ GridFunctionsSpace for the vectors. + * \param A Matrix for this operator. This should be the locally + * assembled matrix. + * \param helper_ Helper for parallel communication (not used). + * + * \note The constructed object stores references to all the objects + * given as parameters here. They should be valid for as long as + * the constructed object is used. They are not needed to + * destruct the constructed object. + * + * \deprecated The helper_ parameter is unused. Use the constructor + * without the helper_ parameter instead. + */ + NonoverlappingOperator (const GFS& gfs_, const M& A, + const ParallelISTLHelper<GFS>& helper_) + DUNE_DEPRECATED + : gfs(gfs_), _A_(A) + { + } + + //! Construct a non-overlapping operator + /** + * \param gfs_ GridFunctionsSpace for the vectors. + * \param A Matrix for this operator. This should be the locally + * assembled matrix. + * + * \note The constructed object stores references to all the objects + * given as parameters here. They should be valid for as long as + * the constructed object is used. They are not needed to + * destruct the constructed object. + */ + NonoverlappingOperator (const GFS& gfs_, const M& A) + : gfs(gfs_), _A_(A) + { } + + //! apply operator + /** + * Compute \f$y:=A(x)\f$ on this process, then make y consistent (sum up + * corresponding entries of y on the different processes and store the + * result back in y on each process). + */ + virtual void apply (const X& x, Y& y) const + { + // apply local operator; now we have sum y_p = sequential y + _A_.mv(x,y); + + // accumulate y on border + Dune::PDELab::AddDataHandle<GFS,Y> adddh(gfs,y); + if (gfs.gridView().comm().size()>1) + gfs.gridView().communicate(adddh,Dune::InteriorBorder_InteriorBorder_Interface,Dune::ForwardCommunication); + } + + //! apply operator to x, scale and add: \f$ y = y + \alpha A(x) \f$ + /** + * Compute \f$y:=\alpha A(x)\f$ on this process, then make y consistent + * (sum up corresponding entries of y on the different processes and + * store the result back in y on each process). + */ + virtual void applyscaleadd (field_type alpha, const X& x, Y& y) const + { + // apply local operator; now we have sum y_p = sequential y + _A_.usmv(alpha,x,y); + + // accumulate y on border + Dune::PDELab::AddDataHandle<GFS,Y> adddh(gfs,y); + if (gfs.gridView().comm().size()>1) + gfs.gridView().communicate(adddh,Dune::InteriorBorder_InteriorBorder_Interface,Dune::ForwardCommunication); + } + + //! extract the matrix + virtual const M& getmat () const + { + return _A_; + } + + private: + const GFS& gfs; + const M& _A_; + }; + + // parallel scalar product assuming no overlap + template<class GFS, class X> + class NonoverlappingScalarProduct : public Dune::ScalarProduct<X> + { + public: + //! export types + typedef X domain_type; + typedef typename X::ElementType field_type; + + //! define the category + enum {category=Dune::SolverCategory::nonoverlapping}; + + /*! \brief Constructor needs to know the grid function space + */ + NonoverlappingScalarProduct (const GFS& gfs_, const ParallelISTLHelper<GFS>& helper_) + : gfs(gfs_), helper(helper_) + {} + + /*! \brief Dot product of two vectors. + It is assumed that the vectors are consistent on the interior+border + partition. + */ + virtual field_type dot (const X& x, const X& y) + { + // do local scalar product on unique partition + field_type sum = 0; + for (typename X::size_type i=0; i<x.base().N(); ++i) + for (typename X::size_type j=0; j<x[i].N(); ++j) + sum += (x[i][j]*y[i][j])*helper.mask(i,j); + + // do global communication + return gfs.gridView().comm().sum(sum); + } + + /*! \brief Norm of a right-hand side vector. + The vector must be consistent on the interior+border partition + */ + virtual double norm (const X& x) + { + return sqrt(static_cast<double>(this->dot(x,x))); + } + + /*! \brief make additive vector consistent + */ + void make_consistent (X& x) const + { + Dune::PDELab::AddDataHandle<GFS,X> adddh(gfs,x); + if (gfs.gridView().comm().size()>1) + gfs.gridView().communicate(adddh,Dune::InteriorBorder_InteriorBorder_Interface,Dune::ForwardCommunication); + } + + private: + const GFS& gfs; + const ParallelISTLHelper<GFS>& helper; + }; + + // parallel Richardson preconditioner + template<class GFS, class X, class Y> + class NonoverlappingRichardson : public Dune::Preconditioner<X,Y> + { + 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::ElementType field_type; + + // define the category + enum { + //! \brief The category the preconditioner is part of. + category=Dune::SolverCategory::nonoverlapping + }; + + //! \brief Constructor. + NonoverlappingRichardson (const GFS& gfs_, const ParallelISTLHelper<GFS>& helper_) + : gfs(gfs_), helper(helper_) + { + } + + /*! + \brief Prepare the preconditioner. + */ + virtual void pre (X& x, Y& b) {} + + /*! + \brief Apply the precondioner. + */ + virtual void apply (X& v, const Y& d) + { + v = d; + } + + /*! + \brief Clean up. + */ + virtual void post (X& x) {} + + private: + const GFS& gfs; + const ParallelISTLHelper<GFS>& helper; + }; + + //! parallel non-overlapping Jacobi preconditioner + /** + * \tparam Diagonal Vector type used to store the diagonal of the matrix + * \tparam X Vector type used to store the result of applying the + * preconditioner. + * \tparam Y Vector type used to store the defect. + * + * The Jacobi preconditioner approximates the inverse of a matrix M by + * taking the diagonal diag(M) and inverting that. In the parallel case + * the matrix M is assumed to be inconsistent, so diagonal entries for + * dofs on the border are summed up over all relevant processes by this + * precoditioner before the inverse is computed. + */ + template<class Diagonal, class X, class Y> + class NonoverlappingJacobi : public Dune::Preconditioner<X,Y> + { + typedef typename Diagonal::Backend DBackend; + + std::size_t gfsSize; + Diagonal diagonal; + + public: + //! The domain type of the operator. + /** + * The preconditioner is an inverse operator, so this is the output type + * of the preconditioner. + */ + typedef X domain_type; + //! \brief The range type of the operator. + /** + * The preconditioner is an inverse operator, so this is the input type + * of the preconditioner. + */ + typedef Y range_type; + //! \brief The field type of the preconditioner. + typedef typename X::ElementType field_type; + + enum { + //! \brief The category the preconditioner is part of. + category=Dune::SolverCategory::nonoverlapping + }; + + //! \brief Constructor. + /** + * \param gfs The GridFunctionSpace the matrix and the vectors live on. + * \param m The matrix whose inverse the preconditioner should + * estimate. m is assumed to be inconsistent (i.e. rows for + * dofs on the border only contain the contribution of the + * local process). + * + * The preconditioner does not store any reference to the gfs or the + * matrix m. The diagonal of m is copied, since it has to be made + * consistent. + */ + template<class GFS, class Matrix> + NonoverlappingJacobi(const GFS& gfs, const Matrix &m) : + gfsSize(gfs.size()), diagonal(gfs) + { + typedef typename Matrix::Backend MBackend; + + for(std::size_t i = 0; i < gfsSize; ++i) + DBackend::access(diagonal, i) = MBackend::access(m, i, i); + + AddDataHandle<GFS, Diagonal> addDH(gfs, diagonal); + gfs.gridView().communicate(addDH, + InteriorBorder_InteriorBorder_Interface, + ForwardCommunication); + } + + //! Prepare the preconditioner. + virtual void pre (X& x, Y& b) {} + + //! Apply the precondioner. + /* + * For this preconditioner, this method works with both consistent and + * inconsistent vectors: if d is consistent, v will be consistent, if d + * is inconsistent, v will be inconsistent. + */ + virtual void apply (X& v, const Y& d) + { + typedef typename X::Backend XBackend; + typedef typename Y::Backend YBackend; + + for(std::size_t i = 0; i < gfsSize; ++i) + XBackend::access(v, i) = + YBackend::access(d, i) / DBackend::access(diagonal, i); + } + + //! Clean up. + virtual void post (X& x) {} + }; + + //! \addtogroup PDELab_novlpsolvers Nonoverlapping Solvers + //! \{ + + //! \brief Nonoverlapping parallel CG solver without preconditioner + template<class GFS> + class ISTLBackend_NOVLP_CG_NOPREC + { + typedef Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_NOVLP_CG_NOPREC (const GFS& gfs_, + unsigned maxiter_=5000, + int verbose_=1) + : gfs(gfs_), phelper(gfs,verbose_), maxiter(maxiter_), verbose(verbose_) + {} + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + template<class V> + typename V::ElementType norm (const V& v) const + { + V x(v); // make a copy because it has to be made consistent + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + psp.make_consistent(x); + return psp.norm(x); + } + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef Dune::PDELab::NonoverlappingOperator<GFS,M,V,W> POP; + POP pop(gfs,A); + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + typedef Dune::PDELab::NonoverlappingRichardson<GFS,V,W> PRICH; + PRICH prich(gfs,phelper); + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + Dune::CGSolver<V> solver(pop,psp,prich,reduction,maxiter,verb); + Dune::InverseOperatorResult stat; + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + /*! \brief Return access to result data */ + const Dune::PDELab::LinearSolverResult<double>& result() const + { + return res; + } + + private: + const GFS& gfs; + PHELPER phelper; + Dune::PDELab::LinearSolverResult<double> res; + unsigned maxiter; + int verbose; + }; + + //! \brief Nonoverlapping parallel CG solver with Jacobi preconditioner + template<class GFS> + class ISTLBackend_NOVLP_CG_Jacobi + { + typedef Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + + const GFS& gfs; + PHELPER phelper; + LinearSolverResult<double> res; + unsigned maxiter; + int verbose; + + public: + //! make a linear solver object + /** + * \param gfs_ A grid function space + * \param maxiter_ Maximum number of iterations to do. + * \param verbose_ Verbosity level, directly handed to the CGSolver. + */ + explicit ISTLBackend_NOVLP_CG_Jacobi(const GFS& gfs_, + unsigned maxiter_ = 5000, + int verbose_ = 1) : + gfs(gfs_), phelper(gfs,verbose_), maxiter(maxiter_), verbose(verbose_) + {} + + //! compute global norm of a vector + /** + * \param v The vector to compute the norm of. Should be an + * inconsistent vector (i.e. the entries corresponding a DoF on + * the border should only contain the summand of this process). + */ + template<class V> + typename V::ElementType norm (const V& v) const + { + V x(v); // make a copy because it has to be made consistent + typedef NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + psp.make_consistent(x); + return psp.norm(x); + } + + //! solve the given linear system + /** + * \param A The matrix to solve. Should be a matrix from one of + * PDELabs ISTL backends (only ISTLBCRSMatrixBackend at + * the moment). + * \param z The solution vector to be computed + * \param r Right hand side + * \param reduction to be achieved + * + * Solve the linear system A*z=r such that + * norm(A*z0-r)/norm(A*z-r) < reduction where z0 is the initial value of + * z. + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef NonoverlappingOperator<GFS,M,V,W> POP; + POP pop(gfs,A); + typedef NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + + typedef typename M::ElementType MField; + typedef typename BackendVectorSelector<GFS,MField>::Type Diagonal; + typedef NonoverlappingJacobi<Diagonal,V,W> PPre; + PPre ppre(gfs,A); + + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + CGSolver<V> solver(pop,psp,ppre,reduction,maxiter,verb); + InverseOperatorResult stat; + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + //! Return access to result data + const LinearSolverResult<double>& result() const + { return res; } + }; + + //! \brief Nonoverlapping parallel BiCGStab solver without preconditioner + template<class GFS> + class ISTLBackend_NOVLP_BCGS_NOPREC + { + typedef Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_NOVLP_BCGS_NOPREC (const GFS& gfs_, unsigned maxiter_=5000, int verbose_=1) + : gfs(gfs_), phelper(gfs,verbose_), maxiter(maxiter_), verbose(verbose_) + {} + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + template<class V> + typename V::ElementType norm (const V& v) const + { + V x(v); // make a copy because it has to be made consistent + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + psp.make_consistent(x); + return psp.norm(x); + } + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef Dune::PDELab::NonoverlappingOperator<GFS,M,V,W> POP; + POP pop(gfs,A); + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + typedef Dune::PDELab::NonoverlappingRichardson<GFS,V,W> PRICH; + PRICH prich(gfs,phelper); + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + Dune::BiCGSTABSolver<V> solver(pop,psp,prich,reduction,maxiter,verb); + Dune::InverseOperatorResult stat; + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + /*! \brief Return access to result data */ + const Dune::PDELab::LinearSolverResult<double>& result() const + { + return res; + } + + private: + const GFS& gfs; + PHELPER phelper; + Dune::PDELab::LinearSolverResult<double> res; + unsigned maxiter; + int verbose; + }; + + //! Solver to be used for explicit time-steppers with (block-)diagonal mass matrix + template<typename GFS> + class ISTLBackend_NOVLP_ExplicitDiagonal + { + typedef Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + + const GFS& gfs; + PHELPER phelper; + Dune::PDELab::LinearSolverResult<double> res; + + public: + /*! \brief make a linear solver object + + \param[in] gfs_ GridFunctionSpace, used to identify DoFs for parallel + communication + */ + explicit ISTLBackend_NOVLP_ExplicitDiagonal(const GFS& gfs_) + : gfs(gfs_), phelper(gfs) + {} + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + template<class V> + typename V::ElementType norm (const V& v) const + { + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,V> PSP; + V x(v); // make a copy because it has to be made consistent + PSP psp(gfs,phelper); + psp.make_consistent(x); + return psp.norm(x); + } + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename W::ElementType reduction) + { + Dune::SeqJac<M,V,W> jac(A,1,1.0); + jac.pre(z,r); + jac.apply(z,r); + jac.post(z); + if (gfs.gridView().comm().size()>1) + { + Dune::PDELab::AddDataHandle<GFS,V> adddh(gfs,z); + gfs.gridView().communicate(adddh,Dune::InteriorBorder_InteriorBorder_Interface,Dune::ForwardCommunication); + } + res.converged = true; + res.iterations = 1; + res.elapsed = 0.0; + res.reduction = reduction; + res.conv_rate = reduction; // pow(reduction,1.0/1) + } + + /*! \brief Return access to result data */ + const Dune::PDELab::LinearSolverResult<double>& result() const + { + return res; + } + }; + //! \} Nonoverlapping Solvers + + /** + * @brief Helper class for adding up matrix entries on border. + * @tparam GridOperator The grid operator to work on. + * @tparam MatrixType The MatrixType. + */ + template<class GridOperator, class MatrixType> + class VertexExchanger + { + typedef MatrixType Matrix; + typedef typename GridOperator::Traits GridOperatorTraits; + typedef typename GridOperatorTraits::JacobianField Scalar; + typedef typename GridOperatorTraits::TrialGridFunctionSpace GFS; + typedef typename GFS::Traits::GridViewType GridView; + enum {dim = GridView::dimension}; + typedef typename GridView::Traits::Grid Grid; + typedef typename Matrix::block_type BlockType; + typedef typename GridView::template Codim<dim>::Iterator VertexIterator; + typedef typename Grid::Traits::GlobalIdSet IDS; + typedef typename IDS::IdType IdType; + typedef typename Matrix::RowIterator RowIterator; + typedef typename Matrix::ColIterator ColIterator; + + public: + /*! \brief Constructor. Sets up the local to global relations. + + \param[in] gridView The grid view to operate on. + */ + VertexExchanger(const GridView& gridView) + : gridView_(gridView) + { + gid2Index_.clear(); + index2GID_.clear(); + + + VertexIterator vertexEndIt = gridView_.template end<dim>(); + for (VertexIterator vertexIt = gridView_.template begin<dim>(); vertexIt != vertexEndIt; ++vertexIt) + { + if (vertexIt->partitionType() == BorderEntity) + { + int localIdx = gridView_.indexSet().index(*vertexIt); + IdType globalIdx = gridView_.grid().globalIdSet().id(*vertexIt); + + std::pair<IdType,int> g2iPair(globalIdx, localIdx); + gid2Index_.insert(g2iPair); + + std::pair<int,IdType> i2gPair(localIdx, globalIdx); + index2GID_.insert(i2gPair); + + } + } + } + + //! A DataHandle class to exchange matrix sparsity patterns + class MatPatternExchange + : public CommDataHandleIF<MatPatternExchange,IdType> { + typedef typename Matrix::RowIterator RowIterator; + typedef typename Matrix::ColIterator ColIterator; + public: + //! Export type of data for message buffer + typedef IdType DataType; + + /** @brief Returns true if data for given valid codim should be communicated + */ + bool contains (int dim, int codim) const + { + return (codim==dim); + } + + /** @brief Returns true if size of data per entity of given dim and codim is a constant + */ + bool fixedsize (int dim, int codim) const + { + return false; + } + + /** @brief How many objects of type DataType have to be sent for a given entity + */ + template<class EntityType> + size_t size (EntityType& e) const + { + int i = gridView_.indexSet().index(e); + int n = 0; + for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) + { + typename std::map<int,IdType>::const_iterator it = index2GID_.find(j.index()); + if (it != index2GID_.end()) + n++; + } + + return n; + } + + /** @brief Pack data from user to message buffer + */ + template<class MessageBuffer, class EntityType> + void gather (MessageBuffer& buff, const EntityType& e) const + { + int i = gridView_.indexSet().index(e); + for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) + { + typename std::map<int,IdType>::const_iterator it=index2GID_.find(j.index()); + if (it != index2GID_.end()) + buff.write(it->second); + } + + } + + /** @brief Unpack data from message buffer to user + */ + template<class MessageBuffer, class EntityType> + void scatter (MessageBuffer& buff, const EntityType& e, size_t n) + { + int i = gridView_.indexSet().index(e); + for (size_t k = 0; k < n; k++) + { + IdType id; + buff.read(id); + // only add entries corresponding to border entities + typename std::map<IdType,int>::const_iterator it = gid2Index_.find(id); + if (it != gid2Index_.end() + && sparsity_[i].find(it->second) == sparsity_[i].end() + && helper_.ghost(it->second,0) != 1<<24) + sparsity_[i].insert(it->second); + } + } + + /** + * @brief Get the communicated sparsity pattern + * @return the vector with the sparsity pattern + */ + std::vector<std::set<int> >& sparsity () + { + return sparsity_; + } + + /** @brief Constructor + @param[in] gridView Grid view. + @param[in] g2i Global to local index map. + @param[in] i2g Local to global index map. + @param[in] A Matrix to operate on. + @param[in] helper parallel istl helper. + */ + MatPatternExchange (const GridView& gridView, + const std::map<IdType,int>& g2i, + const std::map<int,IdType>& i2g, Matrix& A, + const ParallelISTLHelper<GFS>& helper) + : gridView_(gridView), gid2Index_(g2i), index2GID_(i2g), + sparsity_(A.N()), A_(A), helper_(helper) + {} + + private: + const GridView& gridView_; + const std::map<IdType,int>& gid2Index_; + const std::map<int,IdType>& index2GID_; + std::vector<std::set<int> > sparsity_; + Matrix& A_; + const ParallelISTLHelper<GFS>& helper_; + }; + + //! Local matrix blocks associated with the global id set + struct MatEntry + { + IdType first; + BlockType second; + MatEntry (const IdType& f, const BlockType& s) : first(f),second(s) {} + MatEntry () {} + }; + + //! A DataHandle class to exchange matrix entries + class MatEntryExchange + : public CommDataHandleIF<MatEntryExchange,MatEntry> { + typedef typename Matrix::RowIterator RowIterator; + typedef typename Matrix::ColIterator ColIterator; + public: + //! Export type of data for message buffer + typedef MatEntry DataType; + + /** @brief Returns true if data for given valid codim should be communicated + */ + bool contains (int dim, int codim) const + { + return (codim==dim); + } + + /** @brief Returns true if size of data per entity of given dim and codim is a constant + */ + bool fixedsize (int dim, int codim) const + { + return false; + } + + /** @brief How many objects of type DataType have to be sent for a given entity + */ + template<class EntityType> + size_t size (EntityType& e) const + { + int i = gridView_.indexSet().index(e); + int n = 0; + for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) + { + typename std::map<int,IdType>::const_iterator it = index2GID_.find(j.index()); + if (it != index2GID_.end()) + n++; + } + + return n; + } + + /** @brief Pack data from user to message buffer + */ + template<class MessageBuffer, class EntityType> + void gather (MessageBuffer& buff, const EntityType& e) const + { + int i = gridView_.indexSet().index(e); + for (ColIterator j = A_[i].begin(); j != A_[i].end(); ++j) + { + typename std::map<int,IdType>::const_iterator it=index2GID_.find(j.index()); + if (it != index2GID_.end()) + buff.write(MatEntry(it->second,*j)); + } + + } + + /** @brief Unpack data from message buffer to user + */ + template<class MessageBuffer, class EntityType> + void scatter (MessageBuffer& buff, const EntityType& e, size_t n) + { + int i = gridView_.indexSet().index(e); + for (size_t k = 0; k < n; k++) + { + MatEntry m; + buff.read(m); + // only add entries corresponding to border entities + typename std::map<IdType,int>::const_iterator it = gid2Index_.find(m.first); + if (it != gid2Index_.end()) + if (A_[i].find(it->second) != A_[i].end()) + A_[i][it->second] += m.second; + } + } + + /** @brief Constructor + @param[in] gridView Grid view. + @param[in] g2i Global to local index map. + @param[in] i2g Local to global index map. + @param[in] A Matrix to operate on. + */ + MatEntryExchange (const GridView& gridView, const std::map<IdType,int>& g2i, + const std::map<int,IdType>& i2g, + Matrix& A) + : gridView_(gridView), gid2Index_(g2i), index2GID_(i2g), A_(A) + {} + + private: + const GridView& gridView_; + const std::map<IdType,int>& gid2Index_; + const std::map<int,IdType>& index2GID_; + Matrix& A_; + }; + + /** @brief communicates values for the sparsity pattern of the new matrix. + @param A Matrix to operate on. + @param helper ParallelelISTLHelper. + */ + void getextendedmatrix (Matrix& A,const ParallelISTLHelper<GFS>& helper) + { + if (gridView_.comm().size() > 1) { + Matrix tmp(A); + std::size_t nnz=0; + // get entries from other processes + MatPatternExchange datahandle(gridView_, gid2Index_, index2GID_, A, helper); + gridView_.communicate(datahandle, InteriorBorder_InteriorBorder_Interface, ForwardCommunication); + std::vector<std::set<int> >& sparsity = datahandle.sparsity(); + // add own entries, count number of nonzeros + for (RowIterator i = A.begin(); i != A.end(); ++i){ + for (ColIterator j = A[i.index()].begin(); j != A[i.index()].end(); ++j){ + if (sparsity[i.index()].find(j.index()) == sparsity[i.index()].end()) + sparsity[i.index()].insert(j.index()); + } + nnz += sparsity[i.index()].size(); + } + A.setSize(tmp.N(), tmp.N(), nnz); + A.setBuildMode(Matrix::row_wise); + typename Matrix::CreateIterator citer = A.createbegin(); + typedef typename std::vector<std::set<int> >::const_iterator Iter; + for (Iter i = sparsity.begin(), end = sparsity.end(); i!=end; ++i, ++citer){ + typedef typename std::set<int>::const_iterator SIter; + for (SIter si = i->begin(), send = i->end(); si!=send; ++si) + citer.insert(*si); + } + // set matrix old values + A = 0; + for (RowIterator i = tmp.begin(); i != tmp.end(); ++i) + for (ColIterator j = tmp[i.index()].begin(); j != tmp[i.index()].end(); ++j){ + A[i.index()][j.index()] = tmp[i.index()][j.index()]; + } + } + } + + /** @brief Sums up the entries corresponding to border vertices. + @param A Matrix to operate on. + */ + void sumEntries (Matrix& A) + { + if (gridView_.comm().size() > 1) + { + MatEntryExchange datahandle(gridView_, gid2Index_, index2GID_, A); + gridView_.communicate(datahandle, InteriorBorder_InteriorBorder_Interface, ForwardCommunication); + } + } + + private: + const GridView& gridView_; + std::map<IdType,int> gid2Index_; + std::map<int,IdType> index2GID_; + }; + + template<class GO, + template<class,class,class,int> class Preconditioner, + template<class> class Solver> + class ISTLBackend_NOVLP_BASE_PREC + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + typedef Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + + public: + /*! \brief Constructor. + + \param[in] gfs_ a grid function space + \param[in] maxiter_ maximum number of iterations to do + \param[in] steps_ number of preconditioner steps to apply as inner iteration + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_NOVLP_BASE_PREC (const GFS& gfs_, unsigned maxiter_ = 5000, unsigned steps_ = 5, int verbose_ = 1) + : gfs(gfs_), phelper(gfs_,verbose_), + maxiter(maxiter_), steps(steps_), verbose(verbose_) + {} + + /*! \brief Compute global norm of a vector. + + \param[in] v the given vector + */ + template<class Vector> + typename Vector::ElementType norm (const Vector& v) const + { + Vector x(v); // make a copy because it has to be made consistent + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,Vector> PSP; + PSP psp(gfs,phelper); + psp.make_consistent(x); + return psp.norm(x); + } + + /*! \brief Solve the given linear system. + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef typename CommSelector<96,Dune::MPIHelper::isFake>::type Comm; + typedef typename M::BaseT MatrixType; + MatrixType& mat=A.base(); + typedef typename BlockProcessor<GFS>::template AMGVectorTypeSelector<V>::Type VectorType; +#if HAVE_MPI + Comm oocc(gfs.gridView().comm(),Dune::SolverCategory::nonoverlapping); + typedef VertexExchanger<GO,MatrixType> Exchanger; + Exchanger exchanger(gfs.gridView()); + exchanger.getextendedmatrix(mat,phelper); + exchanger.sumEntries(mat); + phelper.createIndexSetAndProjectForAMG(mat, oocc); + typedef Preconditioner<MatrixType,VectorType,VectorType,1> Smoother; + Smoother smoother(mat, steps, 1.0); + typedef Dune::NonoverlappingSchwarzScalarProduct<VectorType,Comm> PSP; + PSP psp(oocc); + typedef Dune::NonoverlappingSchwarzOperator<MatrixType,VectorType,VectorType,Comm> Operator; + Operator oop(mat,oocc); + typedef Dune::NonoverlappingBlockPreconditioner<Comm, Smoother> ParSmoother; + ParSmoother parsmoother(smoother, oocc); +#else + Comm oocc(gfs.gridView().comm()); + typedef Preconditioner<MatrixType,VectorType,VectorType,1> ParSmoother; + ParSmoother parsmoother(mat, steps, 1.0); + typedef Dune::SeqScalarProduct<VectorType> PSP; + PSP psp; + typedef Dune::MatrixAdapter<MatrixType,VectorType,VectorType> Operator; + Operator oop(mat); +#endif + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + Solver<VectorType> solver(oop,psp,parsmoother,reduction,maxiter,verb); + Dune::InverseOperatorResult stat; + //make r consistent + if (gfs.gridView().comm().size()>1){ + Dune::PDELab::AddDataHandle<GFS,V> adddh(gfs,r); + gfs.gridView().communicate(adddh, + Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); + } + + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + /*! \brief Return access to result data. */ + const Dune::PDELab::LinearSolverResult<double>& result() const + { + return res; + } + + private: + const GFS& gfs; + PHELPER phelper; + Dune::PDELab::LinearSolverResult<double> res; + unsigned maxiter; + unsigned steps; + int verbose; + }; + + //! \addtogroup PDELab_novlpsolvers Nonoverlapping Solvers + //! \{ + + /** + * @brief Nonoverlapping parallel BiCGSTAB solver preconditioned by block SSOR. + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + * + * The solver uses a NonoverlappingBlockPreconditioner with underlying + * sequential SSOR preconditioner. The crucial step is to add up the matrix entries + * corresponding to the border vertices on each process. This is achieved by + * performing a VertexExchanger::sumEntries(Matrix&) before constructing the + * sequential SSOR. + */ + template<class GO> + class ISTLBackend_NOVLP_BCGS_SSORk + : public ISTLBackend_NOVLP_BASE_PREC<GO,Dune::SeqSSOR, Dune::BiCGSTABSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] maxiter_ maximum number of iterations to do + \param[in] steps_ number of SSOR steps to apply as inner iteration + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_NOVLP_BCGS_SSORk (const GFS& gfs_, unsigned maxiter_=5000, + int steps_=5, int verbose_=1) + : ISTLBackend_NOVLP_BASE_PREC<GO,Dune::SeqSSOR, Dune::BiCGSTABSolver>(gfs_, maxiter_, steps_, verbose_) + {} + }; + + /** + * @brief Nonoverlapping parallel CG solver preconditioned by block SSOR. + */ + template<class GO> + class ISTLBackend_NOVLP_CG_SSORk + : public ISTLBackend_NOVLP_BASE_PREC<GO,Dune::SeqSSOR, Dune::CGSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] maxiter_ maximum number of iterations to do + \param[in] steps_ number of SSOR steps to apply as inner iteration + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_NOVLP_CG_SSORk (const GFS& gfs_, unsigned maxiter_=5000, + int steps_=5, int verbose_=1) + : ISTLBackend_NOVLP_BASE_PREC<GO,Dune::SeqSSOR, Dune::CGSolver>(gfs_, maxiter_, steps_, verbose_) + {} + }; + //! \} Nonoverlapping Solvers + //! \} group Backend + + template<class GO,int s, template<class,class,class,int> class Preconditioner, + template<class> class Solver> + class ISTLBackend_AMG_NOVLP : public LinearResultStorage + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + typedef typename Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + typedef typename GO::Traits::Jacobian M; + typedef typename M::BaseT MatrixType; + typedef typename GO::Traits::Domain V; + typedef typename BlockProcessor<GFS>::template AMGVectorTypeSelector<V>::Type VectorType; + typedef typename CommSelector<s,Dune::MPIHelper::isFake>::type Comm; +#if HAVE_MPI + typedef Preconditioner<MatrixType,VectorType,VectorType,1> Smoother; + typedef Dune::NonoverlappingBlockPreconditioner<Comm,Smoother> ParSmoother; + typedef Dune::NonoverlappingSchwarzOperator<MatrixType,VectorType,VectorType,Comm> Operator; +#else + typedef Preconditioner<MatrixType,VectorType,VectorType,1> ParSmoother; + typedef Dune::MatrixAdapter<MatrixType,VectorType,VectorType> Operator; +#endif + typedef typename Dune::Amg::SmootherTraits<ParSmoother>::Arguments SmootherArgs; + typedef Dune::Amg::AMG<Operator,VectorType,ParSmoother,Comm> AMG; + typedef Dune::Amg::Parameters Parameters; + + public: + ISTLBackend_AMG_NOVLP(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : gfs(gfs_), phelper(gfs,verbose_), maxiter(maxiter_), + params(15,2000,1.2,1.6,Dune::Amg::noAccu/*Dune::Amg::atOnceAccu*/), + verbose(verbose_), reuse(reuse_), firstapply(true), + usesuperlu(usesuperlu_) + { + params.setDefaultValuesIsotropic(GFS::Traits::GridViewType::Traits::Grid::dimension); + params.setDebugLevel(verbose_); +#if !HAVE_SUPERLU + if (gfs.gridView().comm().rank() == 0 && usesuperlu == true) + { + std::cout << "WARNING: You are using AMG without SuperLU!" + << " Please consider installing SuperLU," + << " or set the usesuperlu flag to false" + << " to suppress this warning." << std::endl; + } +#endif + } + + /*! \brief set AMG parameters + + \param[in] params_ a parameter object of Type Dune::Amg::Parameters + */ + void setParameters(const Parameters& params_) + { + params = params_; + } + + void setparams(Parameters params_) + { + params = params_; + } + + /** + * @brief Get the parameters describing the behaviuour of AMG. + * + * The returned object can be adjusted to ones needs and then can be + * reset using setParameters. + * @return The object holding the parameters of AMG. + */ + const Parameters& parameters() const + { + return params; + } + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + typename V::ElementType norm (const V& v) const + { + V x(v); // make a copy because it has to be made consistent + typedef Dune::PDELab::NonoverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + psp.make_consistent(x); + return psp.norm(x); + } + + void apply(MatrixType& A, V& z, V& r, typename V::ElementType reduction) + { + Timer watch; + MatrixType& mat=A; + typedef Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<MatrixType, + Dune::Amg::FirstDiagonal> > Criterion; +#if HAVE_MPI + Comm oocc(gfs.gridView().comm(),Dune::SolverCategory::nonoverlapping); + typedef VertexExchanger<GO,MatrixType> Exchanger; + Exchanger exchanger(gfs.gridView()); + exchanger.getextendedmatrix(mat,phelper); + exchanger.sumEntries(mat); + phelper.createIndexSetAndProjectForAMG(mat, oocc); + Dune::NonoverlappingSchwarzScalarProduct<VectorType,Comm> sp(oocc); + Operator oop(mat, oocc); +#else + Comm oocc(gfs.gridView().comm()); + Operator oop(mat); + Dune::SeqScalarProduct<VectorType> sp; +#endif + SmootherArgs smootherArgs; + smootherArgs.iterations = 1; + smootherArgs.relaxationFactor = 1; + //use noAccu or atOnceAccu + Criterion criterion(params); + stats.tprepare=watch.elapsed(); + watch.reset(); + + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + //only construct a new AMG if the matrix changes + if (reuse==false || firstapply==true){ + amg.reset(new AMG(oop, criterion, smootherArgs, oocc)); + firstapply = false; + stats.tsetup = watch.elapsed(); + stats.levels = amg->maxlevels(); + stats.directCoarseLevelSolver=amg->usesDirectCoarseLevelSolver(); + } + + Dune::InverseOperatorResult stat; + // make r consistent + if (gfs.gridView().comm().size()>1) { + Dune::PDELab::AddDataHandle<GFS,V> adddh(gfs,r); + gfs.gridView().communicate(adddh, + Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); + } + watch.reset(); + Solver<VectorType> solver(oop,sp,*amg,reduction,maxiter,verb); + solver.apply(BlockProcessor<GFS>::getVector(z),BlockProcessor<GFS>::getVector(r),stat); + stats.tsolve= watch.elapsed(); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + /** + * @brief Get statistics of the AMG solver (no of levels, timings). + * @return statistis of the AMG solver. + */ + const ISTLAMGStatistics& statistics() const + { + return stats; + } + + private: + const GFS& gfs; + PHELPER phelper; + unsigned maxiter; + Parameters params; + int verbose; + bool reuse; + bool firstapply; + bool usesuperlu; + Dune::shared_ptr<AMG> amg; + ISTLAMGStatistics stats; + }; + + template<class GO, int s=96> + class ISTLBackend_NOVLP_CG_AMG_SSOR + : public ISTLBackend_AMG_NOVLP<GO, s, Dune::SeqSSOR, Dune::CGSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + + public: + ISTLBackend_NOVLP_CG_AMG_SSOR(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : ISTLBackend_AMG_NOVLP<GO, s, Dune::SeqSSOR, Dune::CGSolver> + (gfs_, maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + + template<class GO, int s=96> + class ISTLBackend_NOVLP_BCGS_AMG_SSOR + : public ISTLBackend_AMG_NOVLP<GO, s, Dune::SeqSSOR, Dune::BiCGSTABSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + + public: + ISTLBackend_NOVLP_BCGS_AMG_SSOR(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : ISTLBackend_AMG_NOVLP<GO, s, Dune::SeqSSOR, Dune::BiCGSTABSolver> + (gfs_, maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + template<class GO, int s=96> + class ISTLBackend_NOVLP_LS_AMG_SSOR + : public ISTLBackend_AMG_NOVLP<GO, s, Dune::SeqSSOR, Dune::LoopSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + + public: + ISTLBackend_NOVLP_LS_AMG_SSOR(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : ISTLBackend_AMG_NOVLP<GO, s, Dune::SeqSSOR, Dune::LoopSolver> + (gfs_, maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + +} // namespace Dumux + +#endif diff --git a/dumux/linear/ovlpistlsolverbackend.hh b/dumux/linear/ovlpistlsolverbackend.hh new file mode 100644 index 0000000000..6fd40b3b48 --- /dev/null +++ b/dumux/linear/ovlpistlsolverbackend.hh @@ -0,0 +1,1000 @@ +// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=8 sw=2 sts=2: +/***************************************************************************** + * This file is based on the file of DUNE-PDELab with the same name, * + * http://www.dune-project.org/pdelab/. * + * Some changes are made such that the backends work for the vectors and * + * matrices used in Dumux. * + *****************************************************************************/ +#ifndef DUNE_OVLPISTLSOLVERBACKEND_HH +#define DUNE_OVLPISTLSOLVERBACKEND_HH + +#include <dune/common/deprecated.hh> +#include <dune/common/mpihelper.hh> + +#include <dune/istl/owneroverlapcopy.hh> +#include <dune/istl/solvercategory.hh> +#include <dune/istl/operators.hh> +#include <dune/istl/solvers.hh> +#include <dune/istl/preconditioners.hh> +#include <dune/istl/scalarproducts.hh> +#include <dune/istl/paamg/amg.hh> +#include <dune/istl/paamg/pinfo.hh> +#include <dune/istl/io.hh> +#include <dune/istl/superlu.hh> + +#include <dune/pdelab/backend/parallelistlhelper.hh> + +#include "istlvectorbackend.hh" +#include "seqistlsolverbackend.hh" + +namespace Dumux { + + //! \addtogroup Backend + //! \ingroup PDELab + //! \{ + + //======================================================== + // Generic support for overlapping grids + // (need to be used with appropriate constraints) + //======================================================== + + // operator that resets result to zero at constrained DOFS + template<class CC, class M, class X, class Y> + class OverlappingOperator : public Dune::AssembledLinearOperator<M,X,Y> + { + public: + //! export types + typedef M matrix_type; + typedef X domain_type; + typedef Y range_type; + typedef typename X::field_type field_type; + + //redefine the category, that is the only difference + enum {category=Dune::SolverCategory::overlapping}; + + OverlappingOperator (const CC& cc_, const M& A) + : cc(cc_), _A_(A) + {} + + //! apply operator to x: \f$ y = A(x) \f$ + virtual void apply (const X& x, Y& y) const + { + _A_.mv(x,y); + Dune::PDELab::set_constrained_dofs(cc,0.0,y); + } + + //! apply operator to x, scale and add: \f$ y = y + \alpha A(x) \f$ + virtual void applyscaleadd (field_type alpha, const X& x, Y& y) const + { + _A_.usmv(alpha,x,y); + Dune::PDELab::set_constrained_dofs(cc,0.0,y); + } + + //! get matrix via * + virtual const M& getmat () const + { + return _A_; + } + + private: + const CC& cc; + const M& _A_; + }; + + // new scalar product assuming at least overlap 1 + // uses unique partitioning of nodes for parallelization + template<class GFS, class X> + class OverlappingScalarProduct : public Dune::ScalarProduct<X> + { + public: + //! export types + typedef X domain_type; + typedef typename X::ElementType field_type; + + //! define the category + enum {category=Dune::SolverCategory::overlapping}; + + /*! \brief Constructor needs to know the grid function space + */ + OverlappingScalarProduct (const GFS& gfs_, const ParallelISTLHelper<GFS>& helper_) + : gfs(gfs_), helper(helper_) + {} + + + /*! \brief Dot product of two vectors. + It is assumed that the vectors are consistent on the interior+border + partition. + */ + virtual field_type dot (const X& x, const X& y) + { + // do local scalar product on unique partition + field_type sum = 0; + for (typename X::size_type i=0; i<x.base().N(); ++i) + for (typename X::size_type j=0; j<x.base()[i].N(); ++j) + sum += (x.base()[i][j]*y.base()[i][j])*helper.mask(i,j); + + // do global communication + return gfs.gridView().comm().sum(sum); + } + + /*! \brief Norm of a right-hand side vector. + The vector must be consistent on the interior+border partition + */ + virtual double norm (const X& x) + { + return sqrt(static_cast<double>(this->dot(x,x))); + } + + private: + const GFS& gfs; + const ParallelISTLHelper<GFS>& helper; + }; + + // wrapped sequential preconditioner + template<class CC, class GFS, class P> + class OverlappingWrappedPreconditioner + : public Dune::Preconditioner<typename Dune::PDELab::BackendVectorSelector<GFS,typename P::domain_type::field_type>::Type, + typename Dune::PDELab::BackendVectorSelector<GFS,typename P::range_type::field_type>::Type> + { + public: + //! \brief The domain type of the preconditioner. + typedef typename Dune::PDELab::BackendVectorSelector<GFS,typename P::domain_type::field_type>::Type + domain_type; + //! \brief The range type of the preconditioner. + typedef typename Dune::PDELab::BackendVectorSelector<GFS,typename P::range_type::field_type>::Type + range_type; + + // define the category + enum { + //! \brief The category the preconditioner is part of. + category=Dune::SolverCategory::overlapping + }; + + //! Constructor. + OverlappingWrappedPreconditioner (const GFS& gfs_, P& prec_, const CC& cc_, + const ParallelISTLHelper<GFS>& helper_) + : gfs(gfs_), prec(prec_), cc(cc_), helper(helper_) + {} + + /*! + \brief Prepare the preconditioner. + */ + virtual void pre (domain_type& x, range_type& b) + { + prec.pre(x,b); + } + + /*! + \brief Apply the precondioner. + */ + virtual void apply (domain_type& v, const range_type& d) + { + range_type dd(d); + set_constrained_dofs(cc,0.0,dd); + prec.apply(v,dd); + Dune::PDELab::AddDataHandle<GFS,domain_type,typename domain_type::field_type> adddh(gfs,v); + if (gfs.gridView().comm().size()>1) + gfs.gridView().communicate(adddh,Dune::All_All_Interface,Dune::ForwardCommunication); + } + + /*! + \brief Clean up. + */ + virtual void post (domain_type& x) + { + prec.post(x); + } + + private: + const GFS& gfs; + P& prec; + const CC& cc; + const ParallelISTLHelper<GFS>& helper; + }; + + +#if HAVE_SUPERLU + // exact subdomain solves with SuperLU as preconditioner + template<class GFS, class M, class X, class Y> + class SuperLUSubdomainSolver : public Dune::Preconditioner<X,Y> + { + typedef typename M::BaseT ISTLM; + + 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::ElementType field_type; + + + // define the category + enum { + //! \brief The category the preconditioner is part of. + category=Dune::SolverCategory::overlapping + }; + + /*! \brief Constructor. + + Constructor gets all parameters to operate the prec. + \param gfs_ The grid function space. + \param A_ The matrix to operate on. + */ + SuperLUSubdomainSolver (const GFS& gfs_, const M& A_) + : gfs(gfs_), A(A_), solver(A_,false) // this does the decomposition + {} + + /*! + \brief Prepare the preconditioner. + */ + virtual void pre (X& x, Y& b) {} + + /*! + \brief Apply the precondioner. + */ + virtual void apply (X& v, const Y& d) + { + Dune::InverseOperatorResult stat; + Y b(d); // need copy, since solver overwrites right hand side + solver.apply(v,b,stat); + Dune::PDELab::AddDataHandle<GFS,X> adddh(gfs,v); + if (gfs.gridview().comm().size()>1) + gfs.gridview().communicate(adddh,Dune::All_All_Interface,Dune::ForwardCommunication); + } + + /*! + \brief Clean up. + */ + virtual void post (X& x) {} + + private: + const GFS& gfs; + const M& A; + Dune::SuperLU<ISTLM> solver; + }; + + // exact subdomain solves with SuperLU as preconditioner + template<class GFS, class M, class X, class Y> + class RestrictedSuperLUSubdomainSolver : public Dune::Preconditioner<X,Y> + { + typedef typename M::BaseT ISTLM; + + 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::ElementType field_type; + + + // define the category + enum { + //! \brief The category the preconditioner is part of. + category=Dune::SolverCategory::overlapping + }; + + /*! \brief Constructor. + + Constructor gets all parameters to operate the prec. + \param gfs_ The grid function space. + \param A_ The matrix to operate on. + \param helper_ The parallel istl helper. + */ + RestrictedSuperLUSubdomainSolver (const GFS& gfs_, const M& A_, + const ParallelISTLHelper<GFS>& helper_) + : gfs(gfs_), A(A_), solver(A_,false), helper(helper_) // this does the decomposition + {} + + /*! + \brief Prepare the preconditioner. + */ + virtual void pre (X& x, Y& b) {} + + /*! + \brief Apply the precondioner. + */ + virtual void apply (X& v, const Y& d) + { + Dune::InverseOperatorResult stat; + Y b(d); // need copy, since solver overwrites right hand side + solver.apply(v,b,stat); + helper.mask(v); + Dune::PDELab::AddDataHandle<GFS,X> adddh(gfs,v); + if (gfs.gridView().comm().size()>1) + gfs.gridView().communicate(adddh,Dune::InteriorBorder_All_Interface,Dune::ForwardCommunication); + } + + /*! + \brief Clean up. + */ + virtual void post (X& x) {} + + private: + const GFS& gfs; + const M& A; + Dune::SuperLU<ISTLM> solver; + const ParallelISTLHelper<GFS>& helper; + }; +#endif + + template<typename GFS> + class OVLPScalarProductImplementation + { + public: + OVLPScalarProductImplementation(const GFS& gfs_) + : gfs(gfs_), helper(gfs_) + {} + + /*! \brief Dot product of two vectors. + It is assumed that the vectors are consistent on the interior+border + partition. + */ + template<typename X> + typename X::ElementType dot (const X& x, const X& y) const + { + // do local scalar product on unique partition + typename X::ElementType sum = 0; + for (typename X::size_type i=0; i<x.base().N(); ++i) + for (typename X::size_type j=0; j<x[i].N(); ++j) + sum += (x[i][j]*y[i][j])*helper.mask(i,j); + + // do global communication + return gfs.gridView().comm().sum(sum); + } + + /*! \brief Norm of a right-hand side vector. + The vector must be consistent on the interior+border partition + */ + template<typename X> + typename X::ElementType norm (const X& x) const + { + return sqrt(static_cast<double>(this->dot(x,x))); + } + + const ParallelISTLHelper<GFS>& parallelHelper() + { + return helper; + } + + private: + const GFS& gfs; + ParallelISTLHelper<GFS> helper; + }; + + + template<typename GFS, typename X> + class OVLPScalarProduct + : public ScalarProduct<X> + { + public: + enum {category=Dune::SolverCategory::overlapping}; + OVLPScalarProduct(const OVLPScalarProductImplementation<GFS>& implementation_) + : implementation(implementation_) + {} + virtual typename X::ElementType dot(const X& x, const X& y) + { + return implementation.dot(x,y); + } + + virtual typename X::ElementType norm (const X& x) + { + return sqrt(static_cast<double>(this->dot(x,x))); + } + + private: + const OVLPScalarProductImplementation<GFS>& implementation; + }; + + template<class GFS, class C, + template<class,class,class,int> class Preconditioner, + template<class> class Solver> + class ISTLBackend_OVLP_Base + : public OVLPScalarProductImplementation<GFS>, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] c_ a constraints object + \param[in] maxiter_ maximum number of iterations to do + \param[in] steps_ number of SSOR steps to apply as inner iteration + \param[in] verbose_ print messages if true + */ + ISTLBackend_OVLP_Base (const GFS& gfs_, const C& c_, unsigned maxiter_=5000, + int steps_=5, int verbose_=1) + : OVLPScalarProductImplementation<GFS>(gfs_), gfs(gfs_), c(c_), maxiter(maxiter_), steps(steps_), verbose(verbose_) + {} + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef Dune::PDELab::OverlappingOperator<C,M,V,W> POP; + POP pop(c,A); + typedef OVLPScalarProduct<GFS,V> PSP; + PSP psp(*this); + typedef Preconditioner<M,V,W,1> SeqPrec; + SeqPrec seqprec(A,steps,1.0); + typedef Dune::PDELab::OverlappingWrappedPreconditioner<C,GFS,SeqPrec> WPREC; + WPREC wprec(gfs,seqprec,c,this->parallelHelper()); + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + Solver<V> solver(pop,psp,wprec,reduction,maxiter,verb); + Dune::InverseOperatorResult stat; + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + private: + const GFS& gfs; + const C& c; + unsigned maxiter; + int steps; + int verbose; + }; + + // Base class for ILU0 as preconditioner + template<class GFS, class C, + template<class> class Solver> + class ISTLBackend_OVLP_ILU0_Base + : public OVLPScalarProductImplementation<GFS>, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] c_ a constraints object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + ISTLBackend_OVLP_ILU0_Base (const GFS& gfs_, const C& c_, unsigned maxiter_=5000, int verbose_=1) + : OVLPScalarProductImplementation<GFS>(gfs_), gfs(gfs_), c(c_), maxiter(maxiter_), verbose(verbose_) + {} + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef Dune::PDELab::OverlappingOperator<C,M,V,W> POP; + POP pop(c,A); + typedef OVLPScalarProduct<GFS,V> PSP; + PSP psp(*this); + typedef SeqILU0<M,V,W,1> SeqPrec; + SeqPrec seqprec(A,1.0); + typedef Dune::PDELab::OverlappingWrappedPreconditioner<C,GFS,SeqPrec> WPREC; + WPREC wprec(gfs,seqprec,c,this->parallelHelper()); + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + Solver<V> solver(pop,psp,wprec,reduction,maxiter,verb); + Dune::InverseOperatorResult stat; + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + private: + const GFS& gfs; + const C& c; + unsigned maxiter; + int steps; + int verbose; + }; + + //! \addtogroup PDELab_ovlpsolvers Overlapping Solvers + //! \{ + + /** + * @brief Overlapping parallel BiCGStab solver with SSOR preconditioner + * @tparam GFS The Type of the GridFunctionSpace. + * @tparam CC The Type of the Constraints Container. + */ + template<class GFS, class CC> + class ISTLBackend_OVLP_BCGS_SSORk + : public ISTLBackend_OVLP_Base<GFS,CC,Dune::SeqSSOR, Dune::BiCGSTABSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] gfs a grid function space + \param[in] cc a constraints container object + \param[in] maxiter maximum number of iterations to do + \param[in] steps number of SSOR steps to apply as inner iteration + \param[in] verbose print messages if true + */ + ISTLBackend_OVLP_BCGS_SSORk (const GFS& gfs, const CC& cc, unsigned maxiter=5000, + int steps=5, int verbose=1) + : ISTLBackend_OVLP_Base<GFS,CC,Dune::SeqSSOR, Dune::BiCGSTABSolver>(gfs, cc, maxiter, steps, verbose) + {} + }; + /** + * @brief Overlapping parallel BiCGStab solver with ILU0 preconditioner + * @tparam GFS The Type of the GridFunctionSpace. + * @tparam CC The Type of the Constraints Container. + */ + template<class GFS, class CC> + class ISTLBackend_OVLP_BCGS_ILU0 + : public ISTLBackend_OVLP_ILU0_Base<GFS,CC,Dune::BiCGSTABSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] gfs a grid function space + \param[in] cc a constraints container object + \param[in] maxiter maximum number of iterations to do + \param[in] verbose print messages if true + */ + ISTLBackend_OVLP_BCGS_ILU0 (const GFS& gfs, const CC& cc, unsigned maxiter=5000, int verbose=1) + : ISTLBackend_OVLP_ILU0_Base<GFS,CC,Dune::BiCGSTABSolver>(gfs, cc, maxiter, verbose) + {} + }; + /** + * @brief Overlapping parallel CGS solver with SSOR preconditioner + * @tparam GFS The Type of the GridFunctionSpace. + * @tparam CC The Type of the Constraints Container. + */ + template<class GFS, class CC> + class ISTLBackend_OVLP_CG_SSORk + : public ISTLBackend_OVLP_Base<GFS,CC,Dune::SeqSSOR, Dune::CGSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] gfs a grid function space + \param[in] cc a constraints container object + \param[in] maxiter maximum number of iterations to do + \param[in] steps number of SSOR steps to apply as inner iteration + \param[in] verbose print messages if true + */ + ISTLBackend_OVLP_CG_SSORk (const GFS& gfs, const CC& cc, unsigned maxiter=5000, + int steps=5, int verbose=1) + : ISTLBackend_OVLP_Base<GFS,CC,Dune::SeqSSOR, Dune::CGSolver>(gfs, cc, maxiter, steps, verbose) + {} + }; + + //! \} Solver + + template<class GFS, class C, template<typename> class Solver> + class ISTLBackend_OVLP_SuperLU_Base + : public OVLPScalarProductImplementation<GFS>, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] c_ a constraints object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + ISTLBackend_OVLP_SuperLU_Base (const GFS& gfs_, const C& c_, unsigned maxiter_=5000, + int verbose_=1) + : OVLPScalarProductImplementation<GFS>(gfs_), gfs(gfs_), c(c_), maxiter(maxiter_), verbose(verbose_) + {} + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename V::ElementType reduction) + { + typedef Dune::PDELab::OverlappingOperator<C,M,V,W> POP; + POP pop(c,A); + typedef OVLPScalarProduct<GFS,V> PSP; + PSP psp(*this); +#if HAVE_SUPERLU + typedef Dune::PDELab::SuperLUSubdomainSolver<GFS,M,V,W> PREC; + PREC prec(gfs,A); + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + Solver<V> solver(pop,psp,prec,reduction,maxiter,verbose); + Dune::InverseOperatorResult stat; + solver.apply(z,r,stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; +#else + std::cout << "No superLU support, please install and configure it." << std::endl; +#endif + } + + private: + const GFS& gfs; + const C& c; + unsigned maxiter; + int verbose; + }; + + //! \addtogroup PDELab_ovlpsolvers Overlapping Solvers + //! \{ + /** + * @brief Overlapping parallel BiCGStab solver with SuperLU preconditioner + * @tparam GFS The Type of the GridFunctionSpace. + * @tparam CC The Type of the Constraints Container. + */ + template<class GFS, class CC> + class ISTLBackend_OVLP_BCGS_SuperLU + : public ISTLBackend_OVLP_SuperLU_Base<GFS,CC,Dune::BiCGSTABSolver> + { + public: + + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] cc_ a constraints container object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + ISTLBackend_OVLP_BCGS_SuperLU (const GFS& gfs_, const CC& cc_, unsigned maxiter_=5000, + int verbose_=1) + : ISTLBackend_OVLP_SuperLU_Base<GFS,CC,Dune::BiCGSTABSolver>(gfs_,cc_,maxiter_,verbose_) + {} + }; + + /** + * @brief Overlapping parallel CG solver with SuperLU preconditioner + * @tparam GFS The Type of the GridFunctionSpace. + * @tparam CC The Type of the Constraints Container. + */ + template<class GFS, class CC> + class ISTLBackend_OVLP_CG_SuperLU + : public ISTLBackend_OVLP_SuperLU_Base<GFS,CC,Dune::CGSolver> + { + public: + + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + \param[in] cc_ a constraints object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + ISTLBackend_OVLP_CG_SuperLU (const GFS& gfs_, const CC& cc_, + unsigned maxiter_=5000, + int verbose_=1) + : ISTLBackend_OVLP_SuperLU_Base<GFS,CC,Dune::CGSolver>(gfs_,cc_,maxiter_,verbose_) + {} + }; + + + /** @brief Solver to be used for explicit time-steppers with (block-)diagonal mass matrix + * @tparam GFS The Type of the GridFunctionSpace. + */ + template<class GFS> + class ISTLBackend_OVLP_ExplicitDiagonal + : public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] gfs_ a grid function space + */ + explicit ISTLBackend_OVLP_ExplicitDiagonal (const GFS& gfs_) + : gfs(gfs_) + {} + + explicit ISTLBackend_OVLP_ExplicitDiagonal (const ISTLBackend_OVLP_ExplicitDiagonal& other_) + : gfs(other_.gfs) + {} + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + template<class V> + typename V::ElementType norm(const V& v) const + { + dune_static_assert + (AlwaysFalse<V>::value, + "ISTLBackend_OVLP_ExplicitDiagonal::norm() should not be " + "neccessary, so we skipped the implementation. If you have a " + "scenario where you need it, please implement it or report back to " + "us."); + } + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename W::ElementType reduction) + { + Dune::SeqJac<M,V,W> jac(A,1,1.0); + jac.pre(z,r); + jac.apply(z,r); + jac.post(z); + if (gfs.gridView().comm().size()>1) + { + Dune::PDELab::CopyDataHandle<GFS,V> copydh(gfs,z); + gfs.gridView().communicate(copydh,Dune::InteriorBorder_All_Interface,Dune::ForwardCommunication); + } + res.converged = true; + res.iterations = 1; + res.elapsed = 0.0; + res.reduction = reduction; + res.conv_rate = reduction; // pow(reduction,1.0/1) + } + + private: + const GFS& gfs; + }; + //! \} Overlapping Solvers + + /** + * @brief traits class for using AMG with the old grid operator space + * instead of the new grid operator + * @tparam MatrixFT The field type of the matrix. + * @tparam V The type of the BackendVectorSelector + * @tparam GOS The type of the old grid operator space. + */ + template<class MatrixFT, class V, class GOS> + class fakeGOTraits + { + public: + struct Traits{ + typedef V Domain; + typedef MatrixFT JacobianField; + typedef typename V::ElementType DomainField; + typedef typename GOS::Traits GOSTraits; + typedef typename GOSTraits::TrialGridFunctionSpace TrialGridFunctionSpace; + typedef typename GOS::template MatrixContainer<MatrixFT>::Type Jacobian; + }; + }; + + template<class GO, int s, template<class,class,class,int> class Preconditioner, + template<class> class Solver> + class ISTLBackend_AMG : public LinearResultStorage + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + typedef typename Dune::PDELab::ParallelISTLHelper<GFS> PHELPER; + typedef typename GO::Traits::Jacobian M; + typedef typename M::BaseT MatrixType; + typedef typename GO::Traits::Domain V; + typedef typename BlockProcessor<GFS>::template AMGVectorTypeSelector<V>::Type VectorType; + typedef typename CommSelector<s,Dune::MPIHelper::isFake>::type Comm; +#if HAVE_MPI + typedef Preconditioner<MatrixType,VectorType,VectorType,1> Smoother; + typedef Dune::BlockPreconditioner<VectorType,VectorType,Comm,Smoother> ParSmoother; + typedef Dune::OverlappingSchwarzOperator<MatrixType,VectorType,VectorType,Comm> Operator; +#else + typedef Preconditioner<MatrixType,VectorType,VectorType,1> ParSmoother; + typedef Dune::MatrixAdapter<MatrixType,VectorType,VectorType> Operator; +#endif + typedef typename Dune::Amg::SmootherTraits<ParSmoother>::Arguments SmootherArgs; + typedef Dune::Amg::AMG<Operator,VectorType,ParSmoother,Comm> AMG; + + public: + + /** + * @brief Parameters object to customize matrix hierachy building. + */ + typedef Dune::Amg::Parameters Parameters; + + ISTLBackend_AMG(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : gfs(gfs_), phelper(gfs,verbose_), maxiter(maxiter_), params(15,2000,1.2,1.6,Dune::Amg::atOnceAccu), + verbose(verbose_), reuse(reuse_), firstapply(true), + usesuperlu(usesuperlu_) + { + params.setDefaultValuesIsotropic(GFS::Traits::GridViewType::Traits::Grid::dimension); + params.setDebugLevel(verbose_); +#if !HAVE_SUPERLU + if (gfs.gridView().comm().rank() == 0 && usesuperlu == true) + { + std::cout << "WARNING: You are using AMG without SuperLU!" + << " Please consider installing SuperLU," + << " or set the usesuperlu flag to false" + << " to suppress this warning." << std::endl; + } +#endif + } + + /*! \brief set AMG parameters + + \param[in] params_ a parameter object of Type Dune::Amg::Parameters + */ + void setParameters(const Parameters& params_) + { + params = params_; + } + + void setparams(Parameters params_) + { + params = params_; + } + + /** + * @brief Get the parameters describing the behaviuour of AMG. + * + * The returned object can be adjusted to ones needs and then can be + * reset using setParameters. + * @return The object holding the parameters of AMG. + */ + const Parameters& parameters() const + { + return params; + } + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + typename V::ElementType norm (const V& v) const + { + typedef Dune::PDELab::OverlappingScalarProduct<GFS,V> PSP; + PSP psp(gfs,phelper); + return psp.norm(v); + } + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template <class Vector> + void apply(MatrixType& A, Vector& z, Vector& r, typename V::ElementType reduction) + { + Timer watch; + Comm oocc(gfs.gridView().comm()); + MatrixType& mat=A; + typedef Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<MatrixType, + Dune::Amg::FirstDiagonal> > Criterion; +#if HAVE_MPI + phelper.createIndexSetAndProjectForAMG(mat, oocc); + Operator oop(mat, oocc); + Dune::OverlappingSchwarzScalarProduct<VectorType,Comm> sp(oocc); +#else + Operator oop(mat); + Dune::SeqScalarProduct<VectorType> sp; +#endif + SmootherArgs smootherArgs; + smootherArgs.iterations = 1; + smootherArgs.relaxationFactor = 1; + Criterion criterion(params); + stats.tprepare=watch.elapsed(); + watch.reset(); + + int verb=0; + if (gfs.gridView().comm().rank()==0) verb=verbose; + //only construct a new AMG if the matrix changes + if (reuse==false || firstapply==true){ + amg.reset(new AMG(oop, criterion, smootherArgs, oocc)); + firstapply = false; + stats.tsetup = watch.elapsed(); + stats.levels = amg->maxlevels(); + stats.directCoarseLevelSolver=amg->usesDirectCoarseLevelSolver(); + } + watch.reset(); + Solver<VectorType> solver(oop,sp,*amg,reduction,maxiter,verb); + Dune::InverseOperatorResult stat; + +// solver.apply(BlockProcessor<GFS>::getVector(z),BlockProcessor<GFS>::getVector(r),stat); + solver.apply(z,r,stat); + stats.tsolve= watch.elapsed(); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + /** + * @brief Get statistics of the AMG solver (no of levels, timings). + * @return statistis of the AMG solver. + */ + const ISTLAMGStatistics& statistics() const + { + return stats; + } + + private: + const GFS& gfs; + PHELPER phelper; + unsigned maxiter; + Parameters params; + int verbose; + bool reuse; + bool firstapply; + bool usesuperlu; + Dune::shared_ptr<AMG> amg; + ISTLAMGStatistics stats; + }; + + //! \addtogroup PDELab_ovlpsolvers Overlapping Solvers + //! \{ + + /** + * @brief Overlapping parallel conjugate gradient solver preconditioned with AMG smoothed by SSOR + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + * @tparam s The bits to use for the global index. + */ + template<class GO, int s=96> + class ISTLBackend_CG_AMG_SSOR + : public ISTLBackend_AMG<GO, s, Dune::SeqSSOR, Dune::CGSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + public: + /** + * @brief Constructor + * @param gfs_ The grid function space used. + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_CG_AMG_SSOR(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : ISTLBackend_AMG<GO, s, Dune::SeqSSOR, Dune::CGSolver> + (gfs_, maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + /** + * @brief Overlapping parallel BiCGStab solver preconditioned with AMG smoothed by SSOR. + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + * @tparam s The bits to use for the globale index. + */ + template<class GO, int s=96> + class ISTLBackend_BCGS_AMG_SSOR + : public ISTLBackend_AMG<GO, s, Dune::SeqSSOR, Dune::BiCGSTABSolver> + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + public: + /** + * @brief Constructor + * @param gfs_ The grid function space used. + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_BCGS_AMG_SSOR(const GFS& gfs_, unsigned maxiter_=5000, + int verbose_=1, bool reuse_=false, + bool usesuperlu_=true) + : ISTLBackend_AMG<GO, s, Dune::SeqSSOR, Dune::BiCGSTABSolver> + (gfs_, maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + //! \} Overlapping Solvers + + //! \} group Backend + +} // namespace Dumux + +#endif diff --git a/dumux/linear/seqistlsolverbackend.hh b/dumux/linear/seqistlsolverbackend.hh new file mode 100644 index 0000000000..3aa5e06254 --- /dev/null +++ b/dumux/linear/seqistlsolverbackend.hh @@ -0,0 +1,743 @@ +// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=8 sw=2 sts=2: +/***************************************************************************** + * This file is based on the file of DUNE-PDELab with the same name, * + * http://www.dune-project.org/pdelab/. * + * Some changes are made such that the backends work for the vectors and * + * matrices used in Dumux. * + *****************************************************************************/ +#ifndef DUNE_SEQISTLSOLVERBACKEND_HH +#define DUNE_SEQISTLSOLVERBACKEND_HH + +#include <dune/common/deprecated.hh> +#include <dune/common/mpihelper.hh> + +#include <dune/istl/owneroverlapcopy.hh> +#include <dune/istl/solvercategory.hh> +#include <dune/istl/operators.hh> +#include <dune/istl/solvers.hh> +#include <dune/istl/preconditioners.hh> +#include <dune/istl/scalarproducts.hh> +#include <dune/istl/paamg/amg.hh> +#include <dune/istl/paamg/pinfo.hh> +#include <dune/istl/io.hh> +#include <dune/istl/superlu.hh> + +#include <dune/pdelab/constraints/constraints.hh> +#include <dune/pdelab/gridfunctionspace/genericdatahandle.hh> +#include <dune/pdelab/backend/solver.hh> +#include <dune/pdelab/backend/parallelistlhelper.hh> + +#include "istlvectorbackend.hh" + +namespace Dumux { + + //! \addtogroup Backend + //! \ingroup PDELab + //! \{ + + template<typename X, typename Y, typename GOS> + class OnTheFlyOperator : public Dune::LinearOperator<X,Y> + { + public: + typedef X domain_type; + typedef Y range_type; + typedef typename X::field_type field_type; + + enum {category=Dune::SolverCategory::sequential}; + + OnTheFlyOperator (GOS& gos_) + : gos(gos_) + {} + + virtual void apply (const X& x, Y& y) const + { + y = 0.0; + gos.jacobian_apply(x,y); + } + + virtual void applyscaleadd (field_type alpha, const X& x, Y& y) const + { + Y temp(y); + temp = 0.0; + gos.jacobian_apply(x,temp); + y.axpy(alpha,temp); + } + + private: + GOS& gos; + }; + + //============================================================================== + // Here we add some standard linear solvers conforming to the linear solver + // interface required to solve linear and nonlinear problems. + //============================================================================== + + template<template<class,class,class,int> class Preconditioner, + template<class> class Solver> + class ISTLBackend_SEQ_Base + : public SequentialNorm, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_Base(unsigned maxiter_=5000, int verbose_=1) + : maxiter(maxiter_), verbose(verbose_) + {} + + + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename W::ElementType reduction) + { + Dune::MatrixAdapter<typename M::BaseT, + typename V::BaseT, + typename W::BaseT> opa(A); + Preconditioner<typename M::BaseT, + typename V::BaseT, + typename W::BaseT,1> ssor(A, 3, 1.0); + Solver<typename V::BaseT> solver(opa, ssor, reduction, maxiter, verbose); + Dune::InverseOperatorResult stat; + solver.apply(z, r, stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + private: + unsigned maxiter; + int verbose; + }; + + template<template<typename> class Solver> + class ISTLBackend_SEQ_ILU0 + : public SequentialNorm, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_ILU0 (unsigned maxiter_=5000, int verbose_=1) + : maxiter(maxiter_), verbose(verbose_) + {} + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename Dune::template FieldTraits<typename W::ElementType >::real_type reduction) + { + Dune::MatrixAdapter<typename M::BaseT, + typename V::BaseT, + typename W::BaseT> opa(A); + Dune::SeqILU0<typename M::BaseT, + typename V::BaseT, + typename W::BaseT> ilu0(A, 1.0); + Solver<typename V::BaseT> solver(opa, ilu0, reduction, maxiter, verbose); + Dune::InverseOperatorResult stat; + solver.apply(z, r, stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + private: + unsigned maxiter; + int verbose; + }; + + template<template<typename> class Solver> + class ISTLBackend_SEQ_ILUn + : public SequentialNorm, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + \param[in] n The number of levels to be used. + \param[in] w The relaxation factor. + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + ISTLBackend_SEQ_ILUn (int n, double w, unsigned maxiter_=5000, int verbose_=1) + : n_(n), w_(w), maxiter(maxiter_), verbose(verbose_) + {} + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename W::ElementType reduction) + { + Dune::MatrixAdapter<M,V,W> opa(A); + Dune::SeqILUn<typename M::BaseT,V,W> ilu0(A.base(), n_, w_); + Solver<V> solver(opa, ilu0, reduction, maxiter, verbose); + Dune::InverseOperatorResult stat; + solver.apply(z, r, stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + private: + int n_; + double w_; + + unsigned maxiter; + int verbose; + }; + + //! \addtogroup PDELab_seqsolvers Sequential Solvers + //! \{ + + /** + * @brief Backend for sequential loop solver with Jacobi preconditioner. + */ + class ISTLBackend_SEQ_LOOP_Jac + : public ISTLBackend_SEQ_Base<Dune::SeqJac, Dune::LoopSolver> + { + public: + /*! \brief make a linear solver object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_LOOP_Jac (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_Base<Dune::SeqJac, Dune::LoopSolver>(maxiter_, verbose_) + {} + }; + + /** + * @brief Backend for sequential BiCGSTAB solver with Jacobi preconditioner. + */ + class ISTLBackend_SEQ_BCGS_Jac + : public ISTLBackend_SEQ_Base<Dune::SeqJac, Dune::BiCGSTABSolver> + { + public: + /*! \brief make a linear solver object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_BCGS_Jac (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_Base<Dune::SeqJac, Dune::BiCGSTABSolver>(maxiter_, verbose_) + {} + }; + + /** + * @brief Backend for sequential BiCGSTAB solver with SSOR preconditioner. + */ + class ISTLBackend_SEQ_BCGS_SSOR + : public ISTLBackend_SEQ_Base<Dune::SeqSSOR, Dune::BiCGSTABSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_BCGS_SSOR (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_Base<Dune::SeqSSOR, Dune::BiCGSTABSolver>(maxiter_, verbose_) + {} + }; + + /** + * @brief Backend for sequential BiCGSTAB solver with ILU0 preconditioner. + */ + class ISTLBackend_SEQ_BCGS_ILU0 + : public ISTLBackend_SEQ_ILU0<Dune::BiCGSTABSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_BCGS_ILU0 (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_ILU0<Dune::BiCGSTABSolver>(maxiter_, verbose_) + {} + }; + + /** + * @brief Backend for sequential conjugate gradient solver with ILU0 preconditioner. + */ + class ISTLBackend_SEQ_CG_ILU0 + : public ISTLBackend_SEQ_ILU0<Dune::CGSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_CG_ILU0 (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_ILU0<Dune::CGSolver>(maxiter_, verbose_) + {} + }; + + //! \brief Sequential BiCGStab solver with ILU0 preconditioner + class ISTLBackend_SEQ_BCGS_ILUn + : public ISTLBackend_SEQ_ILUn<Dune::BiCGSTABSolver> + { + public: + /*! \brief make a linear solver object + + + \param[in] n_ The number of levels to be used. + \param[in] w_ The relaxation factor. + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_BCGS_ILUn (int n_, double w_=1.0, unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_ILUn<Dune::BiCGSTABSolver>(n_, w_, maxiter_, verbose_) + {} + }; + + //! \brief Sequential congute gradient solver with ILU0 preconditioner + class ISTLBackend_SEQ_CG_ILUn + : public ISTLBackend_SEQ_ILUn<Dune::CGSolver> + { + public: + /*! \brief make a linear solver object + + + \param[in] n_ The number of levels to be used. + \param[in] w_ The relaxation factor. + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_CG_ILUn (int n_, double w_=1.0, unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_ILUn<Dune::CGSolver>(n_, w_, maxiter_, verbose_) + {} + }; + + /** + * @brief Backend for sequential conjugate gradient solver with SSOR preconditioner. + */ + class ISTLBackend_SEQ_CG_SSOR + : public ISTLBackend_SEQ_Base<Dune::SeqSSOR, Dune::CGSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_CG_SSOR (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_Base<Dune::SeqSSOR, Dune::CGSolver>(maxiter_, verbose_) + {} + }; + + /** + * @brief Backend using a MINRes solver preconditioned by SSOR. + */ + class ISTLBackend_SEQ_MINRES_SSOR + : public ISTLBackend_SEQ_Base<Dune::SeqSSOR, Dune::MINRESSolver> + { + public: + /*! \brief make a linear solver object + + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_MINRES_SSOR (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_Base<Dune::SeqSSOR, Dune::MINRESSolver>(maxiter_, verbose_) + {} + }; + + /** + * @brief Backend for conjugate gradient solver with Jacobi preconditioner. + */ + class ISTLBackend_SEQ_CG_Jac + : public ISTLBackend_SEQ_Base<Dune::SeqJac, Dune::CGSolver> + { + public: + /*! \brief make a linear solver object + \param[in] maxiter_ maximum number of iterations to do + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_CG_Jac (unsigned maxiter_=5000, int verbose_=1) + : ISTLBackend_SEQ_Base<Dune::SeqJac, Dune::CGSolver>(maxiter_, verbose_) + {} + }; + +#if HAVE_SUPERLU + /** + * @brief Solver backend using SuperLU as a direct solver. + */ + class ISTLBackend_SEQ_SuperLU + : public SequentialNorm, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + + \param[in] verbose_ print messages if true + */ + explicit ISTLBackend_SEQ_SuperLU (int verbose_=1) + : verbose(verbose_) + {} + + + /*! \brief make a linear solver object + + \param[in] maxiter Maximum number of allowed steps (ignored) + \param[in] verbose_ print messages if true + */ + ISTLBackend_SEQ_SuperLU (int maxiter, int verbose_) + : verbose(verbose_) + {} + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename W::ElementType reduction) + { + typedef typename M::BaseT ISTLM; + Dune::SuperLU<ISTLM> solver(A, verbose); + Dune::InverseOperatorResult stat; + solver.apply(z, r, stat); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + private: + int verbose; + }; +#endif // HAVE_SUPERLU + + //! Solver to be used for explicit time-steppers with (block-)diagonal mass matrix + class ISTLBackend_SEQ_ExplicitDiagonal + : public SequentialNorm, public LinearResultStorage + { + public: + /*! \brief make a linear solver object + */ + ISTLBackend_SEQ_ExplicitDiagonal () + {} + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + template<class M, class V, class W> + void apply(M& A, V& z, W& r, typename W::ElementType reduction) + { + Dune::SeqJac<typename M::BaseT, + typename V::BaseT, + typename W::BaseT> jac(A,1,1.0); + jac.pre(z,r); + jac.apply(z,r); + jac.post(z); + res.converged = true; + res.iterations = 1; + res.elapsed = 0.0; + res.reduction = reduction; + res.conv_rate = reduction; // pow(reduction,1.0/1) + } + }; + + //! \} Sequential Solvers + + /** + * @brief Class providing some statistics of the AMG solver. + * + */ + struct ISTLAMGStatistics + { + /** + * @brief The needed for computing the parallel information and + * for adapting the linear system. + */ + double tprepare; + /** @brief the number of levels in the AMG hierarchy. */ + int levels; + /** @brief The time spent in solving the system (without building the hierarchy. */ + double tsolve; + /** @brief The time needed for building the AMG hierarchy (coarsening). */ + double tsetup; + /** @brief The number of iterations performed until convergence was reached. */ + int iterations; + /** @brief True if a direct solver was used on the coarset level. */ + bool directCoarseLevelSolver; + }; + + template<class GO, template<class,class,class,int> class Preconditioner, template<class> class Solver> + class ISTLBackend_SEQ_AMG : public LinearResultStorage + { + typedef typename GO::Traits::TrialGridFunctionSpace GFS; + typedef typename GO::Traits::Jacobian M; + typedef typename M::BaseT MatrixType; + typedef typename GO::Traits::Domain V; + typedef typename BlockProcessor<GFS>::template AMGVectorTypeSelector<V>::Type VectorType; + typedef Preconditioner<MatrixType,VectorType,VectorType,1> Smoother; + typedef Dune::MatrixAdapter<MatrixType,VectorType,VectorType> Operator; + typedef typename Dune::Amg::SmootherTraits<Smoother>::Arguments SmootherArgs; + typedef Dune::Amg::AMG<Operator,VectorType,Smoother> AMG; + typedef Dune::Amg::Parameters Parameters; + + public: + ISTLBackend_SEQ_AMG(unsigned maxiter_=5000, int verbose_=1, + bool reuse_=false, bool usesuperlu_=true) + : maxiter(maxiter_), params(15,2000), verbose(verbose_), + reuse(reuse_), firstapply(true), usesuperlu(usesuperlu_) + { + params.setDefaultValuesIsotropic(GFS::Traits::GridViewType::Traits::Grid::dimension); + params.setDebugLevel(verbose_); +#if !HAVE_SUPERLU + if (usesuperlu == true) + { + std::cout << "WARNING: You are using AMG without SuperLU!" + << " Please consider installing SuperLU," + << " or set the usesuperlu flag to false" + << " to suppress this warning." << std::endl; + } +#endif + } + + /*! \brief set AMG parameters + + \param[in] params_ a parameter object of Type Dune::Amg::Parameters + */ + void setparams(Parameters params_) + { + params = params_; + } + + /*! \brief compute global norm of a vector + + \param[in] v the given vector + */ + typename V::ElementType norm (const V& v) const + { + return v.base().two_norm(); + } + + /*! \brief solve the given linear system + + \param[in] A the given matrix + \param[out] z the solution vector to be computed + \param[in] r right hand side + \param[in] reduction to be achieved + */ + void apply(MatrixType& A, V& z, V& r, typename V::ElementType reduction) + { + Timer watch; + MatrixType& mat=A; + typedef Dune::Amg::CoarsenCriterion<Dune::Amg::SymmetricCriterion<MatrixType, + Dune::Amg::FirstDiagonal> > Criterion; + SmootherArgs smootherArgs; + smootherArgs.iterations = 1; + smootherArgs.relaxationFactor = 1; + + Criterion criterion(params); + Operator oop(mat); + //only construct a new AMG if the matrix changes + if (reuse==false || firstapply==true){ + amg.reset(new AMG(oop, criterion, smootherArgs)); + firstapply = false; + stats.tsetup = watch.elapsed(); + stats.levels = amg->maxlevels(); + stats.directCoarseLevelSolver=amg->usesDirectCoarseLevelSolver(); + } + watch.reset(); + Dune::InverseOperatorResult stat; + + Solver<VectorType> solver(oop,*amg,reduction,maxiter,verbose); + solver.apply(BlockProcessor<GFS>::getVector(z),BlockProcessor<GFS>::getVector(r),stat); + stats.tsolve= watch.elapsed(); + res.converged = stat.converged; + res.iterations = stat.iterations; + res.elapsed = stat.elapsed; + res.reduction = stat.reduction; + res.conv_rate = stat.conv_rate; + } + + + /** + * @brief Get statistics of the AMG solver (no of levels, timings). + * @return statistis of the AMG solver. + */ + const ISTLAMGStatistics& statistics() const + { + return stats; + } + + private: + unsigned maxiter; + Parameters params; + int verbose; + bool reuse; + bool firstapply; + bool usesuperlu; + Dune::shared_ptr<AMG> amg; + ISTLAMGStatistics stats; + }; + + //! \addtogroup PDELab_seqsolvers Sequential Solvers + //! \{ + + /** + * @brief Sequential conjugate gradient solver preconditioned with AMG smoothed by SSOR + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + */ + template<class GO> + class ISTLBackend_SEQ_CG_AMG_SSOR + : public ISTLBackend_SEQ_AMG<GO, Dune::SeqSSOR, Dune::CGSolver> + { + + public: + /** + * @brief Constructor + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_SEQ_CG_AMG_SSOR(unsigned maxiter_=5000, int verbose_=1, + bool reuse_=false, bool usesuperlu_=true) + : ISTLBackend_SEQ_AMG<GO, Dune::SeqSSOR, Dune::CGSolver> + (maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + /** + * @brief Sequential BiCGStab solver preconditioned with AMG smoothed by SSOR + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + */ + template<class GO> + class ISTLBackend_SEQ_BCGS_AMG_SSOR + : public ISTLBackend_SEQ_AMG<GO, Dune::SeqSSOR, Dune::BiCGSTABSolver> + { + + public: + /** + * @brief Constructor + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_SEQ_BCGS_AMG_SSOR(unsigned maxiter_=5000, int verbose_=1, + bool reuse_=false, bool usesuperlu_=true) + : ISTLBackend_SEQ_AMG<GO, Dune::SeqSSOR, Dune::BiCGSTABSolver> + (maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + /** + * @brief Sequential BiCGSTAB solver preconditioned with AMG smoothed by SOR + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + */ + template<class GO> + class ISTLBackend_SEQ_BCGS_AMG_SOR + : public ISTLBackend_SEQ_AMG<GO, Dune::SeqSOR, Dune::BiCGSTABSolver> + { + + public: + /** + * @brief Constructor + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_SEQ_BCGS_AMG_SOR(unsigned maxiter_=5000, int verbose_=1, + bool reuse_=false, bool usesuperlu_=true) + : ISTLBackend_SEQ_AMG<GO, Dune::SeqSOR, Dune::BiCGSTABSolver> + (maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + /** + * @brief Sequential Loop solver preconditioned with AMG smoothed by SSOR + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + */ + template<class GO> + class ISTLBackend_SEQ_LS_AMG_SSOR + : public ISTLBackend_SEQ_AMG<GO, Dune::SeqSSOR, Dune::LoopSolver> + { + + public: + /** + * @brief Constructor + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_SEQ_LS_AMG_SSOR(unsigned maxiter_=5000, int verbose_=1, + bool reuse_=false, bool usesuperlu_=true) + : ISTLBackend_SEQ_AMG<GO, Dune::SeqSSOR, Dune::LoopSolver> + (maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + /** + * @brief Sequential Loop solver preconditioned with AMG smoothed by SOR + * @tparam GO The type of the grid operator + * (or the fakeGOTraits class for the old grid operator space). + */ + template<class GO> + class ISTLBackend_SEQ_LS_AMG_SOR + : public ISTLBackend_SEQ_AMG<GO, Dune::SeqSOR, Dune::LoopSolver> + { + + public: + /** + * @brief Constructor + * @param maxiter_ The maximum number of iterations allowed. + * @param verbose_ The verbosity level to use. + * @param reuse_ Set true, if the Matrix to be used is always identical + * (AMG aggregation is then only performed once). + * @param usesuperlu_ Set false, to suppress the no SuperLU warning + */ + ISTLBackend_SEQ_LS_AMG_SOR(unsigned maxiter_=5000, int verbose_=1, + bool reuse_=false, bool usesuperlu_=true) + : ISTLBackend_SEQ_AMG<GO, Dune::SeqSOR, Dune::LoopSolver> + (maxiter_, verbose_, reuse_, usesuperlu_) + {} + }; + + //! \} group Sequential Solvers + //! \} group Backend + +} // namespace Dumux + +#endif -- GitLab