From 4bcf59c2c5c8b12b13c93537abccd5c447670f4c Mon Sep 17 00:00:00 2001 From: Norihiro Watanabe <norihiro.watanabe@ufz.de> Date: Thu, 9 Jul 2015 11:09:51 +0200 Subject: [PATCH] [Mat] add LinAlg/Eigen and LinAlg/EigenLis --- MathLib/CMakeLists.txt | 10 ++ MathLib/LinAlg/ApplyKnownSolution.h | 4 + MathLib/LinAlg/Eigen/EigenLinearSolver.cpp | 145 +++++++++++++++ MathLib/LinAlg/Eigen/EigenLinearSolver.h | 80 +++++++++ MathLib/LinAlg/Eigen/EigenMatrix.h | 170 ++++++++++++++++++ MathLib/LinAlg/Eigen/EigenOption.cpp | 48 +++++ MathLib/LinAlg/Eigen/EigenOption.h | 82 +++++++++ MathLib/LinAlg/Eigen/EigenTools.cpp | 58 ++++++ MathLib/LinAlg/Eigen/EigenTools.h | 36 ++++ MathLib/LinAlg/Eigen/EigenVector.h | 114 ++++++++++++ .../LinAlg/EigenLis/EigenLisLinearSolver.cpp | 82 +++++++++ .../LinAlg/EigenLis/EigenLisLinearSolver.h | 76 ++++++++ Tests/MathLib/TestGlobalMatrixInterface.cpp | 12 ++ Tests/MathLib/TestGlobalVectorInterface.cpp | 11 ++ Tests/MathLib/TestLinearSolver.cpp | 44 +++++ 15 files changed, 972 insertions(+) create mode 100644 MathLib/LinAlg/Eigen/EigenLinearSolver.cpp create mode 100644 MathLib/LinAlg/Eigen/EigenLinearSolver.h create mode 100644 MathLib/LinAlg/Eigen/EigenMatrix.h create mode 100644 MathLib/LinAlg/Eigen/EigenOption.cpp create mode 100644 MathLib/LinAlg/Eigen/EigenOption.h create mode 100644 MathLib/LinAlg/Eigen/EigenTools.cpp create mode 100644 MathLib/LinAlg/Eigen/EigenTools.h create mode 100644 MathLib/LinAlg/Eigen/EigenVector.h create mode 100644 MathLib/LinAlg/EigenLis/EigenLisLinearSolver.cpp create mode 100644 MathLib/LinAlg/EigenLis/EigenLisLinearSolver.h diff --git a/MathLib/CMakeLists.txt b/MathLib/CMakeLists.txt index 4887c539178..09c09926eac 100644 --- a/MathLib/CMakeLists.txt +++ b/MathLib/CMakeLists.txt @@ -23,11 +23,21 @@ set(SOURCES ${SOURCES} ${SOURCES_LINALG_SOLVERS}) GET_SOURCE_FILES(SOURCES_LINALG_PRECOND LinAlg/Preconditioner) set(SOURCES ${SOURCES} ${SOURCES_LINALG_PRECOND}) +if(OGS_USE_EIGEN) + GET_SOURCE_FILES(SOURCES_LINALG_EIGEN LinAlg/Eigen) + set(SOURCES ${SOURCES} ${SOURCES_LINALG_EIGEN}) +endif() + if(OGS_USE_LIS) GET_SOURCE_FILES(SOURCES_LINALG_LIS LinAlg/Lis) set(SOURCES ${SOURCES} ${SOURCES_LINALG_LIS}) endif() +if(OGS_USE_EIGEN AND OGS_USE_LIS) + GET_SOURCE_FILES(SOURCES_LINALG_EIGENLIS LinAlg/EigenLis) + set(SOURCES ${SOURCES} ${SOURCES_LINALG_EIGENLIS}) +endif() + if(OGS_USE_PETSC) GET_SOURCE_FILES(SOURCES_LINALG_PETSC LinAlg/PETSc) set(SOURCES ${SOURCES} ${SOURCES_LINALG_PETSC}) diff --git a/MathLib/LinAlg/ApplyKnownSolution.h b/MathLib/LinAlg/ApplyKnownSolution.h index 31c99e56cc2..72c28fe3481 100644 --- a/MathLib/LinAlg/ApplyKnownSolution.h +++ b/MathLib/LinAlg/ApplyKnownSolution.h @@ -13,6 +13,10 @@ #include "MathLib/LinAlg/Dense/DenseTools.h" +#ifdef OGS_USE_EIGEN +#include "MathLib/LinAlg/Eigen/EigenTools.h" +#endif // USE_LIS + #ifdef USE_LIS #include "MathLib/LinAlg/Lis/LisTools.h" #endif // USE_LIS diff --git a/MathLib/LinAlg/Eigen/EigenLinearSolver.cpp b/MathLib/LinAlg/Eigen/EigenLinearSolver.cpp new file mode 100644 index 00000000000..8071c650e30 --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenLinearSolver.cpp @@ -0,0 +1,145 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "EigenLinearSolver.h" + +#include <logog/include/logog.hpp> +#include <unsupported/Eigen/IterativeSolvers> + +#include "EigenVector.h" +#include "EigenMatrix.h" +#include "EigenTools.h" + +namespace MathLib +{ + +using boost::property_tree::ptree; + +namespace details +{ + +template <class T_SOLVER> +class EigenDirectSolver : public EigenLinearSolver::IEigenSolver +{ +public: + EigenDirectSolver(EigenMatrix::RawMatrixType &A) : _A(A) + { + // fill A and b; + // Compute the ordering permutation vector from the structural pattern of A + _solver.analyzePattern(A); + // Compute the numerical factorization + _solver.factorize(A); + if(_solver.info()!=Eigen::Success) { + INFO("\t failed"); + return; + } + } + + virtual ~EigenDirectSolver() {} + + void solve(EigenVector::RawVectorType &b, EigenVector::RawVectorType &x, EigenOption &) override + { + //Use the factors to solve the linear system + INFO("-> solve"); + x = _solver.solve(b); + } + +private: + T_SOLVER _solver; + EigenMatrix::RawMatrixType& _A; +}; + +template <class T_SOLVER> +class EigenIterativeSolver : public EigenLinearSolver::IEigenSolver +{ +public: + EigenIterativeSolver(EigenMatrix::RawMatrixType &A) : _A(A) + { + INFO("-> initialize with the coefficient matrix"); + _solver.compute(A); + if(_solver.info()!=Eigen::Success) { + INFO("\t failed"); + return; + } + } + + virtual ~EigenIterativeSolver() {} + + void solve(EigenVector::RawVectorType &b, EigenVector::RawVectorType &x, EigenOption &opt) override + { + INFO("-> solve"); + _solver.setTolerance(opt.error_tolerance); + _solver.setMaxIterations(opt.max_iterations); + x = _solver.solveWithGuess(b, x); + if(_solver.info()!=Eigen::Success) { + INFO("\t solving failed"); + return; + } + INFO("\t iteration: %d/%ld", _solver.iterations(), opt.max_iterations); + INFO("\t residual: %e\n", _solver.error()); + } + +private: + T_SOLVER _solver; + EigenMatrix::RawMatrixType& _A; +}; + +} // details + +EigenLinearSolver::EigenLinearSolver(EigenMatrix &A, ptree const*const option) +{ + if (option) + setOption(*option); + + A.getRawMatrix().makeCompressed(); + if (_option.solver_type==EigenOption::SolverType::SparseLU) { + typedef Eigen::SparseLU<EigenMatrix::RawMatrixType, Eigen::COLAMDOrdering<int> > SolverType; + _solver = new details::EigenDirectSolver<SolverType>(A.getRawMatrix()); + } else if (_option.solver_type==EigenOption::SolverType::BiCGSTAB) { + typedef Eigen::BiCGSTAB<EigenMatrix::RawMatrixType, Eigen::DiagonalPreconditioner<double>> SolverType; + _solver = new details::EigenIterativeSolver<SolverType>(A.getRawMatrix()); + } else if (_option.solver_type==EigenOption::SolverType::CG) { + typedef Eigen::ConjugateGradient<EigenMatrix::RawMatrixType, Eigen::Lower, Eigen::DiagonalPreconditioner<double>> SolverType; + _solver = new details::EigenIterativeSolver<SolverType>(A.getRawMatrix()); + } +} + +void EigenLinearSolver::setOption(const ptree &option) +{ + boost::optional<ptree> ptSolver = option.get_child("LinearSolver"); + if (!ptSolver) + return; + + boost::optional<std::string> solver_type = ptSolver->get_optional<std::string>("solver_type"); + if (solver_type) { + _option.solver_type = _option.getSolverType(*solver_type); + } + boost::optional<std::string> precon_type = ptSolver->get_optional<std::string>("precon_type"); + if (precon_type) { + _option.precon_type = _option.getPreconType(*precon_type); + } + boost::optional<double> error_tolerance = ptSolver->get_optional<double>("error_tolerance"); + if (error_tolerance) { + _option.error_tolerance = *error_tolerance; + } + boost::optional<int> max_iteration_step = ptSolver->get_optional<int>("max_iteration_step"); + if (max_iteration_step) { + _option.max_iterations = *max_iteration_step; + } +} + +void EigenLinearSolver::solve(EigenVector &b, EigenVector &x) +{ + INFO("------------------------------------------------------------------"); + INFO("*** Eigen solver computation"); + _solver->solve(b.getRawVector(), x.getRawVector(), _option); + INFO("------------------------------------------------------------------"); +} + +} //MathLib diff --git a/MathLib/LinAlg/Eigen/EigenLinearSolver.h b/MathLib/LinAlg/Eigen/EigenLinearSolver.h new file mode 100644 index 00000000000..d536b157c9a --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenLinearSolver.h @@ -0,0 +1,80 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef EIGENLINEARSOLVER_H_ +#define EIGENLINEARSOLVER_H_ + +#include <vector> + +#include <boost/any.hpp> +#include <boost/property_tree/ptree.hpp> + +#include "EigenVector.h" +#include "EigenOption.h" + +namespace MathLib +{ + +class EigenMatrix; + +/** + */ +class EigenLinearSolver +{ +public: + EigenLinearSolver(EigenMatrix &A, boost::property_tree::ptree const*const option = nullptr); + + virtual ~EigenLinearSolver() + { + delete _solver; + } + + /** + * configure linear solvers + * @param option + */ + void setOption(const boost::property_tree::ptree &option); + + /** + * configure linear solvers + * @param option + */ + void setOption(const EigenOption &option) { _option = option; } + + /** + * get linear solver options + * @return + */ + EigenOption &getOption() { return _option; } + + /** + * solve a given linear equations + * + * @param b RHS vector + * @param x Solution vector + */ + void solve(EigenVector &b, EigenVector &x); + +protected: + class IEigenSolver + { + public: + virtual ~IEigenSolver() {} + /// execute a linear solver + virtual void solve(EigenVector::RawVectorType &b, EigenVector::RawVectorType &x, EigenOption &) = 0; + }; + + EigenOption _option; + IEigenSolver* _solver; +}; + +} // MathLib + +#endif //EIGENLINEARSOLVER_H_ + diff --git a/MathLib/LinAlg/Eigen/EigenMatrix.h b/MathLib/LinAlg/Eigen/EigenMatrix.h new file mode 100644 index 00000000000..fb254a58e0f --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenMatrix.h @@ -0,0 +1,170 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef EIGENMATRIX_H_ +#define EIGENMATRIX_H_ + +#include <cassert> +#include <fstream> +#include <iosfwd> +#include <string> + +#include <Eigen/Sparse> + +#include "MathLib/LinAlg/RowColumnIndices.h" +#include "EigenVector.h" + +namespace MathLib +{ + +/** + * Global matrix based on Eigen sparse matrix + */ +class EigenMatrix +{ +public: + typedef Eigen::SparseMatrix<double, Eigen::RowMajor> RawMatrixType; + + /** + * constructor + * @param n_rows the number of rows (that is equal to the number of columns) + */ + explicit EigenMatrix(std::size_t n) :_mat(n, n) {} + + virtual ~EigenMatrix() {} + + /// return the number of rows + virtual std::size_t getNRows() const { return _mat.rows(); } + + /// return the number of columns + virtual std::size_t getNCols() const { return _mat.cols(); } + + /// return a start index of the active data range + virtual std::size_t getRangeBegin() const { return 0; } + + /// return an end index of the active data range + virtual std::size_t getRangeEnd() const { return getNRows(); } + + /// Reset data entries to zero. + virtual void setZero() + { + _mat.setZero(); + } + + /// set entry + int setValue(std::size_t row, std::size_t col, double val) + { + _mat.coeffRef(row, col) = val; + return 0; + } + + /// add value + int add(std::size_t row, std::size_t col, double val) + { + assert(row < getNRows() && col < getNCols()); + _mat.coeffRef(row, col) += val; + return 0; + } + + /// Add sub-matrix at positions \c row_pos and same column positions as the + /// given row positions. + template<class T_DENSE_MATRIX> + void add(std::vector<std::size_t> const& row_pos, + const T_DENSE_MATRIX &sub_matrix, + double fkt = 1.0) + { + this->add(row_pos, row_pos, sub_matrix, fkt); + } + + /// Add sub-matrix at positions given by \c indices. + template<class T_DENSE_MATRIX> + void add(RowColumnIndices<std::size_t> const& indices, + const T_DENSE_MATRIX &sub_matrix, + double fkt = 1.0) + { + this->add(indices.rows, indices.columns, sub_matrix, fkt); + } + + /// + template <class T_DENSE_MATRIX> + void add(std::vector<std::size_t> const& row_pos, + std::vector<std::size_t> const& col_pos, const T_DENSE_MATRIX &sub_matrix, + double fkt = 1.0); + + /// get value + double get(std::size_t row, std::size_t col) + { + assert(row < getNRows() && col < getNCols()); + return _mat.coeff(row, col); + } + + /// get value + double operator() (std::size_t row, std::size_t col) const + { + return _mat.coeff(row, col); + } + + /// get a maximum value in diagonal entries + virtual double getMaxDiagCoeff() {return 1;} + + /// y = mat * x + virtual void multiply(const EigenVector &x, EigenVector &y) const + { + y.getRawVector() = _mat * x.getRawVector(); + } + + /// return if this matrix is already assembled or not + bool isAssembled() const { return true; } + + /// printout this matrix for debugging + void write(const std::string &filename) const + { + std::ofstream of(filename); + if (of) + write(of); + } + + /// printout this matrix for debugging + void write(std::ostream &os) const + { + for (int k=0; k<_mat.outerSize(); ++k) + for (Eigen::SparseMatrix<double>::InnerIterator it(_mat,k); it; ++it) + os << it.row() << " " << it.col() << ": " << it.value() << "\n"; + os << std::endl; + } + + RawMatrixType& getRawMatrix() { return _mat; } + const RawMatrixType& getRawMatrix() const { return _mat; } + +protected: + RawMatrixType _mat; +}; + + +template<class T_DENSE_MATRIX> +void +EigenMatrix::add(std::vector<std::size_t> const& row_pos, std::vector<std::size_t> const& col_pos, + const T_DENSE_MATRIX &sub_matrix, double fkt) +{ + const std::size_t n_rows = row_pos.size(); + const std::size_t n_cols = col_pos.size(); + for (std::size_t i = 0; i < n_rows; i++) { + const std::size_t row = row_pos[i]; + for (std::size_t j = 0; j < n_cols; j++) { + const std::size_t col = col_pos[j]; + add(row, col, fkt * sub_matrix(i, j)); + } + } +}; + + +} // end namespace MathLib + +#endif + diff --git a/MathLib/LinAlg/Eigen/EigenOption.cpp b/MathLib/LinAlg/Eigen/EigenOption.cpp new file mode 100644 index 00000000000..03533f688a3 --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenOption.cpp @@ -0,0 +1,48 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "EigenOption.h" + +namespace MathLib +{ + +EigenOption::EigenOption() +{ + solver_type = SolverType::SparseLU; + precon_type = PreconType::NONE; + max_iterations = 1e6; + error_tolerance = 1.e-16; +} + +EigenOption::SolverType EigenOption::getSolverType(const std::string &solver_name) +{ +#define RETURN_SOLVER_ENUM_IF_SAME_STRING(str, TypeName) \ + if (#TypeName==str) return SolverType::TypeName; + + RETURN_SOLVER_ENUM_IF_SAME_STRING(solver_name, CG); + RETURN_SOLVER_ENUM_IF_SAME_STRING(solver_name, BiCGSTAB); + RETURN_SOLVER_ENUM_IF_SAME_STRING(solver_name, SparseLU); + + return SolverType::INVALID; +#undef RETURN_SOLVER_ENUM_IF_SAME_STRING +} + +EigenOption::PreconType EigenOption::getPreconType(const std::string &precon_name) +{ +#define RETURN_PRECOM_ENUM_IF_SAME_STRING(str, TypeName) \ + if (#TypeName==str) return PreconType::TypeName; + + RETURN_PRECOM_ENUM_IF_SAME_STRING(precon_name, NONE); + RETURN_PRECOM_ENUM_IF_SAME_STRING(precon_name, DIAGONAL); + + return PreconType::NONE; +#undef RETURN_PRECOM_ENUM_IF_SAME_STRING +} + +} //MathLib diff --git a/MathLib/LinAlg/Eigen/EigenOption.h b/MathLib/LinAlg/Eigen/EigenOption.h new file mode 100644 index 00000000000..ba911c49a9d --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenOption.h @@ -0,0 +1,82 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef EIGENOPTION_H_ +#define EIGENOPTION_H_ + +#include <string> + +namespace MathLib +{ + +/** + * \brief Option for Eigen sparse solver + */ +struct EigenOption +{ + /// Solver type + enum class SolverType : int + { + INVALID, + CG, + BiCGSTAB, + SparseLU + }; + + /// Preconditioner type + enum class PreconType : int + { + NONE, + DIAGONAL + }; + + /// Linear solver type + SolverType solver_type; + /// Preconditioner type + PreconType precon_type; + /// Maximum iteration count + long max_iterations; + /// Error tolerance + double error_tolerance; + + /** + * Constructor + * + * Default options are CG, no preconditioner, iteration count 500 and + * tolerance 1e-10. Default matrix storage type is CRS. + */ + EigenOption(); + + /// Destructor + ~EigenOption() {} + + /** + * return a linear solver type from the solver name + * + * @param solver_name + * @return a linear solver type + * If there is no solver type matched with the given name, INVALID + * is returned. + */ + static SolverType getSolverType(const std::string &solver_name); + + /** + * return a preconditioner type from the name + * + * @param precon_name + * @return a preconditioner type + * If there is no preconditioner type matched with the given name, NONE + * is returned. + */ + static PreconType getPreconType(const std::string &precon_name); + +}; + +} +#endif //LIS_OPTION_H_ diff --git a/MathLib/LinAlg/Eigen/EigenTools.cpp b/MathLib/LinAlg/Eigen/EigenTools.cpp new file mode 100644 index 00000000000..b820e768c84 --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenTools.cpp @@ -0,0 +1,58 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "EigenTools.h" + +#include <logog/include/logog.hpp> + +#include "EigenMatrix.h" +#include "EigenVector.h" + +namespace MathLib +{ + +void applyKnownSolution(EigenMatrix &A_, EigenVector &b_, const std::vector<std::size_t> &vec_knownX_id, + const std::vector<double> &vec_knownX_x, double /*penalty_scaling*/) +{ + typedef EigenMatrix::RawMatrixType SpMat; + auto &A = A_.getRawMatrix(); + auto &b = b_.getRawVector(); + const size_t n_rows = A.rows(); + for (std::size_t ix=0; ix<vec_knownX_id.size(); ix++) + { + int row_id = vec_knownX_id[ix]; + auto x = vec_knownX_x[ix]; + //A(k, j) = 0. + for (SpMat::InnerIterator it(A,row_id); it; ++it) + it.valueRef() = .0; + //b_i -= A(i,k)*val, i!=k + for (size_t i=0; i<n_rows; i++) + for (SpMat::InnerIterator it(A,i); it; ++it) + { + if (it.col()!=row_id) continue; + b[i] -= it.value()*x; + } + //b_k = val + b[row_id] = x; + //A(i, k) = 0., i!=k + for (size_t i=0; i<n_rows; i++) + for (SpMat::InnerIterator it(A,i); it; ++it) + { + if (it.col()!=row_id) continue; + it.valueRef() = 0.0; + } + //A(k, k) = 1.0 + A.coeffRef(row_id, row_id) = 1.0; //=x + } +} + +} // MathLib + + + diff --git a/MathLib/LinAlg/Eigen/EigenTools.h b/MathLib/LinAlg/Eigen/EigenTools.h new file mode 100644 index 00000000000..95995e0c259 --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenTools.h @@ -0,0 +1,36 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef EIGENTOOLS_H_ +#define EIGENTOOLS_H_ + +#include <vector> + +namespace MathLib +{ +class EigenMatrix; +class EigenVector; + +/** + * apply known solutions to a system of linear equations + * + * @param A Coefficient matrix + * @param b RHS vector + * @param _vec_knownX_id a vector of known solution entry IDs + * @param _vec_knownX_x a vector of known solutions + * @param penalty_scaling value for scaling some matrix and right hand side + * entries to enforce some conditions + */ +void applyKnownSolution(EigenMatrix &A, EigenVector &b, const std::vector<std::size_t> &_vec_knownX_id, + const std::vector<double> &_vec_knownX_x, double penalty_scaling = 1e+10); + +} // MathLib + +#endif //EIGENTOOLS_H_ + diff --git a/MathLib/LinAlg/Eigen/EigenVector.h b/MathLib/LinAlg/Eigen/EigenVector.h new file mode 100644 index 00000000000..edc93f4af2e --- /dev/null +++ b/MathLib/LinAlg/Eigen/EigenVector.h @@ -0,0 +1,114 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef EIGENVECTOR_H_ +#define EIGENVECTOR_H_ + +#include <string> +#include <vector> +#include <fstream> + +#include <Eigen/Eigen> + +namespace MathLib +{ + +/** + * Global vector based on Eigen vector + */ +class EigenVector +{ +public: + typedef Eigen::VectorXd RawVectorType; + + /** + * Constructor for initialization of the number of rows + * @param length number of rows + */ + explicit EigenVector(std::size_t length) : _vec(length) {} + + /// copy constructor + EigenVector(EigenVector const &src) : _vec(src._vec) {} + + /** + * + */ + virtual ~EigenVector() {} + + /// return a vector length + std::size_t size() const { return _vec.size(); } + + /// return a start index of the active data range + std::size_t getRangeBegin() const { return 0;} + + /// return an end index of the active data range + std::size_t getRangeEnd() const { return this->size(); } + + /// set all values in this vector + EigenVector& operator= (double v) { _vec.setConstant(v); return *this; } + + /// set all values in this vector + EigenVector& operator*= (double v) { _vec *= v; return *this; } + + /// access entry + double operator[] (std::size_t rowId) const { return get(rowId); } + + /// get entry + double get(std::size_t rowId) const + { + return _vec[rowId]; + } + + /// set entry + void set(std::size_t rowId, double v) + { + _vec[rowId] = v; + } + + /// add entry + void add(std::size_t rowId, double v) + { + _vec[rowId] += v; + } + + /// add entries + template<class T_SUBVEC> + void add(const std::vector<std::size_t> &pos, const T_SUBVEC &sub_vec) + { + for (std::size_t i=0; i<pos.size(); ++i) { + this->add(pos[i], sub_vec[i]); + } + } + + /// printout this equation for debugging + void write (const std::string &filename) const { std::ofstream os(filename); os << _vec; } + + /// return a raw Lis vector object + RawVectorType& getRawVector() {return _vec; } + + /// return a raw Lis vector object + const RawVectorType& getRawVector() const {return _vec; } + + /// vector operation: set data + EigenVector& operator= (const EigenVector &src) { _vec = static_cast<const EigenVector&>(src)._vec; return *this; } + + /// vector operation: add + void operator+= (const EigenVector& v) { _vec += static_cast<const EigenVector&>(v)._vec; } + + /// vector operation: subtract + void operator-= (const EigenVector& v) { _vec -= static_cast<const EigenVector&>(v)._vec; } + +private: + RawVectorType _vec; +}; + +} // MathLib + +#endif //EIGENVECTOR_H_ + diff --git a/MathLib/LinAlg/EigenLis/EigenLisLinearSolver.cpp b/MathLib/LinAlg/EigenLis/EigenLisLinearSolver.cpp new file mode 100644 index 00000000000..b2254372238 --- /dev/null +++ b/MathLib/LinAlg/EigenLis/EigenLisLinearSolver.cpp @@ -0,0 +1,82 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "EigenLisLinearSolver.h" + +#ifdef _OPENMP +#include <omp.h> +#endif +#include <logog/include/logog.hpp> + +#include "MathLib/LinAlg/Eigen/EigenMatrix.h" +#include "MathLib/LinAlg/Eigen/EigenVector.h" +#include "MathLib/LinAlg/Lis/LisMatrix.h" +#include "MathLib/LinAlg/Lis/LisVector.h" +#include "MathLib/LinAlg/Lis/LisLinearSolver.h" + +namespace MathLib +{ + +using boost::property_tree::ptree; + +EigenLisLinearSolver::EigenLisLinearSolver(EigenMatrix &A, ptree const*const option) +: _A(A) +{ + if (option) + setOption(*option); +} + +void EigenLisLinearSolver::setOption(const ptree &option) +{ + boost::optional<ptree> ptSolver = option.get_child("LinearSolver"); + if (!ptSolver) + return; + + boost::optional<std::string> solver_type = ptSolver->get_optional<std::string>("solver_type"); + if (solver_type) { + _option.solver_type = _option.getSolverType(*solver_type); + } + boost::optional<std::string> precon_type = ptSolver->get_optional<std::string>("precon_type"); + if (precon_type) { + _option.precon_type = _option.getPreconType(*precon_type); + } + boost::optional<double> error_tolerance = ptSolver->get_optional<double>("error_tolerance"); + if (error_tolerance) { + _option.error_tolerance = *error_tolerance; + } + boost::optional<int> max_iteration_step = ptSolver->get_optional<int>("max_iteration_step"); + if (max_iteration_step) { + _option.max_iterations = *max_iteration_step; + } +} + +void EigenLisLinearSolver::solve(EigenVector &b_, EigenVector &x_) +{ + auto &A = _A.getRawMatrix(); + auto &b = b_.getRawVector(); + auto &x = x_.getRawVector(); + + A.makeCompressed(); + int nnz = A.nonZeros(); + int* ptr = A.outerIndexPtr(); + int* col = A.innerIndexPtr(); + double* data = A.valuePtr(); + LisMatrix lisA(_A.getNRows(), nnz, ptr, col, data); + LisVector lisb(b.rows(), b.data()); + LisVector lisx(x.rows(), x.data()); + + LisLinearSolver lissol(lisA); + lissol.setOption(_option); + lissol.solve(lisb, lisx); + + for (std::size_t i=0; i<lisx.size(); i++) + x[i] = lisx[i]; +} + +} //MathLib diff --git a/MathLib/LinAlg/EigenLis/EigenLisLinearSolver.h b/MathLib/LinAlg/EigenLis/EigenLisLinearSolver.h new file mode 100644 index 00000000000..796dd8b44bc --- /dev/null +++ b/MathLib/LinAlg/EigenLis/EigenLisLinearSolver.h @@ -0,0 +1,76 @@ +/** + * \copyright + * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef EIGENLISLINEARSOLVER_H_ +#define EIGENLISLINEARSOLVER_H_ + +#include <vector> + +#include <boost/property_tree/ptree.hpp> +#include <lis.h> + +#include "MathLib/LinAlg/Lis/LisOption.h" + +namespace MathLib +{ +class EigenVector; +class EigenMatrix; + +/** + * Linear solver using Lis library with Eigen matrix and vector objects + */ +class EigenLisLinearSolver +{ +public: + /** + * Constructor + * @param A Coefficient matrix object + * @param option A pointer to a linear solver option. In case you omit + * this argument, default settings follow those of + * LisOption struct. + */ + EigenLisLinearSolver(EigenMatrix &A, boost::property_tree::ptree const*const option = nullptr); + + virtual ~EigenLisLinearSolver() {} + + /** + * configure linear solvers + * @param option + */ + void setOption(const boost::property_tree::ptree &option); + + /** + * configure linear solvers + * @param option + */ + void setOption(const LisOption &option) { _option = option; } + + /** + * get linear solver options + * @return + */ + LisOption &getOption() { return _option; } + + /** + * solve a given linear equations + * + * @param b RHS vector + * @param x Solution vector + */ + void solve(EigenVector &b, EigenVector &x); + +private: + EigenMatrix& _A; + LisOption _option; +}; + +} // MathLib + +#endif //EIGENLISLINEARSOLVER_H_ + diff --git a/Tests/MathLib/TestGlobalMatrixInterface.cpp b/Tests/MathLib/TestGlobalMatrixInterface.cpp index d9017896b55..430704887e4 100644 --- a/Tests/MathLib/TestGlobalMatrixInterface.cpp +++ b/Tests/MathLib/TestGlobalMatrixInterface.cpp @@ -19,6 +19,10 @@ #include "MathLib/LinAlg/Dense/GlobalDenseMatrix.h" #include "MathLib/LinAlg/FinalizeMatrixAssembly.h" +#ifdef OGS_USE_EIGEN +#include "MathLib/LinAlg/Eigen/EigenMatrix.h" +#endif + #ifdef USE_LIS #include "MathLib/LinAlg/Lis/LisMatrix.h" #endif @@ -169,6 +173,14 @@ TEST(Math, CheckInterface_GlobalDenseMatrix) checkGlobalMatrixInterface(m); } +#ifdef OGS_USE_EIGEN +TEST(Math, CheckInterface_EigenMatrix) +{ + MathLib::EigenMatrix m(10); + checkGlobalMatrixInterface(m); +} +#endif + #ifdef USE_LIS TEST(Math, CheckInterface_LisMatrix) { diff --git a/Tests/MathLib/TestGlobalVectorInterface.cpp b/Tests/MathLib/TestGlobalVectorInterface.cpp index 3ad962468ff..caa06479069 100644 --- a/Tests/MathLib/TestGlobalVectorInterface.cpp +++ b/Tests/MathLib/TestGlobalVectorInterface.cpp @@ -19,6 +19,10 @@ #include "MathLib/LinAlg/Dense/DenseVector.h" #include "MathLib/LinAlg/FinalizeVectorAssembly.h" +#ifdef OGS_USE_EIGEN +#include "MathLib/LinAlg/Eigen/EigenVector.h" +#endif + #ifdef USE_LIS #include "MathLib/LinAlg/Lis/LisVector.h" #endif @@ -195,6 +199,13 @@ TEST(Math, CheckInterface_DenseVector) checkGlobalVectorInterface<MathLib::DenseVector<double> >(); } +#ifdef OGS_USE_EIGEN +TEST(Math, CheckInterface_EigenVector) +{ + checkGlobalVectorInterface<MathLib::EigenVector >(); +} +#endif + #ifdef USE_LIS TEST(Math, CheckInterface_LisVector) { diff --git a/Tests/MathLib/TestLinearSolver.cpp b/Tests/MathLib/TestLinearSolver.cpp index 7c5415b3df0..95d9569ec0a 100644 --- a/Tests/MathLib/TestLinearSolver.cpp +++ b/Tests/MathLib/TestLinearSolver.cpp @@ -23,6 +23,16 @@ #include "MathLib/LinAlg/ApplyKnownSolution.h" #include "MathLib/LinAlg/Solvers/GaussAlgorithm.h" +#ifdef OGS_USE_EIGEN +#include "MathLib/LinAlg/Eigen/EigenMatrix.h" +#include "MathLib/LinAlg/Eigen/EigenVector.h" +#include "MathLib/LinAlg/Eigen/EigenLinearSolver.h" +#endif + +#if defined(OGS_USE_EIGEN) && defined(USE_LIS) +#include "MathLib/LinAlg/EigenLis/EigenLisLinearSolver.h" +#endif + #ifdef USE_LIS #include "MathLib/LinAlg/Lis/LisLinearSolver.h" #endif @@ -201,6 +211,40 @@ TEST(MathLib, CheckInterface_GaussAlgorithm) checkLinearSolverInterface<MathLib::GlobalDenseMatrix<double>, MathLib::DenseVector<double>, LinearSolverType>(A, t_root); } +#ifdef OGS_USE_EIGEN +TEST(Math, CheckInterface_Eigen) +{ + // set solver options using Boost property tree + boost::property_tree::ptree t_root; + boost::property_tree::ptree t_solver; + t_solver.put("solver_type", "CG"); + t_solver.put("precon_type", "NONE"); + t_solver.put("error_tolerance", 1e-15); + t_solver.put("max_iteration_step", 1000); + t_root.put_child("LinearSolver", t_solver); + + MathLib::EigenMatrix A(Example1::dim_eqs); + checkLinearSolverInterface<MathLib::EigenMatrix, MathLib::EigenVector, MathLib::EigenLinearSolver>(A, t_root); +} +#endif + +#if defined(OGS_USE_EIGEN) && defined(USE_LIS) +TEST(Math, CheckInterface_EigenLis) +{ + // set solver options using Boost property tree + boost::property_tree::ptree t_root; + boost::property_tree::ptree t_solver; + t_solver.put("solver_type", "CG"); + t_solver.put("precon_type", "NONE"); + t_solver.put("error_tolerance", 1e-15); + t_solver.put("max_iteration_step", 1000); + t_root.put_child("LinearSolver", t_solver); + + MathLib::EigenMatrix A(Example1::dim_eqs); + checkLinearSolverInterface<MathLib::EigenMatrix, MathLib::EigenVector, MathLib::EigenLisLinearSolver>(A, t_root); +} +#endif + #ifdef USE_LIS TEST(Math, CheckInterface_Lis) { -- GitLab