From 28e812ee2c5eb088c0514ed9b85754fefb6ce1bb Mon Sep 17 00:00:00 2001 From: Marco Agnese <ma2413@imperial.ac.uk> Date: Mon, 17 Nov 2014 16:30:39 +0000 Subject: [PATCH] [suitesparse] LDL wrapper derived from Dune::InverseOperator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christoph Grüninger <gruenich@dune-project.org> --- dune/istl/ldl.hh | 216 +++++++++++++++++++++++++++++++---------------- 1 file changed, 143 insertions(+), 73 deletions(-) diff --git a/dune/istl/ldl.hh b/dune/istl/ldl.hh index 6126d6cc7..03945653d 100644 --- a/dune/istl/ldl.hh +++ b/dune/istl/ldl.hh @@ -1,9 +1,9 @@ // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: -#ifndef DUNE_LDL_HH -#define DUNE_LDL_HH +#ifndef DUNE_ISTL_LDL_HH +#define DUNE_ISTL_LDL_HH -#if HAVE_LDL +#if HAVE_LDL || defined DOXYGEN #include <iostream> #include<complex> @@ -36,7 +36,7 @@ namespace Dune { * @brief Class for using LDL with ISTL matrices. */ - // forward declaration + // forward declarations template<class M, class T, class TM, class TD, class TA> class SeqOverlappingSchwarz; @@ -44,93 +44,140 @@ namespace Dune { struct SeqOverlappingSchwarzAssemblerHelper; /** - * @brief The %LDL direct sparse solver for matrices of type Matrix - * Details on LDL can be found on http://www.cise.ufl.edu/research/sparse/ldl/ - * \note This will only work if dune-istl has been configured to use LDL + * @brief Use the %LDL package to directly solve linear systems -- empty default class + * @tparam Matrix the matrix type defining the system + * Details on UMFPack can be found on + * http://www.cise.ufl.edu/research/sparse/ldl/ */ - template<typename MT> + template<class Matrix> class LDL + {}; + + /** + * @brief The %LDL direct sparse solver for matrices of type BCRSMatrix + * + * Specialization for the Dune::BCRSMatrix. %LDL will always go double + * precision. + * + * \tparam T Number type. Only double is supported + * \tparam A STL-compatible allocator type + * \tparam n Number of rows in a matrix block + * \tparam m Number of columns in a matrix block + * + * \note This will only work if dune-istl has been configured to use LDL + */ + template<typename T, typename A, int n, int m> + class LDL<BCRSMatrix<FieldMatrix<T,n,m>,A > > + : public InverseOperator<BlockVector<FieldVector<T,m>, typename A::template rebind<FieldVector<T,m> >::other>, + BlockVector<FieldVector<T,n>, typename A::template rebind<FieldVector<T,n> >::other> > { public: /** @brief The matrix type. */ - typedef MT Matrix; - - /** @brief The column-compressed matrix type.*/ - typedef ColCompMatrix<Matrix> LDLMatrix; + typedef Dune::BCRSMatrix<FieldMatrix<T,n,m>,A> Matrix; + typedef Dune::BCRSMatrix<FieldMatrix<T,n,m>,A> matrix_type; + /** @brief The corresponding SuperLU Matrix type. */ + typedef Dune::ColCompMatrix<Matrix> LDLMatrix; + /** @brief Type of an associated initializer class. */ + typedef ColCompMatrixInitializer<BCRSMatrix<FieldMatrix<T,n,m>,A> > MatrixInitializer; + /** @brief The type of the domain of the solver. */ + typedef Dune::BlockVector<FieldVector<T,m>, typename A::template rebind<FieldVector<T,m> >::other> domain_type; + /** @brief The type of the range of the solver. */ + typedef Dune::BlockVector<FieldVector<T,n>, typename A::template rebind<FieldVector<T,n> >::other> range_type; /** - * @brief Construct a solver object. - * @param mat the matrix to solve for + * @brief Construct a solver object from a BCRSMatrix. + * + * This computes the matrix decomposition, and may take a long time + * (and use a lot of memory). + * + * @param matrix the matrix to solve for * @param verbose 0 or 1 set the verbosity level, defaults to 0 */ - LDL(const Matrix& mat, int verbose=0) : isloaded_(false), verbose_(verbose) + LDL(const Matrix& matrix, int verbose=0) : matrixIsLoaded_(false), verbose_(verbose) { - setMatrix(mat); + //check whether T is a supported type + static_assert(std::is_same<T,double>::value,"Unsupported Type in LDL (only double supported)"); + setMatrix(matrix); } /** * @brief Constructor for compatibility with SuperLU standard constructor - * @param mat the matrix to solve for + * + * This computes the matrix decomposition, and may take a long time + * (and use a lot of memory). + * + * @param matrix the matrix to solve for * @param verbose 0 or 1 set the verbosity level, defaults to 0 */ - LDL(const Matrix& mat, int verbose, bool) : isloaded_(false), verbose_(verbose) + LDL(const Matrix& matrix, int verbose, bool) : matrixIsLoaded_(false), verbose_(verbose) { - setMatrix(mat); + //check whether T is a supported type + static_assert(std::is_same<T,double>::value,"Unsupported Type in LDL (only double supported)"); + setMatrix(matrix); } /** @brief Default constructor. */ - LDL() : isloaded_(false), verbose_(0) + LDL() : matrixIsLoaded_(false), verbose_(0) {} /** @brief Default constructor. */ - ~LDL() + virtual ~LDL() { - if ((mat_.N() + mat_.M() > 0) || isloaded_) + if ((ldlMatrix_.N() + ldlMatrix_.M() > 0) || matrixIsLoaded_) free(); } - /** @brief Solve the system Ax=b. */ - template<class DT,class RT> - void apply(DT& x, const RT& b, InverseOperatorResult& res) + /** \copydoc InverseOperator::apply(X&, Y&, InverseOperatorResult&) */ + virtual void apply(domain_type& x, range_type& b, InverseOperatorResult& res) { - const int dimMat(mat_.N()); - ldl_perm (dimMat, Y_, reinterpret_cast<double*>(&b[0]), P_); + const int dimMat(ldlMatrix_.N()); + ldl_perm(dimMat, Y_, reinterpret_cast<double*>(&b[0]), P_); ldl_lsolve(dimMat, Y_, Lp_, Li_, Lx_); ldl_dsolve(dimMat, Y_, D_); ldl_ltsolve(dimMat, Y_, Lp_, Li_, Lx_); - ldl_permt (dimMat, reinterpret_cast<double*>(&x[0]), Y_, P_); + ldl_permt(dimMat, reinterpret_cast<double*>(&x[0]), Y_, P_); // this is a direct solver res.iterations = 1; res.converged = true; } - /** @brief Solve the system Ax=b. */ - template<class DT,class RT> - inline void apply(DT& x, const RT& b, double reduction, InverseOperatorResult& res) + /** \copydoc InverseOperator::apply(X&,Y&,double,InverseOperatorResult&) */ + virtual void apply(domain_type& x, range_type& b, double reduction, InverseOperatorResult& res) { DUNE_UNUSED_PARAMETER(reduction); apply(x,b,res); } + /** + * @brief Additional apply method with c-arrays in analogy to superlu. + * @param x solution array + * @param b rhs array + */ + void apply(T* x, T* b) + { + const int dimMat(ldlMatrix_.N()); + ldl_perm(dimMat, Y_, b, P_); + ldl_lsolve(dimMat, Y_, Lp_, Li_, Lx_); + ldl_dsolve(dimMat, Y_, D_); + ldl_ltsolve(dimMat, Y_, Lp_, Li_, Lx_); + ldl_permt(dimMat, x, Y_, P_); + } + /** @brief Initialize data from given matrix. */ - void setMatrix(const Matrix& mat) + void setMatrix(const Matrix& matrix) { - if ((mat_.N() + mat_.M() > 0) || isloaded_) + if ((ldlMatrix_.N() + ldlMatrix_.M() > 0) || matrixIsLoaded_) free(); - mat_ = mat; - - // set correct dimension for additional vectors (only those before symbolic) - const int dimMat(mat_.N()); - D_ = new double [dimMat]; - Y_ = new double [dimMat]; - Lp_ = new int [dimMat + 1]; - Parent_ = new int [dimMat]; - Lnz_ = new int [dimMat]; - Flag_ = new int [dimMat]; - Pattern_ = new int [dimMat]; - P_ = new int [dimMat]; - Pinv_ = new int [dimMat]; + ldlMatrix_ = matrix; + decompose(); + } + template<class S> + void setSubMatrix(const Matrix& matrix, const S& rowIndexSet) + { + if ((ldlMatrix_.N() + ldlMatrix_.M() > 0) || matrixIsLoaded_) + free(); + ldlMatrix_.setMatrix(matrix,rowIndexSet); decompose(); } @@ -143,6 +190,15 @@ namespace Dune { verbose_=v; } + /** + * @brief Return the column compress matrix. + * @warning It is up to the user to keep consistency. + */ + inline LDLMatrix& getInternalMatrix() + { + return ldlMatrix_; + } + /** * @brief Free allocated space. * @warning Later calling apply will result in an error. @@ -152,16 +208,12 @@ namespace Dune { delete [] D_; delete [] Y_; delete [] Lp_; - delete [] Parent_; - delete [] Lnz_; - delete [] Flag_; - delete [] Pattern_; delete [] Lx_; delete [] Li_; delete [] P_; delete [] Pinv_; - mat_.free(); - isloaded_ = false; + ldlMatrix_.free(); + matrixIsLoaded_ = false; } /** @brief Get method name. */ @@ -172,36 +224,36 @@ namespace Dune { /** * @brief Get factorization diagonal matrix D. - * @warning It is up to the user to preserve consistency when modifyng it. + * @warning It is up to the user to preserve consistency. */ - inline double* getD(void) + inline double* getD() { return D_; } /** * @brief Get factorization Lp. - * @warning It is up to the user to preserve consistency when modifyng it. + * @warning It is up to the user to preserve consistency. */ - inline int* getLp(void) + inline int* getLp() { return Lp_; } /** * @brief Get factorization Li. - * @warning It is up to the user to preserve consistency when modifyng it. + * @warning It is up to the user to preserve consistency. */ - inline int* getLi(void) + inline int* getLi() { return Li_; } /** * @brief Get factorization Lx. - * @warning It is up to the user to preserve consistency when modifyng it. + * @warning It is up to the user to preserve consistency. */ - inline double* getLx(void) + inline double* getLx() { return Lx_; } @@ -215,26 +267,43 @@ namespace Dune { /** @brief Computes the LDL decomposition. */ void decompose() { - const int dimMat(mat_.N()); + // allocate vectors + const int dimMat(ldlMatrix_.N()); + D_ = new double [dimMat]; + Y_ = new double [dimMat]; + Lp_ = new int [dimMat + 1]; + Parent_ = new int [dimMat]; + Lnz_ = new int [dimMat]; + Flag_ = new int [dimMat]; + Pattern_ = new int [dimMat]; + P_ = new int [dimMat]; + Pinv_ = new int [dimMat]; + double Info [AMD_INFO]; - if (amd_order (dimMat, mat_.getColStart(), mat_.getRowIndex(), P_, (double *) NULL, Info) < AMD_OK) + if(amd_order (dimMat, ldlMatrix_.getColStart(), ldlMatrix_.getRowIndex(), P_, (double *) NULL, Info) < AMD_OK) std::cout<<"WARNING: call to AMD failed."<<std::endl; if(verbose_ > 0) amd_info (Info); // compute the symbolic factorisation - ldl_symbolic(dimMat, mat_.getColStart(), mat_.getRowIndex(), Lp_, Parent_, Lnz_, Flag_, P_, Pinv_); + ldl_symbolic(dimMat, ldlMatrix_.getColStart(), ldlMatrix_.getRowIndex(), Lp_, Parent_, Lnz_, Flag_, P_, Pinv_); // initialise those entries of additionalVectors_ whose dimension is known only now Lx_ = new double [Lp_[dimMat]]; Li_ = new int [Lp_[dimMat]]; // compute the numeric factorisation - const int rank(ldl_numeric(dimMat, mat_.getColStart(), mat_.getRowIndex(), mat_.getValues(), + const int rank(ldl_numeric(dimMat, ldlMatrix_.getColStart(), ldlMatrix_.getRowIndex(), ldlMatrix_.getValues(), Lp_, Parent_, Lnz_, Li_, Lx_, D_, Y_, Pattern_, Flag_, P_, Pinv_)); + // free temporary vectors + delete [] Flag_; + delete [] Pattern_; + delete [] Parent_; + delete [] Lnz_; + if(rank!=dimMat) std::cout<<"WARNING: matrix is singular."<<std::endl; } - LDLMatrix mat_; - bool isloaded_; + LDLMatrix ldlMatrix_; + bool matrixIsLoaded_; int verbose_; int* Lp_; int* Parent_; @@ -249,18 +318,19 @@ namespace Dune { int* Li_; }; - template<typename MT> - struct IsDirectSolver<LDL<MT> > + template<typename T, typename A, int n, int m> + struct IsDirectSolver<LDL<BCRSMatrix<FieldMatrix<T,n,m>,A> > > { - enum {value=true}; + enum {value = true}; }; - template<typename MT> - struct StoresColumnCompressed<LDL<MT> > + template<typename T, typename A, int n, int m> + struct StoresColumnCompressed<LDL<BCRSMatrix<FieldMatrix<T,n,m>,A> > > { - enum {value=true}; + enum {value = true}; }; + } #endif //HAVE_LDL -#endif //DUNE_LDL_HH +#endif //DUNE_ISTL_LDL_HH -- GitLab