diff --git a/include/GooseFEM/Matrix.h b/include/GooseFEM/Matrix.h index 9f6c035..085997f 100644 --- a/include/GooseFEM/Matrix.h +++ b/include/GooseFEM/Matrix.h @@ -1,242 +1,244 @@ /** Sparse matrix. \file Matrix.h \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_MATRIX_H #define GOOSEFEM_MATRIX_H #include "config.h" #include #include #include namespace GooseFEM { // forward declaration template class MatrixSolver; /** Sparse matrix. See Vector() for bookkeeping definitions. */ class Matrix { public: Matrix() = default; + virtual ~Matrix() = default; + /** Constructor. \param conn connectivity [#nelem, #nne]. \param dofs DOFs per node [#nnode, #ndim]. */ Matrix(const xt::xtensor& conn, const xt::xtensor& dofs); /** \return Number of elements. */ size_t nelem() const; /** \return Number of nodes per element. */ size_t nne() const; /** \return Number of nodes. */ size_t nnode() const; /** \return Number of dimensions. */ size_t ndim() const; /** \return Number of DOFs. */ size_t ndof() const; /** \return DOFs per node [#nnode, #ndim] */ xt::xtensor dofs() const; /** Assemble from matrices stored per element. \param elemmat [#nelem, #nne * #ndim, #nne * #ndim]. */ virtual void assemble(const xt::xtensor& elemmat); /** Overwrite matrix with (sparse) matrix. \param rows Row numbers in the matrix [n]. \param cols Column numbers in the matrix [n]. \param matrix Data entries on (rows, cols) [n]. */ virtual void set( const xt::xtensor& rows, const xt::xtensor& cols, const xt::xtensor& matrix); /** Add a (sparse) matrix to the matrix. \param rows Row numbers in the matrix [n]. \param cols Column numbers in the matrix [n]. \param matrix Data entries on (rows, cols) [n]. */ virtual void add( const xt::xtensor& rows, const xt::xtensor& cols, const xt::xtensor& matrix); /** \return Matrix as dense matrix [#ndof, #ndof]. */ xt::xtensor Todense() const; /** Covert matrix to dense matrix. \param ret overwritten [#ndof, #ndof]. */ virtual void todense(xt::xtensor& ret) const; /** Dot-product \f$ b_i = A_{ij} x_j \f$. \param x nodevec [#nelem, #ndim]. \return b nodevec overwritten [#nelem, #ndim]. */ xt::xtensor Dot(const xt::xtensor& x) const; /** Same as Dot(const xt::xtensor&, xt::xtensor& b) but writing to preallocated data. \param x nodevec [#nelem, #ndim]. \param b nodevec overwritten [#nelem, #ndim]. */ virtual void dot(const xt::xtensor& x, xt::xtensor& b) const; /** Dot-product \f$ b_i = A_{ij} x_j \f$. \param x dofval [#ndof]. \return b dofval overwritten [#ndof]. */ xt::xtensor Dot(const xt::xtensor& x) const; /** Same as Dot(const xt::xtensor&, xt::xtensor& b) but writing to preallocated data. \param x dofval [#ndof]. \param b dofval overwritten [#ndof]. */ virtual void dot(const xt::xtensor& x, xt::xtensor& b) const; protected: xt::xtensor m_conn; ///< Connectivity [#nelem, #nne]. xt::xtensor m_dofs; ///< DOF-numbers per node [#nnode, #ndim]. size_t m_nelem; ///< See nelem(). size_t m_nne; ///< See nne(). size_t m_nnode; ///< See nnode(). size_t m_ndim; ///< See ndim(). size_t m_ndof; ///< See ndof(). bool m_changed = true; ///< Signal changes to data. private: Eigen::SparseMatrix m_A; ///< The matrix. std::vector> m_T; ///< Matrix entries. template friend class MatrixSolver; ///< Grant access to solver class /** Convert "nodevec" to "dofval" (overwrite entries that occur more than once). \param nodevec input [#nnode, #ndim] \return dofval output [#ndof] */ Eigen::VectorXd AsDofs(const xt::xtensor& nodevec) const; /** Convert "dofval" to "nodevec" (overwrite entries that occur more than once). \param dofval input [#ndof] \param nodevec output [#nnode, #ndim] */ void asNode(const Eigen::VectorXd& dofval, xt::xtensor& nodevec) const; }; /** Solver for Matrix(). The idea is that this solver class can be used to solve for multiple right-hand-sides using one factorisation. */ template >> class MatrixSolver { public: MatrixSolver() = default; /** Solve \f$ x = A^{-1} b \f$. \param A sparse matrix, see Matrix(). \param b nodevec [nelem, ndim]. \return x nodevec [nelem, ndim]. */ xt::xtensor Solve(Matrix& A, const xt::xtensor& b); /** Same as Solve(Matrix&, const xt::xtensor&) but writing to preallocated data. \param A sparse matrix, see Matrix(). \param b nodevec [nelem, ndim]. \param x nodevec overwritten [nelem, ndim]. */ void solve(Matrix& A, const xt::xtensor& b, xt::xtensor& x); /** Same as Solve(Matrix&, const xt::xtensor&) but for "dofval" input and output. \param A sparse matrix, see Matrix(). \param b dofval [ndof]. \return x dofval [ndof]. */ xt::xtensor Solve(Matrix& A, const xt::xtensor& b); /** Same as Solve(Matrix&, const xt::xtensor&) but writing to preallocated data. \param A sparse matrix, see Matrix(). \param b dofval [ndof]. \param x dofval overwritten [ndof]. */ void solve(Matrix& A, const xt::xtensor& b, xt::xtensor& x); private: Solver m_solver; ///< Solver. bool m_factor = true; ///< Signal to force factorization. void factorize(Matrix& A); ///< Compute inverse (evaluated by "solve"). }; } // namespace GooseFEM #include "Matrix.hpp" #endif