#pragma once #include "geom.h" #include #include #include #include // ##################################################################### /** * Abstract matrix class. */ class Matrix { public: /** * Constructor for abstract matrix class. * * No memory is allocated. * * @param[in] nrows number of matrix rows. * @param[in] ncols number of matrix columns. */ Matrix(int nrows, int ncols); //Matrix(Matrix &) = default; Matrix(Matrix const& org) = default; // Copy constructor Matrix(Matrix && org) = default; // Move constructor Matrix& operator=(Matrix const& rhs) = default; // Copy assignment Matrix& operator=(Matrix && rhs) = default; // Move assignment virtual ~Matrix(); /** * Checks whether the matrix is a square matrix. * * @return True iff square matrix. */ bool isSquare() const { return _nrows==_ncols;} /** * Number of rows in matrix. * @return number of rows. */ int Nrows() const {return _nrows;} /** * Number of columns in matrix. * @return number of columns. */ int Ncols() const {return _ncols;} /** * Show the matrix entries. */ virtual void Debug() const = 0; /** * Extracts the diagonal elements of an inherited matrix. * * @param[in,out] d (prellocated) vector of diagonal elements */ virtual void GetDiag(std::vector &d) const = 0; /** * Extracts the diagonal elements of the matrix. * * @return d vector of diagonal elements */ std::vector const & GetDiag() const; /** * Performs the matrix-vector product w := K*u. * * @param[in,out] w resulting vector (preallocated) * @param[in] u vector */ virtual void Mult(std::vector &w, std::vector const &u) const = 0; /** * Calculates the defect/residuum w := f - K*u. * * @param[in,out] w resulting vector (preallocated) * @param[in] f load vector * @param[in] u vector */ virtual void Defect( std::vector &w, std::vector const &f, std::vector const &u) const = 0; //virtual void JacobiSmoother(std::vector const &f, std::vector &u, //std::vector &r, int nsmooth, double const omega, bool zero) const virtual void JacobiSmoother(std::vector const &, std::vector &, std::vector &, int, double const, bool) const { std::cout << "ERROR in Matrix::JacobiSmoother" << std::endl; assert(false); } /** * Finds in a CRS matrix the access index for an entry at row @p row and column @p col. * * @param[in] row row index * @param[in] col column index * @return index for element (@p row, @p col). If no appropriate entry exists then -1 will be returned. * * @warning assert() stops the function in case that matrix element (@p row, @p col) doesn't exist. */ virtual int fetch(int row, int col) const =0; protected: int _nrows; //!< number of rows in matrix int _ncols; //!< number of columns in matrix mutable std::vector _dd; //!< diagonal matrix elements }; // ##################################################################### class BisectInterpolation; // class forward declaration /** * Matrix in CRS format (compressed row storage; also named CSR), * see an introduction. */ class CRS_Matrix: public Matrix { public: /** * Constructor * */ CRS_Matrix(); //! \brief The sparse matrix in CRS format is initialized from a binary file. //! //! The binary file has to store 4 Byte integers and 8 Byte doubles and contains the following data: //! - Number of rows //! - Number of non-zero elements/blocks //! - Number of non-zero matrix elements (= previous number * dofs per block) //! - [#elements per row] (counter) //! - [column indices] //! - [matrix elements] //! //! \param[in] file name of binary file //! explicit CRS_Matrix(const std::string& file); CRS_Matrix(CRS_Matrix const& org) = default; // Copy constructor CRS_Matrix(CRS_Matrix && org) = default; // Move constructor CRS_Matrix& operator=(CRS_Matrix const& rhs) = default; // Copy assignment CRS_Matrix& operator=(CRS_Matrix && rhs) = default; // Move assignment ~CRS_Matrix() override; /** * Extracts the diagonal elements of the sparse matrix. * * @param[in,out] d (prellocated) vector of diagonal elements */ void GetDiag(std::vector &d) const override; // Solves non-M matrix problems for Jacobi iteration but not for MG void GetDiag_M(std::vector &d) const; /** * Performs the matrix-vector product w := K*u. * * @param[in,out] w resulting vector (preallocated) * @param[in] u vector */ void Mult(std::vector &w, std::vector const &u) const override; /** * Calculates the defect/residuum w := f - K*u. * * @param[in,out] w resulting vector (preallocated) * @param[in] f load vector * @param[in] u vector */ void Defect(std::vector &w, std::vector const &f, std::vector const &u) const override; void JacobiSmoother(std::vector const &f, std::vector &u, std::vector &r, int nsmooth, double omega, bool zero) const override; /** * Show the matrix entries. */ void Debug() const override; /** * Finds in a CRS matrix the access index for an entry at row @p row and column @p col. * * @param[in] row row index * @param[in] col column index * @return index for element (@p row, @p col). If no appropriate entry exists then -1 will be returned. * * @warning assert() stops the function in case that matrix element (@p row, @p col) doesn't exist. */ int fetch(int row, int col) const override; /** * Compare @p this CRS matrix with an external CRS matrix stored in C-Style. * * The method prints statements on differences found. * * @param[in] nnode row number of external matrix * @param[in] id start indices of matrix rows of external matrix * @param[in] ik column indices of external matrix * @param[in] sk non-zero values of external matrix * * @return true iff all data are identical. */ bool Compare2Old(int nnode, int const id[], int const ik[], double const sk[]) const; /** * Calculates the defect and projects it to the next coarser level @f$ f_C := P^T \cdot (f_F - SK\cdot u_F) @f$. * * @param[in] SK matrix on fine mesh * @param[in] P prolongation operator * @param[in,out] fc resulting coarse mesh vector (preallocated) * @param[in] ff r.h.s. on fine mesh * @param[in] uf status vector on fine mesh * */ friend void DefectRestrict(CRS_Matrix const & SK, BisectInterpolation const& P, std::vector &fc, std::vector &ff, std::vector &uf); //! \brief A sparse matrix in CRS format (counter, column index, value) is written to a binary file. //! //! The binary file has to store 4 Byte integers and 8 Byte doubles and contains the following data: //! - Number of rows //! - Number of non-zero elements //! - Number of non-zero elements //! - [#elements per row] //! - [column indices] //! - [elements] //! //! \param[in] file name of binary file //! void writeBinary(const std::string& file); private: //! \brief A sparse matrix in CRS format (counter, column index, value) is read from a binary file. //! //! The binary file has to store 4 Byte integers and 8 Byte doubles and contains the following data: //! - Number of rows //! - Number of non-zero elements/blocks //! - Number of non-zero matrix elements (= previous number * dofs per block) //! - [#elements per row] //! - [column indices] //! - [matrix elements] //! //! \param[in] file name of binary file //! void readBinary(const std::string& file); public: //private: /** * Checks matrix symmetry. * @return true iff matrix is symmetric. */ bool CheckSymmetry() const; /** * Checks whether the sum of all entries in each separate row is zero. * @return true/false */ bool CheckRowSum() const; /** * Checks M-matrix properties. * @return true/false */ bool CheckMproperty() const; /** * Checks for several matrix properties, as row sum and M-matrix * @return true/false */ bool CheckMatrix() const; /** * Changes the given matrix into an M-matrix. * The posive off diagonal enries of a row are lumped (added) * to the main diagonal entry of that row. * * @return true iff changes have been neccessary. */ bool ForceMproperty(); protected: int _nnz; //!< number of non-zero entries std::vector _id; //!< start indices of matrix rows std::vector _ik; //!< column indices std::vector _sk; //!< non-zero values }; /** * FEM Matrix in CRS format (compressed row storage; also named CSR), * see an introduction. */ class FEM_Matrix: public CRS_Matrix { public: /** * Initializes the CRS matrix structure from the given discretization in @p mesh. * * The sparse matrix pattern is generated but the values are 0. * * @param[in] mesh given discretization * * @warning A reference to the discretization @p mesh is stored inside this class. * Therefore, changing @p mesh outside requires also * to call method @p Derive_Matrix_Pattern explicitly. * * @see Derive_Matrix_Pattern */ explicit FEM_Matrix(Mesh const & mesh); FEM_Matrix(FEM_Matrix const &) = default; /** * Destructor. */ ~FEM_Matrix() override; /** * Generates the sparse matrix pattern and overwrites the existing pattern. * * The sparse matrix pattern is generated but the values are 0. */ void Derive_Matrix_Pattern() { //Derive_Matrix_Pattern_slow(); Derive_Matrix_Pattern_fast(); CheckRowSum(); } void Derive_Matrix_Pattern_fast(); void Derive_Matrix_Pattern_slow(); /** * Calculates the entries of f.e. stiffness matrix for the Laplace operator * for multiple domains with different conductivities * and load/rhs vector @p f. * No memory is allocated. * * @param[in,out] f (preallocated) rhs/load vector */ void CalculateLaplace_mult(std::vector &f); // Returns thermal conductivity coefficient of subdomain [ kg * m / (s^3 * K) ] double ThermalConductivity(const int subdomain); // Returns volumetric heap capacity (specific heat capacity * density) coefficient of subdomain // c * rho [ J / (m^3 * K) ] double VolumetricHeatCapacity(const int subdomain); /** * Calculates the entries of f.e. mass matrix * for multiple domains with different heat capacities * and load/rhs vector @p f. * No memory is allocated. * * @param[in,out] f (preallocated) rhs/load vector */ void AddMass_mult(std::vector &f); /** * Calculates the entries of f.e. stiffness matrix for the Laplace operator * and load/rhs vector @p f. * No memory is allocated. * * @param[in,out] f (preallocated) rhs/load vector */ void CalculateLaplace(std::vector &f); ///** //* Calculates the entries of f.e. stiffness matrix for the Laplace operator //* and load/rhs vector @p f according to function @p f_func, //* //* @param[in,out] f (preallocated) rhs/load vector //* @param[in] f_func function f(x,y,z) //*/ //void CalculateLaplace(std::vector &f, const std::function &f_func); /** * Calculates the entries of load/rhs vector @p f. * No memory is allocated. * * @param[in,out] f (preallocated) rhs/load vector * @param[in] func continuous function f(x,y) */ void CalculateRHS(std::vector &f, const std::function &func); /** * Applies Dirichlet boundary conditions to stiffness matrix and to load vector @p f. * The penalty method * is used for incorporating the given values @p u. * * @param[in] u (global) vector with Dirichlet data * @param[in,out] f load vector */ void ApplyDirichletBC(std::vector const &u, std::vector &f); /** * Applies Robin boundary conditions to stiffness matrix and to load vector @p f * for multiple subdomains * The penalty method * is used for incorporating the given values @p u. * * @param[in,out] f load vector * @param[in] u_out outside temperature */ void ApplyRobinBC_mult(std::vector &f, const double u_out); double Heat_transfer_coefficient(const int subdomain); /** * Extracts the diagonal elements of the sparse matrix. * * @param[in,out] d (prellocated) vector of diagonal elements */ //void GetDiag(std::vector &d) const; // override in MPI parallel void GetDiag(std::vector &d) const override { GetDiag_M(d); } // Solves non-M matrix problems for Jacobi iteration but not for MG //void GetDiag_M(std::vector &d) const; /** * Adds the element stiffness matrix @p ske and the element load vector @p fe * of one triangular element with linear shape functions to the appropriate positions in * the stiffness matrix, stored as CSR matrix K(@p sk,@p id, @p ik). * * @param[in] ial node indices of the three element vertices * @param[in] ske element stiffness matrix * @param[in] fe element load vector * @param[in,out] f distributed local vector storing the right hand side * * @warning Algorithm assumes linear triangular elements (ndof_e==3). */ void AddElem_3(int const ial[3], double const ske[3][3], double const fe[3], std::vector &f); /** * Adds the the element load vector @p fe * of one triangular element with linear shape functions to the appropriate positions in * the right hand side @p f. * * @param[in] ial node indices of the three element vertices * @param[in] fe element load vector * @param[in,out] f distributed local vector storing the right hand side * * @warning Algorithm assumes linear triangular elements (ndof_e==3). */ void AddElemRHS_3(int const ial[3], double const fe[3], std::vector &f); private: Mesh const & _mesh; //!< reference to discretization }; ///** //* Prolongation matrix in CRS format (compressed row storage; also named CSR), //* see an introduction. //* //* The prolongation is applied for each node from the coarse mesh to the fine mesh and //* is derived only geometrically (no operator weighted prolongation). //*/ //class Prolongation: public CRS_Matrix //{ //public: ///** //* Intializes the CRS matrix structure from the given discetization in @p mesh. //* //* The sparse matrix pattern is generated but the values are 0. //* //* @param[in] cmesh coarse mesh //* @param[in] fmesh fine mesh //* //* @warning A reference to the discretizations @p fmesh @p cmesh are stored inside this class. //* Therefore, changing these meshes outside requires also //* to call method @p Derive_Matrix_Pattern explicitely. //* //* @see Derive_Matrix_Pattern //*/ //Prolongation(Mesh const & cmesh, Mesh const & fmesh); ///** //* Destructor. //*/ //~Prolongation() override //{} ///** //* Generates the sparse matrix pattern and overwrites the existing pattern. //* //* The sparse matrix pattern is generated but the values are 0. //*/ //void Derive_Matrix_Pattern() override; //private: //Mesh const & _cmesh; //!< reference to coarse discretization //Mesh const & _fmesh; //!< reference to fine discretization //}; // ********************************************************************* /** * Interpolation matrix for prolongation coarse mesh (C) to a fine mesh (F) * generated by bisecting edges. * * All interpolation weights are 0.5 (injection points contribute twice). */ class BisectInterpolation: public Matrix { public: /** * Generates the interpolation matrix for prolongation coarse mesh to a fine mesh * generated by bisecting edges. * The interpolation weights are all 0.5. * * @param[in] fathers vector[nnodes][2] containing * the two coarse grid fathers of a fine grid vertex * */ explicit BisectInterpolation(std::vector const & fathers); BisectInterpolation(); BisectInterpolation(BisectInterpolation const& org) = default; // Copy constructor BisectInterpolation(BisectInterpolation && org) = default; // Move constructor BisectInterpolation& operator=(BisectInterpolation const& rhs) = default; // Copy assignment BisectInterpolation& operator=(BisectInterpolation && rhs) = default; // Move assignment ~BisectInterpolation() override; /** * Extracts the diagonal elements of the matrix. * * @param[in,out] d (prellocated) vector of diagonal elements */ void GetDiag(std::vector &d) const override; ///** //* Extracts the diagonal elements of the sparse matrix. //* //* @return d vector of diagonal elements //*/ //std::vector const & GetDiag() const override; /** * Performs the prolongation @f$ w_F := P*u_C @f$. * * @param[in,out] wf resulting fine vector (preallocated) * @param[in] uc coarse vector */ void Mult(std::vector &wf, std::vector const &uc) const override; /** * Performs the restriction @f$ u_C := P^T*w_F @f$. * * @param[in] wf fine vector * @param[in,out] uc resulting coarse vector (preallocated) */ virtual void MultT(std::vector const &wf, std::vector &uc) const; /** * Performs the full restriction @f$ u_C := F^{-1}*P^T*w_F @f$. * * @f$ F @f$ denotes the row sum of the restriction matrix * and results in restricting exactly a bilinear function from the fine grid onto * the same bilinear function on the coarse grid. * * @param[in] wf fine vector * @param[in,out] uc resulting coarse vector (preallocated) */ void MultT_Full(std::vector const &wf, std::vector &uc) const; /** * Calculates the defect/residuum w := f - P*u. * * @param[in,out] w resulting vector (preallocated) * @param[in] f load vector * @param[in] u coarse vector */ void Defect(std::vector &w, std::vector const &f, std::vector const &u) const override; /** * Show the matrix entries. */ void Debug() const override; /** * Finds in this matrix the access index for an entry at row @p row and column @p col. * * @param[in] row row index * @param[in] col column index * @return index for element (@p row, @p col). If no appropriate entry exists then -1 will be returned. * * @warning assert() stops the function in case that matrix element (@p row, @p col) doesn't exist. */ int fetch(int row, int col) const override; /** * Calculates the defect and projects it to the next coarser level @f$ f_C := P^T \cdot (f_F - SK\cdot u_F) @f$. * * @param[in] SK matrix on fine mesh * @param[in] P prolongation operator * @param[in,out] fc resulting coarse mesh vector (preallocated) * @param[in] ff r.h.s. on fine mesh * @param[in] uf status vector on fine mesh * */ friend void DefectRestrict(CRS_Matrix const & SK, BisectInterpolation const& P, std::vector &fc, std::vector &ff, std::vector &uf); protected: std::vector _iv; //!< fathers[nnode][2] of fine grid nodes, double entries denote injection points std::vector _vv; //!< weights[nnode][2] of fathers for grid nodes }; /** * Interpolation matrix for prolongation from coarse mesh (C)) to a fine mesh (F) * generated by bisecting edges. * * We take into account that values at Dirichlet nodes have to be preserved, i.e., * @f$ w_F = P \cdot I_D \cdot w_C @f$ and @f$ d_C = I_D \cdot P^T \cdot d_F@f$ * with @f$ I_D @f$ as @f$ n_C \times n_C @f$ diagonal matrix and entries * @f$ I_{D(j,j)} := \left\{{\begin{array}{l@{\qquad}l} 0 & x_{j}\;\; \textrm{is Dirichlet node} \\ 1 & \textrm{else} \end{array}}\right. @f$ * * Interpolation weights are eighter 0.5 or 0.0 in case of coarse Dirichlet nodes * (injection points contribute twice), * Sets weight to zero iff (at least) one father nodes is a Dirichlet node. */ class BisectIntDirichlet: public BisectInterpolation { public: /** * Default constructor. */ BisectIntDirichlet() : BisectInterpolation(), _idxDir() {} /** * Constructs interpolation from father-@p row and column @p col. * * @param[in] fathers two father nodes from each fine node [nnode_f*2]. * @param[in] idxc_dir vector containing the indices of coarse mesh Dirichlet nodes. * */ BisectIntDirichlet(std::vector const & fathers, std::vector idxc_dir); BisectIntDirichlet(BisectIntDirichlet const& org) = default; // Copy constructor BisectIntDirichlet(BisectIntDirichlet && org) = default; // Move constructor BisectIntDirichlet& operator=(BisectIntDirichlet const& rhs) = delete; // Copy assignment BisectIntDirichlet& operator=(BisectIntDirichlet && rhs) = delete; // Move assignment ~BisectIntDirichlet() override; /** * Performs the restriction @f$ u_C := P^T*w_F @f$. * * @param[in] wf fine vector * @param[in,out] uc resulting coarse vector (preallocated) */ void MultT(std::vector const &wf, std::vector &uc) const override; private: std::vector const _idxDir; }; // ********************************************************************* /** * Calculates the element stiffness matrix @p ske and the element load vector @p fe * of one triangular element with linear shape functions. * @param[in] ial node indices of the three element vertices * @param[in] xc vector of node coordinates with x(2*k,2*k+1) as coordinates of node k * @param[out] ske element stiffness matrix * @param[out] fe element load vector */ void CalcElem(int const ial[3], double const xc[], double ske[3][3], double fe[3]); /** * Calculates the element stiffness matrix @p ske * of one triangular element with linear shape functions * for specific thermal conductivity in subdomain * @param[in] ial node indices of the three element vertices * @param[in] xc vector of node coordinates with x(2*k,2*k+1) as coordinates of node k * @param[in] lambda thermal conductivity of element * @param[out] ske element stiffness matrix */ void CalcElemSpecific(int const ial[3], double const xc[], double const lambda, double ske[3][3]); /** * Calculates the element mass matrix @p ske. * of one triangular element with linear shape functions. * @param[in] ial node indices of the three element vertices * @param[in] xc vector of node coordinates with x(2*k,2*k+1) as coordinates of node k * @param[out] ske element stiffness matrix */ void CalcElem_Masse(int const ial[3], double const xc[], double ske[3][3]); /** * Calculates the element mass matrix @p ske. * of one triangular element with linear shape functions * for specific volumetric heat capacity in subdomain. * @param[in] ial node indices of the three element vertices * @param[in] xc vector of node coordinates with x(2*k,2*k+1) as coordinates of node k * @param[in] c volumetric heat capacity of element * @param[out] ske element stiffness matrix */ void CalcElem_MasseSpecific(int const ial[3], double const xc[], double const c, double ske[3][3]); /** * Calculates element load vector @p fe of one triangular element with linear shape functions. * @param[in] ial node indices of the three element vertices * @param[in] xc vector of node coordinates with x(2*k,2*k+1) as coordinates of node k * @param[out] fe element load vector * @param[in] func continuous function f(x,y) */ void CalcElem_RHS(int const ial[3], double const xc[], double fe[3], const std::function &func); /** * Adds the element stiffness matrix @p ske and the element load vector @p fe * of one triangular element with linear shape functions to the appropriate positions in * the symmetric stiffness matrix, stored as CSR matrix K(@p sk,@p id, @p ik) * * @param[in] ial node indices of the three element vertices * @param[in] ske element stiffness matrix * @param[in] fe element load vector * @param[out] sk vector non-zero entries of CSR matrix * @param[in] id index vector containing the first entry in a CSR row * @param[in] ik column index vector of CSR matrix * @param[out] f distributed local vector storing the right hand side * * @warning Algorithm requires indices in connectivity @p ial in ascending order. * Currently deprecated. */ void AddElem(int const ial[3], double const ske[3][3], double const fe[3], int const id[], int const ik[], double sk[], double f[]);