SciFEM-Project_CoffeeMugSim.../mgrid_2/getmatrix.h
dino.celebic ff2ba09279 cleanup
2026-01-24 21:29:54 +01:00

750 lines
27 KiB
C++

#pragma once
#include "geom.h"
#include <cassert>
#include <functional>
#include <string>
#include <vector>
// #####################################################################
/**
* 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<double> &d) const = 0;
/**
* Extracts the diagonal elements of the matrix.
*
* @return d vector of diagonal elements
*/
std::vector<double> 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<double> &w, std::vector<double> 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<double> &w,
std::vector<double> const &f, std::vector<double> const &u) const = 0;
//virtual void JacobiSmoother(std::vector<double> const &f, std::vector<double> &u,
//std::vector<double> &r, int nsmooth, double const omega, bool zero) const
virtual void JacobiSmoother(std::vector<double> const &, std::vector<double> &,
std::vector<double> &, 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<double> _dd; //!< diagonal matrix elements
};
// #####################################################################
class BisectInterpolation; // class forward declaration
/**
* Matrix in CRS format (compressed row storage; also named CSR),
* see an <a href="https://en.wikipedia.org/wiki/Sparse_matrix">introduction</a>.
*/
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<double> &d) const override;
// Solves non-M matrix problems for Jacobi iteration but not for MG
void GetDiag_M(std::vector<double> &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<double> &w, std::vector<double> 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<double> &w,
std::vector<double> const &f, std::vector<double> const &u) const override;
void JacobiSmoother(std::vector<double> const &f, std::vector<double> &u,
std::vector<double> &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<double> &fc, std::vector<double> &ff, std::vector<double> &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<int> _id; //!< start indices of matrix rows
std::vector<int> _ik; //!< column indices
std::vector<double> _sk; //!< non-zero values
};
/**
* FEM Matrix in CRS format (compressed row storage; also named CSR),
* see an <a href="https://en.wikipedia.org/wiki/Sparse_matrix">introduction</a>.
*/
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<double> &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<double> &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<double> &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<double> &f, const std::function<double(double, double, double)> &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<double> &f, const std::function<double(double,double)> &func);
/**
* Applies Dirichlet boundary conditions to stiffness matrix and to load vector @p f.
* The <a href="https://www.jstor.org/stable/2005611?seq=1#metadata_info_tab_contents">penalty method</a>
* 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<double> const &u, std::vector<double> &f);
/**
* Applies Robin boundary conditions to stiffness matrix and to load vector @p f
* for multiple subdomains
* The <a href="https://www.jstor.org/stable/2005611?seq=1#metadata_info_tab_contents">penalty method</a>
* 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<double> &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<double> &d) const; // override in MPI parallel
void GetDiag(std::vector<double> &d) const override { GetDiag_M(d); }
// Solves non-M matrix problems for Jacobi iteration but not for MG
//void GetDiag_M(std::vector<double> &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<double> &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<double> &f);
private:
Mesh const & _mesh; //!< reference to discretization
};
///**
//* Prolongation matrix in CRS format (compressed row storage; also named CSR),
//* see an <a href="https://en.wikipedia.org/wiki/Sparse_matrix">introduction</a>.
//*
//* 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<int> 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<double> &d) const override;
///**
//* Extracts the diagonal elements of the sparse matrix.
//*
//* @return d vector of diagonal elements
//*/
//std::vector<double> 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<double> &wf, std::vector<double> 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<double> const &wf, std::vector<double> &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<double> const &wf, std::vector<double> &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<double> &w,
std::vector<double> const &f, std::vector<double> 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<double> &fc, std::vector<double> &ff, std::vector<double> &uf);
protected:
std::vector<int> _iv; //!< fathers[nnode][2] of fine grid nodes, double entries denote injection points
std::vector<double> _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<int> const & fathers, std::vector<int> 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<double> const &wf, std::vector<double> &uc) const override;
private:
std::vector<int> 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<double(double,double)> &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[]);