1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18 
19 
20 #ifndef LIBMESH_SPARSE_MATRIX_H
21 #define LIBMESH_SPARSE_MATRIX_H
22 
23 
24 // Local includes
25 #include "libmesh/libmesh.h"
26 #include "libmesh/libmesh_common.h"
27 #include "libmesh/id_types.h"
28 #include "libmesh/reference_counted_object.h"
29 #include "libmesh/parallel_object.h"
30 #include "libmesh/enum_parallel_type.h"
31 
32 // C++ includes
33 #include <cstddef>
34 #include <iomanip>
35 #include <vector>
36 #include <memory>
37 
38 namespace libMesh
39 {
40 
41 // forward declarations
42 template <typename T> class SparseMatrix;
43 template <typename T> class DenseMatrix;
44 class DofMap;
45 namespace SparsityPattern { class Graph; }
46 template <typename T> class NumericVector;
47 
48 // This template helper function must be declared before it
49 // can be defined below.
50 template <typename T>
51 std::ostream & operator << (std::ostream & os, const SparseMatrix<T> & m);
52 
53 
54 /**
55  * Generic sparse matrix. This class contains pure virtual members
56  * that must be overridden in derived classes.  Using a common base
57  * class allows for uniform access to sparse matrices from various
58  * different solver packages in different formats.
59  *
60  * \author Benjamin S. Kirk
61  * \date 2003
62  */
63 template <typename T>
64 class SparseMatrix : public ReferenceCountedObject<SparseMatrix<T>>,
65                      public ParallelObject
66 {
67 public:
68   /**
69    * Constructor; initializes the matrix to be empty, without any
70    * structure, i.e.  the matrix is not usable at all. This
71    * constructor is therefore only useful for matrices which are
72    * members of a class. All other matrices should be created at a
73    * point in the data flow where all necessary information is
74    * available.
75    *
76    * You have to initialize the matrix before usage with
77    * \p init(...).
78    */
79   explicit
80   SparseMatrix (const Parallel::Communicator & comm);
81 
82   /**
83    * The 5 special functions can be defaulted for this class, as it
84    * does not manage any memory itself.
85    */
86   SparseMatrix (SparseMatrix &&) = default;
87   SparseMatrix (const SparseMatrix &) = default;
88   SparseMatrix & operator= (const SparseMatrix &) = default;
89   SparseMatrix & operator= (SparseMatrix &&) = default;
90   virtual ~SparseMatrix () = default;
91 
92   /**
93    * Builds a \p SparseMatrix<T> using the linear solver package specified by
94    * \p solver_package
95    */
96   static std::unique_ptr<SparseMatrix<T>>
97   build(const Parallel::Communicator & comm,
98         const SolverPackage solver_package = libMesh::default_solver_package());
99 
100   /**
101    * \returns \p true if the matrix has been initialized,
102    * \p false otherwise.
103    */
initialized()104   virtual bool initialized() const { return _is_initialized; }
105 
106   /**
107    * Get a pointer to the \p DofMap to use.
108    */
attach_dof_map(const DofMap & dof_map)109   void attach_dof_map (const DofMap & dof_map)
110   { _dof_map = &dof_map; }
111 
112   /**
113    * \returns \p true if this sparse matrix format needs to be fed the
114    * graph of the sparse matrix.
115    *
116    * This is true for \p LaspackMatrix, but not \p PetscMatrix.  In
117    * the case where the full graph is not required, we can efficiently
118    * approximate it to provide a good estimate of the required size of
119    * the sparse matrix.
120    */
need_full_sparsity_pattern()121   virtual bool need_full_sparsity_pattern() const
122   { return false; }
123 
124   /**
125    * Updates the matrix sparsity pattern. When your \p SparseMatrix<T>
126    * implementation does not need this data, simply do not override
127    * this method.
128    */
update_sparsity_pattern(const SparsityPattern::Graph &)129   virtual void update_sparsity_pattern (const SparsityPattern::Graph &) {}
130 
131   /**
132    * Initialize SparseMatrix with the specified sizes.
133    *
134    * \param m The global number of rows.
135    * \param n The global number of columns.
136    * \param m_l The local number of rows.
137    * \param n_l The local number of columns.
138    * \param nnz The number of on-diagonal nonzeros per row (defaults to 30).
139    * \param noz The number of off-diagonal nonzeros per row (defaults to 10).
140    * \param blocksize Optional value indicating dense coupled blocks
141    * for systems with multiple variables all of the same type.
142    */
143   virtual void init (const numeric_index_type m,
144                      const numeric_index_type n,
145                      const numeric_index_type m_l,
146                      const numeric_index_type n_l,
147                      const numeric_index_type nnz=30,
148                      const numeric_index_type noz=10,
149                      const numeric_index_type blocksize=1) = 0;
150 
151   /**
152    * Initialize this matrix using the sparsity structure computed by \p dof_map.
153    * @param type The serial/parallel/ghosted type of the matrix
154    */
155   virtual void init (ParallelType type = PARALLEL) = 0;
156 
157   /**
158    * Restores the \p SparseMatrix<T> to a pristine state.
159    */
160   virtual void clear () = 0;
161 
162   /**
163    * Set all entries to 0.
164    */
165   virtual void zero () = 0;
166 
167   /**
168    * \returns A smart pointer to a copy of this matrix with the same
169    * type, size, and partitioning, but with all zero entries.
170    *
171    * \note This must be overridden in the derived classes.
172    */
173   virtual std::unique_ptr<SparseMatrix<T>> zero_clone () const = 0;
174 
175   /**
176    * \returns A smart pointer to a copy of this matrix.
177    *
178    * \note This must be overridden in the derived classes.
179    */
180   virtual std::unique_ptr<SparseMatrix<T>> clone () const = 0;
181 
182   /**
183    * Sets all row entries to 0 then puts \p diag_value in the diagonal entry.
184    */
185   virtual void zero_rows (std::vector<numeric_index_type> & rows, T diag_value = 0.0);
186 
187   /**
188    * Calls the SparseMatrix's internal assembly routines, ensuring
189    * that the values are consistent across processors.
190    */
191   virtual void close () = 0;
192 
193   /**
194    *  For PETSc matrix , this function is similar to close but without shrinking memory.
195    *  This is useful when we want to switch between ADD_VALUES and INSERT_VALUES.
196    *  close should be called before using the matrix.
197    */
flush()198   virtual void flush () { close(); }
199 
200   /**
201    * \returns The row-dimension of the matrix.
202    */
203   virtual numeric_index_type m () const = 0;
204 
205   /**
206    * Get the number of rows owned by this process
207    */
local_m()208   virtual numeric_index_type local_m () const { return row_stop() - row_start(); }
209 
210   /**
211    * \returns The column-dimension of the matrix.
212    */
213   virtual numeric_index_type n () const = 0;
214 
215   /**
216    * \returns The index of the first matrix row stored on this
217    * processor.
218    */
219   virtual numeric_index_type row_start () const = 0;
220 
221   /**
222    * \returns The index of the last matrix row (+1) stored on this
223    * processor.
224    */
225   virtual numeric_index_type row_stop () const = 0;
226 
227   /**
228    * Set the element \p (i,j) to \p value.  Throws an error if the
229    * entry does not exist. Zero values can be "stored" in non-existent
230    * fields.
231    */
232   virtual void set (const numeric_index_type i,
233                     const numeric_index_type j,
234                     const T value) = 0;
235 
236   /**
237    * Add \p value to the element \p (i,j).  Throws an error if the
238    * entry does not exist. Zero values can be "added" to non-existent
239    * entries.
240    */
241   virtual void add (const numeric_index_type i,
242                     const numeric_index_type j,
243                     const T value) = 0;
244 
245   /**
246    * Add the full matrix \p dm to the SparseMatrix.  This is useful
247    * for adding an element matrix at assembly time.
248    */
249   virtual void add_matrix (const DenseMatrix<T> & dm,
250                            const std::vector<numeric_index_type> & rows,
251                            const std::vector<numeric_index_type> & cols) = 0;
252 
253   /**
254    * Same as \p add_matrix, but assumes the row and column maps are the same.
255    * Thus the matrix \p dm must be square.
256    */
257   virtual void add_matrix (const DenseMatrix<T> & dm,
258                            const std::vector<numeric_index_type> & dof_indices) = 0;
259 
260   /**
261    * Add the full matrix \p dm to the SparseMatrix.  This is useful
262    * for adding an element matrix at assembly time.  The matrix is
263    * assumed blocked, and \p brow, \p bcol correspond to the *block*
264    * row and column indices.
265    */
266   virtual void add_block_matrix (const DenseMatrix<T> & dm,
267                                  const std::vector<numeric_index_type> & brows,
268                                  const std::vector<numeric_index_type> & bcols);
269 
270   /**
271    * Same as \p add_block_matrix(), but assumes the row and column
272    * maps are the same.  Thus the matrix \p dm must be square.
273    */
add_block_matrix(const DenseMatrix<T> & dm,const std::vector<numeric_index_type> & dof_indices)274   virtual void add_block_matrix (const DenseMatrix<T> & dm,
275                                  const std::vector<numeric_index_type> & dof_indices)
276   { this->add_block_matrix (dm, dof_indices, dof_indices); }
277 
278   /**
279    * Compute \f$ A \leftarrow A + a*X \f$ for scalar \p a, matrix \p X.
280    */
281   virtual void add (const T a, const SparseMatrix<T> & X) = 0;
282 
283   /**
284    * Compute Y = A*X for matrix \p X.
285    */
matrix_matrix_mult(SparseMatrix<T> &,SparseMatrix<T> &)286   virtual void matrix_matrix_mult (SparseMatrix<T> & /*X*/, SparseMatrix<T> & /*Y*/)
287   { libmesh_not_implemented(); }
288 
289   /**
290    * Add \p scalar* \p spm to the rows and cols of this matrix (A):
291    * A(rows[i], cols[j]) += scalar * spm(i,j)
292    */
add_sparse_matrix(const SparseMatrix<T> &,const std::map<numeric_index_type,numeric_index_type> &,const std::map<numeric_index_type,numeric_index_type> &,const T)293   virtual void add_sparse_matrix (const SparseMatrix<T> & /*spm*/,
294                                   const std::map<numeric_index_type, numeric_index_type> & /*rows*/,
295                                   const std::map<numeric_index_type, numeric_index_type> & /*cols*/,
296                                   const T /*scalar*/)
297   { libmesh_not_implemented(); }
298 
299   /**
300    * \returns A copy of matrix entry \p (i,j).
301    *
302    * \note This may be an expensive operation, and you should always
303    * be careful where you call this function.
304    */
305   virtual T operator () (const numeric_index_type i,
306                          const numeric_index_type j) const = 0;
307 
308   /**
309    * \returns The \f$ \ell_1 \f$-norm of the matrix, that is the max column sum:
310    * \f$ |M|_1 = \max_{j} \sum_{i} |M_{ij}| \f$
311    *
312    * This is the natural matrix norm that is compatible with the
313    * \f$ \ell_1 \f$-norm for vectors, i.e. \f$ |Mv|_1 \leq |M|_1 |v|_1 \f$.
314    * (cf. Haemmerlin-Hoffmann : Numerische Mathematik)
315    */
316   virtual Real l1_norm () const = 0;
317 
318   /**
319    * \returns The \f$ \ell_{\infty} \f$-norm of the matrix, that is the max row sum:
320    *
321    * \f$ |M|_{\infty} = \max_{i} \sum_{j} |M_{ij}| \f$
322    *
323    * This is the natural matrix norm that is compatible to the
324    * \f$ \ell_{\infty} \f$-norm of vectors, i.e.
325    * \f$ |Mv|_{\infty} \leq |M|_{\infty} |v|_{\infty} \f$.
326    * (cf. Haemmerlin-Hoffmann : Numerische Mathematik)
327    */
328   virtual Real linfty_norm () const = 0;
329 
330   /**
331    * \returns \p true if the matrix has been assembled.
332    */
333   virtual bool closed() const = 0;
334 
335   /**
336    * Print the contents of the matrix to the screen in a uniform
337    * style, regardless of matrix/solver package being used.
338    */
339   void print(std::ostream & os=libMesh::out, const bool sparse=false) const;
340 
341   /**
342    * Same as the print method above, but allows you to print to a
343    * stream in the standard syntax.
344    *
345    * \code
346    * template <typename U>
347    * friend std::ostream & operator << (std::ostream & os, const SparseMatrix<U> & m);
348    * \endcode
349    *
350    * \note The above syntax, which does not require any
351    * prior declaration of operator<<, declares *any* instantiation of
352    * SparseMatrix<X> is friend to *any* instantiation of
353    * operator<<(ostream &, SparseMatrix<Y> &).  It would not happen in
354    * practice, but in principle it means that SparseMatrix<Complex>
355    * would be friend to operator<<(ostream &, SparseMatrix<Real>).
356    *
357    * \note The form below, which requires a previous
358    * declaration of the operator<<(stream &, SparseMatrix<T> &) function
359    * (see top of this file), means that any instantiation of
360    * SparseMatrix<T> is friend to the specialization
361    * operator<<(ostream &, SparseMatrix<T> &), but e.g. SparseMatrix<U>
362    * is *not* friend to the same function.  So this is slightly
363    * different to the form above...
364    *
365    * This method seems to be the "preferred" technique, see
366    * http://www.parashift.com/c++-faq-lite/template-friends.html
367    */
368   friend std::ostream & operator << <>(std::ostream & os, const SparseMatrix<T> & m);
369 
370   /**
371    * Print the contents of the matrix to the screen in a
372    * package-personalized style, if available.
373    */
374   virtual void print_personal(std::ostream & os=libMesh::out) const = 0;
375 
376   /**
377    * Print the contents of the matrix in Matlab's sparse matrix
378    * format. Optionally prints the matrix to the file named \p name.
379    * If \p name is not specified it is dumped to the screen.
380    */
381   virtual void print_matlab(const std::string & /*name*/ = "") const
382   {
383     libmesh_not_implemented();
384   }
385 
386   /**
387    * This function creates a matrix called "submatrix" which is defined
388    * by the row and column indices given in the "rows" and "cols" entries.
389    * Currently this operation is only defined for the PetscMatrix type.
390    */
create_submatrix(SparseMatrix<T> & submatrix,const std::vector<numeric_index_type> & rows,const std::vector<numeric_index_type> & cols)391   virtual void create_submatrix(SparseMatrix<T> & submatrix,
392                                 const std::vector<numeric_index_type> & rows,
393                                 const std::vector<numeric_index_type> & cols) const
394   {
395     this->_get_submatrix(submatrix,
396                          rows,
397                          cols,
398                          false); // false means DO NOT REUSE submatrix
399   }
400 
401   /**
402    * This function is similar to the one above, but it allows you to reuse
403    * the existing sparsity pattern of "submatrix" instead of reallocating
404    * it again.  This should hopefully be more efficient if you are frequently
405    * extracting submatrices of the same size.
406    */
reinit_submatrix(SparseMatrix<T> & submatrix,const std::vector<numeric_index_type> & rows,const std::vector<numeric_index_type> & cols)407   virtual void reinit_submatrix(SparseMatrix<T> & submatrix,
408                                 const std::vector<numeric_index_type> & rows,
409                                 const std::vector<numeric_index_type> & cols) const
410   {
411     this->_get_submatrix(submatrix,
412                          rows,
413                          cols,
414                          true); // true means REUSE submatrix
415   }
416 
417   /**
418    * Multiplies the matrix by the NumericVector \p arg and stores the
419    * result in NumericVector \p dest.
420    */
421   void vector_mult (NumericVector<T> & dest,
422                     const NumericVector<T> & arg) const;
423 
424   /**
425    * Multiplies the matrix by the NumericVector \p arg and adds the
426    * result to the NumericVector \p dest.
427    */
428   void vector_mult_add (NumericVector<T> & dest,
429                         const NumericVector<T> & arg) const;
430 
431   /**
432    * Copies the diagonal part of the matrix into \p dest.
433    */
434   virtual void get_diagonal (NumericVector<T> & dest) const = 0;
435 
436   /**
437    * Copies the transpose of the matrix into \p dest, which may be
438    * *this.
439    */
440   virtual void get_transpose (SparseMatrix<T> & dest) const = 0;
441 
442   /**
443    * Get a row from the matrix
444    * @param i The matrix row to get
445    * @param indices A container that will be filled with the column indices
446    *                corresponding to (possibly) non-zero values
447    * @param values A container holding the column values
448    */
get_row(numeric_index_type,std::vector<numeric_index_type> &,std::vector<T> &)449   virtual void get_row(numeric_index_type /*i*/,
450                        std::vector<numeric_index_type> & /*indices*/,
451                        std::vector<T> & /*values*/) const
452   {
453     libmesh_not_implemented();
454   }
455 
456 protected:
457 
458   /**
459    * Protected implementation of the create_submatrix and reinit_submatrix
460    * routines.
461    *
462    * \note This function must be overridden in derived classes for it
463    * to work properly!
464    */
_get_submatrix(SparseMatrix<T> &,const std::vector<numeric_index_type> &,const std::vector<numeric_index_type> &,const bool)465   virtual void _get_submatrix(SparseMatrix<T> & /*submatrix*/,
466                               const std::vector<numeric_index_type> & /*rows*/,
467                               const std::vector<numeric_index_type> & /*cols*/,
468                               const bool /*reuse_submatrix*/) const
469   {
470     libmesh_not_implemented();
471   }
472 
473   /**
474    * The \p DofMap object associated with this object.
475    */
476   DofMap const * _dof_map;
477 
478   /**
479    * Flag indicating whether or not the matrix has been initialized.
480    */
481   bool _is_initialized;
482 };
483 
484 
485 
486 //-----------------------------------------------------------------------
487 // SparseMatrix inline members
488 
489 // For SGI MIPSpro this implementation must occur after
490 // the full specialization of the print() member.
491 //
492 // It's generally easier to define these friend functions in the header
493 // file.
494 template <typename T>
495 std::ostream & operator << (std::ostream & os, const SparseMatrix<T> & m)
496 {
497   m.print(os);
498   return os;
499 }
500 
501 
502 } // namespace libMesh
503 
504 
505 #endif // LIBMESH_SPARSE_MATRIX_H
506