.. _program_listing_file_SPlisHSPlasH_Utilities_MatrixFreeSolver.h: Program Listing for File MatrixFreeSolver.h =========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``SPlisHSPlasH/Utilities/MatrixFreeSolver.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef __MatrixFreeSolver_H__ #define __MatrixFreeSolver_H__ #include #include #include using SystemMatrixType = Eigen::SparseMatrix; namespace SPH { class MatrixReplacement; } namespace Eigen { namespace internal { template<> struct traits : public Eigen::internal::traits {}; } } namespace SPH { class MatrixReplacement : public Eigen::EigenBase { public: // Required typedefs, constants, and method: typedef Real Scalar; typedef Real RealScalar; typedef int StorageIndex; typedef void(*MatrixVecProdFct) (const Real*, Real*, void *); enum { ColsAtCompileTime = Eigen::Dynamic, MaxColsAtCompileTime = Eigen::Dynamic, IsRowMajor = false }; Index rows() const { return m_dim; } Index cols() const { return m_dim; } template Eigen::Product operator*(const Eigen::MatrixBase& x) const { return Eigen::Product(*this, x.derived()); } MatrixReplacement(const unsigned int dim, MatrixVecProdFct fct, void *userData) : m_dim(dim), m_matrixVecProdFct(fct), m_userData(userData) {} void * getUserData() { return m_userData; } MatrixVecProdFct getMatrixVecProdFct() { return m_matrixVecProdFct; } protected: unsigned int m_dim; void *m_userData; MatrixVecProdFct m_matrixVecProdFct; }; class JacobiPreconditioner1D { public: typedef typename SystemMatrixType::StorageIndex StorageIndex; typedef void(*DiagonalMatrixElementFct) (const unsigned int, Real&, void *); enum { ColsAtCompileTime = Eigen::Dynamic, MaxColsAtCompileTime = Eigen::Dynamic }; JacobiPreconditioner1D() {} void init(const unsigned int dim, DiagonalMatrixElementFct fct, void *userData) { m_dim = dim; m_diagonalElementFct = fct; m_userData = userData; } Eigen::Index rows() const { return m_dim; } Eigen::Index cols() const { return m_dim; } Eigen::ComputationInfo info() { return Eigen::Success; } template JacobiPreconditioner1D& analyzePattern(const MatType&) { return *this; } template JacobiPreconditioner1D& factorize(const MatType& mat) { return *this; } template JacobiPreconditioner1D& compute(const MatType& mat) { m_invDiag.resize(m_dim); #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int i = 0; i < (int)m_dim; i++) { Real res; m_diagonalElementFct(i, res, m_userData); m_invDiag[i] = static_cast(1.0) / res; } } return *this; } template void _solve_impl(const Rhs& b, Dest& x) const { x = m_invDiag.array() * b.array(); } template inline const Eigen::Solve solve(const Eigen::MatrixBase& b) const { return Eigen::Solve(*this, b.derived()); } protected: unsigned int m_dim; DiagonalMatrixElementFct m_diagonalElementFct; void *m_userData; VectorXr m_invDiag; }; class JacobiPreconditioner3D { public: typedef typename SystemMatrixType::StorageIndex StorageIndex; typedef void(*DiagonalMatrixElementFct) (const unsigned int, Vector3r&, void *); enum { ColsAtCompileTime = Eigen::Dynamic, MaxColsAtCompileTime = Eigen::Dynamic }; JacobiPreconditioner3D() {} void init(const unsigned int dim, DiagonalMatrixElementFct fct, void *userData) { m_dim = dim; m_diagonalElementFct = fct; m_userData = userData; } Eigen::Index rows() const { return 3*m_dim; } Eigen::Index cols() const { return 3*m_dim; } Eigen::ComputationInfo info() { return Eigen::Success; } template JacobiPreconditioner3D& analyzePattern(const MatType&) { return *this; } template JacobiPreconditioner3D& factorize(const MatType& mat) { return *this; } template JacobiPreconditioner3D& compute(const MatType& mat) { m_invDiag.resize(m_dim*3); #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int i = 0; i < (int)m_dim; i++) { Vector3r res; m_diagonalElementFct(i, res, m_userData); m_invDiag[3*i] = static_cast(1.0) / res[0]; m_invDiag[3*i+1] = static_cast(1.0) / res[1]; m_invDiag[3*i+2] = static_cast(1.0) / res[2]; } } return *this; } template void _solve_impl(const Rhs& b, Dest& x) const { x = m_invDiag.array() * b.array(); } template inline const Eigen::Solve solve(const Eigen::MatrixBase& b) const { return Eigen::Solve(*this, b.derived()); } protected: unsigned int m_dim; DiagonalMatrixElementFct m_diagonalElementFct; void *m_userData; VectorXr m_invDiag; }; class BlockJacobiPreconditioner3D { public: typedef typename SystemMatrixType::StorageIndex StorageIndex; typedef void(*DiagonalMatrixElementFct) (const unsigned int, Matrix3r&, void *); enum { ColsAtCompileTime = Eigen::Dynamic, MaxColsAtCompileTime = Eigen::Dynamic }; BlockJacobiPreconditioner3D() {} void init(const unsigned int dim, DiagonalMatrixElementFct fct, void *userData) { m_dim = dim; m_diagonalElementFct = fct; m_userData = userData; } Eigen::Index rows() const { return 3 * m_dim; } Eigen::Index cols() const { return 3 * m_dim; } Eigen::ComputationInfo info() { return Eigen::Success; } template BlockJacobiPreconditioner3D& analyzePattern(const MatType&) { return *this; } template BlockJacobiPreconditioner3D& factorize(const MatType& mat) { return *this; } template BlockJacobiPreconditioner3D& compute(const MatType& mat) { m_invDiag.resize(m_dim); #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int i = 0; i < (int)m_dim; i++) { Matrix3r res; m_diagonalElementFct(i, res, m_userData); m_invDiag[i] = res.inverse(); } } return *this; } template void _solve_impl(const Rhs& b, Dest& x) const { #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int i = 0; i < (int)m_dim; i++) { static_cast(x).block<3, 1>(3 * i, 0) = m_invDiag[i] * static_cast(b).block<3, 1>(3 * i, 0); } } } template inline const Eigen::Solve solve(const Eigen::MatrixBase& b) const { return Eigen::Solve(*this, b.derived()); } protected: unsigned int m_dim; DiagonalMatrixElementFct m_diagonalElementFct; void *m_userData; std::vector m_invDiag; }; } namespace Eigen { namespace internal { template struct generic_product_impl // GEMV stands for generic matrix-vector : generic_product_impl_base > { typedef typename Product::Scalar Scalar; template static void scaleAndAddTo(Dest& dst, const SPH::MatrixReplacement& lhs, const Rhs& rhs, const Scalar& alpha) { // This method should implement "dst += alpha * lhs * rhs" inplace, // however, for iterative solvers, alpha is always equal to 1, so let's not bother about it. assert(alpha == Scalar(1) && "scaling is not implemented"); const Real *vec = &rhs(0); Real *res = &dst(0); SPH::MatrixReplacement& lhs_ = const_cast(lhs); lhs_.getMatrixVecProdFct()(vec, res, lhs_.getUserData()); } }; } } #endif