// ============================================================================ // == == // == AMDiS - Adaptive multidimensional simulations == // == == // ============================================================================ // == == // == crystal growth group == // == == // == Stiftung caesar == // == Ludwig-Erhard-Allee 2 == // == 53175 Bonn == // == germany == // == == // ============================================================================ // == == // == http://www.caesar.de/cg/AMDiS == // == == // ============================================================================ /** \file DOFMatrix.h */ #ifndef AMDIS_DOFMATRIX_H #define AMDIS_DOFMATRIX_H // ============================================================================ // ===== includes ============================================================= // ============================================================================ #include #include #include #include "Global.h" #include "Flag.h" #include "RCNeighbourList.h" #include "DOFAdmin.h" #include "DOFIterator.h" #include "DOFIndexed.h" #include "MemoryManager.h" #include "Boundary.h" #include "Serializable.h" namespace AMDiS { // ============================================================================ // ===== forward declarations ================================================= // ============================================================================ class Mesh; class FiniteElemSpace; class ElInfo; class BasisFunction; class FillInfo; class Operator; class ElementMatrix; class BoundaryManager; template class DOFVector; // =========================================================================== // ===== struct MatEntry ===================================================== // =========================================================================== /** \brief * Represents one entry of a DOFMatrix */ struct MatEntry { /** \brief * column index of entry (if >= 0; else unused) */ DegreeOfFreedom col; /** \brief * matrix entry */ double entry; }; /** \brief * Is used to search for all entries of a matrix which column index is * smaller than a given value. */ class MatEntryValueLess : public ::std::unary_function { private: const double value_; public: MatEntryValueLess(const double& value) : value_(value) {}; bool operator()(const MatEntry& m) { return (fabs(m.entry) < value_); }; }; /** \brief * Is used to search for all entries of a matrix which value is smaller * than a given value. */ class MatEntryColLess : public ::std::unary_function { private: const int col_; public: MatEntryColLess(const int& col) : col_(col) {}; bool operator()(const MatEntry& m) { return (fabs(m.col) < col_); }; }; /** \brief * This function is required if two MatEntries are compared by their col * entry (for example when sorting a vector of MatEntries). */ struct CmpMatEntryCol : public ::std::binary_function { bool operator()(const MatEntry& m1, const MatEntry m2) const { return m1.col < m2.col; }; }; /** \brief * This function compares two matrix entries by their values. It returns true, * if the value of m2 is greater than the value of m1. */ struct CmpMatEntryValue : public ::std::binary_function { bool operator()(const MatEntry& m1, const MatEntry m2) const { return m1.entry < m2.entry; }; }; /** \brief * This function compares two matrix entries by their values. It returns true, * if the value of m2 is greater than the value of m1. */ struct CmpMatEntryAbsValueLess : public ::std::binary_function { bool operator()(const MatEntry& m1, const MatEntry m2) const { return fabs(m1.entry) < fabs(m2.entry); }; }; /** \brief * This function compares two matrix entries by their values. It returns true, * if the value of m1 is greater than the value of m2. */ struct CmpMatEntryAbsValueGreater : public ::std::binary_function { bool operator()(const MatEntry& m1, const MatEntry m2) const { return fabs(m1.entry) > fabs(m2.entry); }; }; // ============================================================================ // ===== class DOFMatrix ====================================================== // ============================================================================ /** \ingroup DOFAdministration * \brief * A DOFMatrix is a sparse matrix representation for matrices that work * on DOFVectors. Every row of a matrix is realized as a vector of MatEntry * objects. Each entry consists of a column DOF index and the corresponding * double matrix entry. Unused entries are marked with a negative column index. */ class DOFMatrix : public DOFIndexed< ::std::vector >, public Serializable { public: MEMORY_MANAGED(DOFMatrix); /** \ingroup DOFAdministration * \brief * Alias for DOFIterator< ::std::vector > >. So one can access an * iterator working on a DOFMatrix via DOFMatrix::Iterator */ class Iterator : public DOFIterator< ::std::vector > { public: Iterator(DOFIndexed< ::std::vector > *c, DOFIteratorType type) : DOFIterator< ::std::vector >(c, type) {}; }; /** \brief * A MatrixRow represents one row of the sparse matrix. It is realized by * a STL vector of MatEntry objects */ typedef ::std::vector MatrixRow; /** \brief * Symbolic constant for an unused matrix entry */ static const int UNUSED_ENTRY = -1; /** \brief * Symbolic constant for an unused entry which is not followed by any * used entry in this row */ static const int NO_MORE_ENTRIES = -2; public: DOFMatrix(); /** \brief * Constructs a DOFMatrix with name n and the given row and * column FESpaces. */ DOFMatrix(const FiniteElemSpace* rowFESpace, const FiniteElemSpace* colFESpace, ::std::string n=""); /** \brief * Copy-Constructor */ DOFMatrix(const DOFMatrix& rhs); /** \brief * Destructor */ virtual ~DOFMatrix(); /** \brief * operator= */ DOFMatrix& operator=(const DOFMatrix& rhs); void copy(const DOFMatrix& rhs); /** \brief * Returns an iterator to the begin of matrix rows (\ref matrix.begin()) */ ::std::vector< ::std::vector >::iterator begin() { return matrix.begin(); }; /** \brief * Returns an iterator to the end of matrix rows (\ref matrix.end()) */ ::std::vector< ::std::vector >::iterator end() { return matrix.end(); }; /** \brief * Used by DOFAdmin to compress the DOFMatrix */ virtual void compressDOFIndexed(int first, int last, ::std::vector &newDOF); /** \brief * Implements DOFIndexedBase::freeDOFContent() */ virtual void freeDOFContent(int index); /** \brief * Returns whether entry matrix[a][b] is used */ inline bool entryUsed(DegreeOfFreedom a,int b) const { return (((matrix[a])[b]).col >= 0); }; /** \brief * Returns true if matrix[a][b] has entry \ref NO_MORE_ENTRIES */ inline bool noMoreEntries(DegreeOfFreedom a,int b) const { return (NO_MORE_ENTRIES==((matrix[a])[b]).col); }; /** \brief * Returns \ref coupleMatrix. */ inline bool isCoupleMatrix() { return coupleMatrix; }; /** \brief * Returns \ref coupleMatrix. */ inline void setCoupleMatrix(bool c) { coupleMatrix = c; }; /** \brief * Matrix-matrix multiplication. */ void mm(MatrixTranspose aTranspose, DOFMatrix& a, MatrixTranspose bTranspose, DOFMatrix& b); /** \brief * a*x + y */ void axpy(double a, const DOFMatrix& x, const DOFMatrix& y); /** \brief * Multiplication with a scalar. */ void scal(double s); inline void addOperator(Operator *op, double* factor = NULL, double* estFactor = NULL) { operators.push_back(op); operatorFactor.push_back(factor); operatorEstFactor.push_back(estFactor); }; inline ::std::vector::iterator getOperatorFactorBegin() { return operatorFactor.begin(); }; inline ::std::vector::iterator getOperatorFactorEnd() { return operatorFactor.end(); }; inline ::std::vector::iterator getOperatorEstFactorBegin() { return operatorEstFactor.begin(); }; inline ::std::vector::iterator getOperatorEstFactorEnd() { return operatorEstFactor.end(); }; inline ::std::vector::iterator getOperatorsBegin() { return operators.begin(); }; inline ::std::vector::iterator getOperatorsEnd() { return operators.end(); }; Flag getAssembleFlag(); /** \brief * Updates the matrix matrix by traversing the underlying mesh and assembling * the element contributions into the matrix. Information about the * computation of element matrices and connection of local and global DOFs is * stored in minfo; the flags for the mesh traversal are stored at * minfo->fill_flags which specifies the elements to be visited and * information that should be present on the elements for the calculation of * the element matrices and boundary information (if minfo->boundBas is not * NULL). On the elements, information about the row DOFs is accessed by * minfo->rowBas using info->row_admin; this vector is also used for the * column DOFs if minfo->nCol is less or equal zero, or minfo->col_admin or * minfo->colBas is a NULL pointer; if row and column DOFs are the same, the * boundary type of the DOFs is accessed by minfo->boundBas if * minfo->boundBas is not a NULL pointer; then the element matrix is * computed by minfo->fillElementMatrix(el info, minfo->myFill); these * contributions, multiplied by minfo->factor, are eventually added to matrix * by a call of addElementMatrix() with all information about row and column * DOFs, the element matrix, and boundary types, if available; * updateMatrix() only adds element contributions; this makes several calls * for the assemblage of one matrix possible; before the first call, the * matrix should be cleared by calling clear dof matrix(). */ ElementMatrix *assemble(double factor, ElInfo *elInfo, const BoundaryType *bound, Operator *op = NULL); /** \brief * Adds an element matrix to \ref matrix */ void addElementMatrix(double sign, const ElementMatrix& elMat, const BoundaryType *bound, bool add = true); /** \brief * Returns \ref matrix */ ::std::vector< ::std::vector >& getMatrix() { return matrix; }; void setMatrix(::std::vector< ::std::vector > m) { matrix = m; }; /** \brief * Returns \ref matrix[n] */ const ::std::vector& getRow(int n) const { return matrix[n]; }; /** \brief * Returns \ref matrix[n] */ ::std::vector& getRow(int n) { return matrix[n]; }; /** \brief * Returns whether interpolation should be performed after refinement * (false by default) */ virtual bool refineInterpol() { return false; }; /** \brief * Returns whether restriction should be performed after coarsening * (false by default) */ virtual bool coarseRestrict() { return false; }; /** \brief * Returns const \ref rowFESpace */ const FiniteElemSpace* getRowFESpace() const { return rowFESpace; }; /** \brief * Returns const \ref colFESpace */ const FiniteElemSpace* getColFESpace() const { return colFESpace; }; /** \brief * Returns const \ref rowFESpace */ const FiniteElemSpace* getFESpace() const { return rowFESpace; }; /** \brief * Returns number of rows (\ref matrix.size()) */ inline int getSize() const { return matrix.size(); }; /** \brief * Returns \ref name */ inline const ::std::string& getName() const { return name; }; /** \brief * Resizes \ref matrix to n rows */ inline void resize(int n) { TEST_EXIT_DBG(n >= 0)("Can't resize DOFMatrix to negative size\n"); matrix.resize(n); }; /** \brief * Returns \ref matrix[i] which is the i-th row */ inline const ::std::vector& operator[](int i) const { TEST_EXIT_DBG((i >= 0) && (i < (static_cast(matrix.size())))) ("Illegal matrix index %d.\n",i); return matrix[i]; }; /** \brief * Returns \ref matrix[i] which is the i-th row */ inline ::std::vector& operator[](int i) { TEST_EXIT_DBG((i >= 0) && (i < (static_cast(matrix.size())))) ("Illegal vector index %d.\n", i); return matrix[i]; }; /** \brief * Access to \ref matrix[a][b].entry */ inline double physAcc(DegreeOfFreedom a, DegreeOfFreedom b) const { return matrix[a][b].entry; }; /** \brief * Access to \ref matrix[a][b].col */ inline DegreeOfFreedom physToLogIndex(DegreeOfFreedom a, DegreeOfFreedom b) const { return matrix[a][b].col; }; /** \brief * Returns physical column index of logical index b in row a */ DegreeOfFreedom logToPhysIndex(DegreeOfFreedom a,DegreeOfFreedom b) const; /** \brief * Returns value at logical indices a,b */ double logAcc(DegreeOfFreedom a,DegreeOfFreedom b) const; /** \brief * Changes col at logical indices a,b to c */ void changeColOfEntry(DegreeOfFreedom a,DegreeOfFreedom b,DegreeOfFreedom c); /** \brief * Changes col of \ref matrix[a][b] to c */ inline void changePhysColOfEntry(DegreeOfFreedom a, DegreeOfFreedom b, DegreeOfFreedom c) { matrix[a][b].col = c; }; /** \brief * Creates an entry with logical indices irow, icol if there is no entry * yet. Than sign * entry is added to the value at this logical indices */ double *addSparseDOFEntry(double sign, int irow, int jcol, double entry, bool add = true); inline double *hasSparseDOFEntry(int irow, int jcol) { ::std::vector::iterator it; ::std::vector::iterator end = matrix[irow].end(); for (it = matrix[irow].begin(); it != end; ++it) { if (it->col == NO_MORE_ENTRIES) return NULL; if (it->col == jcol) return &(it->entry); }; return NULL; }; void addMatEntry(int row, MatEntry entry); void addMatEntry(int row, int DegreeOfFreedom, double value); void addRow(::std::vector row); /** \brief * Prints \ref matrix to stdout */ void print() const; /** \brief * Prints a row of \ref matrix to stdout */ void printRow(int i) const; /** \brief * Removes all matrix entries */ void clear(); /** \brief * Test whether \ref matrix is symmetric. Exits if not. */ void test(); bool symmetric(); inline ::std::vector getOperators() { return operators; }; inline ::std::vector getOperatorFactor() { return operatorFactor; }; inline ::std::vector getOperatorEstFactor() { return operatorEstFactor; }; inline BoundaryManager* getBoundaryManager() const { return boundaryManager; }; inline void setBoundaryManager(BoundaryManager *bm) { boundaryManager = bm; }; void createPictureFile(const char* filename, int dim); // ===== Serializable implementation ===== void serialize(::std::ostream &out) { unsigned int matrixSize = matrix.size(); unsigned int vecSize = 0; out.write(reinterpret_cast(&matrixSize), sizeof(unsigned int)); for(unsigned int i = 0; i < matrixSize; i++) { vecSize = matrix[i].size(); out.write(reinterpret_cast(&vecSize), sizeof(unsigned int)); out.write(reinterpret_cast(&(matrix[i][0])), vecSize * sizeof(MatEntry)); } }; void deserialize(::std::istream &in) { unsigned int matrixSize, vecSize; in.read(reinterpret_cast(&matrixSize), sizeof(unsigned int)); matrix.resize(matrixSize); for(unsigned int i = 0; i < matrixSize; i++) { in.read(reinterpret_cast(&vecSize), sizeof(unsigned int)); matrix[i].resize(vecSize); in.read(reinterpret_cast(&(matrix[i][0])), vecSize * sizeof(MatEntry)); } }; int memsize(); protected: /** \brief * Used by updateMatrix */ //static int assembleFct(ElInfo *el_info); protected: /** \brief * Pointer to a FiniteElemSpace with information about corresponding row DOFs * and basis functions */ const FiniteElemSpace *rowFESpace; /** \brief * Pointer to a FiniteElemSpace with information about corresponding * column DOFs and basis functions */ const FiniteElemSpace *colFESpace; /** \brief * Name of the DOFMatrix */ ::std::string name; /** \brief * Sparse matrix stored in an STL vector of MatrixRow objects */ ::std::vector matrix; /** \brief * Is used in the assembling process to store the assembled matrix of * one element. */ ElementMatrix *elementMatrix; /** \brief * Used while mesh traversal */ static DOFMatrix *traversePtr; /** \brief * Pointers to all operators of the equation systems. Are used in the * assembling process. */ ::std::vector operators; /** \brief * Defines for each operator a factor which is used to scal the element * matrix after the assembling process of the operator. */ ::std::vector operatorFactor; ::std::vector operatorEstFactor; BoundaryManager *boundaryManager; bool coupleMatrix; friend class DOFAdmin; friend class DOFVector; friend class DOFVector; friend class DOFVector; friend class DOFVector >; }; inline DegreeOfFreedom logToPhysIndex(DOFMatrix *m, DegreeOfFreedom a, DegreeOfFreedom b) { return m->logToPhysIndex(a, b); } double norm(::std::vector *row); double min(::std::vector *row); double max(::std::vector *row); } #endif // AMDIS_DOFMATRIX_H