HermesCommon  3.0
matrix.cpp
Go to the documentation of this file.
1 // This file is part of HermesCommon
2 //
3 // Copyright (c) 2009 hp-FEM group at the University of Nevada, Reno (UNR).
4 // Email: hpfem-group@unr.edu, home page: http://www.hpfem.org/.
5 //
6 // Hermes2D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the License,
9 // or (at your option) any later version.
10 //
11 // Hermes2D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with Hermes2D; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "common.h"
23 #include "matrix.h"
24 #include "callstack.h"
25 #include "util/memory_handling.h"
26 
35 #include "qsort.h"
36 #include "api.h"
37 
38 namespace Hermes
39 {
40  namespace Algebra
41  {
42  template<typename Scalar>
43  Matrix<Scalar>::Matrix(unsigned int size) : size(size)
44  {
45  }
46 
47  template<typename Scalar>
48  void Matrix<Scalar>::set_row_zero(unsigned int n)
49  {
50  throw Hermes::Exceptions::MethodNotOverridenException("Matrix<Scalar>::set_row_zero");
51  }
52 
53  template<typename Scalar>
55  {
56  for (unsigned int i = 0; i < this->size; i++)
57  {
58  add(i, i, v);
59  }
60  };
61 
62  template<typename Scalar>
63  void Matrix<Scalar>::multiply_with_vector(Scalar* vector_in, Scalar*& vector_out, bool vector_out_initialized) const
64  {
65  if (!vector_out_initialized)
66  vector_out = malloc_with_check<Scalar>(this->size);
67  for (unsigned int i = 0; i < this->size; i++)
68  {
69  vector_out[i] = Scalar(0.);
70  for (unsigned int j = 0; j < this->size; j++)
71  vector_out[i] += this->get(i, j) * vector_in[j];
72  }
73  }
74 
75  template<typename Scalar>
77  {
78  throw Hermes::Exceptions::MethodNotOverridenException("multiply_with_Scalar()");
79  }
80 
81  template<typename Scalar>
82  unsigned int Matrix<Scalar>::get_size() const
83  {
84  return this->size;
85  };
86 
87  template<>
88  void Matrix<double>::add(unsigned int m, unsigned int n, double *mat, int *rows, int *cols, const int size)
89  {
90  for (unsigned int i = 0; i < m; i++)
91  {
92  for (unsigned int j = 0; j < n; j++)
93  {
94  double entry = mat[i * size + j];
95  if (entry != 0.)
96  {
97  if (rows[i] >= 0 && cols[j] >= 0) // not Dir. dofs.
98  add(rows[i], cols[j], entry);
99  }
100  }
101  }
102  }
103 
104  template<>
105  void Matrix<std::complex<double> >::add(unsigned int m, unsigned int n, std::complex<double>* mat, int *rows, int *cols, const int size)
106  {
107  for (unsigned int i = 0; i < m; i++)
108  {
109  for (unsigned int j = 0; j < n; j++)
110  {
111  std::complex<double> entry = mat[i * size + j];
112  if (entry != 0.)
113  {
114  if (rows[i] >= 0 && cols[j] >= 0) // not Dir. dofs.
115  add(rows[i], cols[j], mat[i * size + j]);
116  }
117  }
118  }
119  }
120 
121  template<typename Scalar>
123  {
124  pages = nullptr;
125  next_pages = nullptr;
126  }
127 
128  template<typename Scalar>
130  {
131  this->size = size;
132  pages = nullptr;
133  next_pages = nullptr;
134  }
135 
136  template<typename Scalar>
138  {
139  this->free();
140  }
141 
142  template<typename Scalar>
144  {
145  if (pages)
146  {
147  free_with_check(pages);
148  }
149 
150  if (next_pages)
151  {
152  for (unsigned int i = 0; i < this->size; i++)
153  delete next_pages[i];
154  free_with_check(next_pages);
155  }
156  }
157 
158  template<typename Scalar>
160  {
161  }
162 
163  template<typename Scalar>
164  int SparseMatrix<Scalar>::get_num_row_entries(unsigned int row) const
165  {
166  return -1;
167  }
168 
169  template<typename Scalar>
170  void SparseMatrix<Scalar>::extract_row_copy(unsigned int row, unsigned int len,
171  unsigned int &n_entries, double *vals,
172  unsigned int *idxs) const
173  {
174  }
175 
176  template<typename Scalar>
177  int SparseMatrix<Scalar>::get_num_col_entries(unsigned int col) const
178  {
179  return -1;
180  }
181 
182  template<typename Scalar>
183  void SparseMatrix<Scalar>::extract_col_copy(unsigned int col, unsigned int len,
184  unsigned int &n_entries, double *vals,
185  unsigned int *idxs) const
186  {
187  }
188 
189  template<typename Scalar>
191  {
192  add_as_block(0, 0, mat);
193  }
194 
195  template<typename Scalar>
197  {
198  int ndof = mat->get_size();
199  if (this->get_size() != (unsigned int)num_stages * ndof)
200  throw Hermes::Exceptions::Exception("Incompatible matrix sizes in SparseMatrix<Scalar>::add_to_diagonal_blocks()");
201 
202  for (int i = 0; i < num_stages; i++)
203  this->add_as_block(ndof*i, ndof*i, mat);
204  }
205 
206  template<typename Scalar>
207  void SparseMatrix<Scalar>::add_as_block(unsigned int offset_i, unsigned int offset_j, SparseMatrix<Scalar>* mat)
208  {
209  if ((this->get_size() < offset_i + mat->get_size()) || (this->get_size() < offset_j + mat->get_size()))
210  throw Hermes::Exceptions::Exception("Incompatible matrix sizes in SparseMatrix<Scalar>::add_as_block()");
211  unsigned int block_size = mat->get_size();
212  for (unsigned int r = 0; r < block_size; r++)
213  {
214  for (unsigned int c = 0; c < block_size; c++)
215  {
216  this->add(offset_i + r, offset_j + c, mat->get(r, c));
217  }
218  }
219  }
220 
221  template<typename Scalar>
223  {
224  throw Hermes::Exceptions::MethodNotOverridenException("SparseMatrix* duplicate()");
225  }
226 
227  template<typename Scalar>
228  unsigned int SparseMatrix<Scalar>::get_nnz() const
229  {
231  return 0;
232  }
233 
234  template<typename Scalar>
235  void SparseMatrix<Scalar>::prealloc(unsigned int n)
236  {
237  this->size = n;
238  pages = malloc_with_check<SparseMatrix<Scalar>, Page>(n, this);
239  }
240 
241  template<typename Scalar>
242  void SparseMatrix<Scalar>::pre_add_ij(unsigned int row, unsigned int col)
243  {
244  if (pages[col].count >= PAGE_SIZE)
245  {
246  Page* final_page = &(pages[col]);
247  while (final_page->next != nullptr && final_page->count >= PAGE_SIZE)
248  final_page = final_page->next;
249 
250  if (final_page->next == nullptr && final_page->count >= PAGE_SIZE)
251  {
252  final_page->next = new Page(true);
253  final_page = final_page->next;
254  }
255  final_page->idx[final_page->count++] = row;
256  }
257  else
258  pages[col].idx[pages[col].count++] = row;
259  }
260 
261  template<typename Scalar>
262  int SparseMatrix<Scalar>::sort_and_store_indices(Page *page, int *buffer, int *max)
263  {
264  // gather all pages in the buffer, deleting them along the way
265  int *end = buffer;
266  while (page != nullptr)
267  {
268  memcpy(end, page->idx, sizeof(int)* page->count);
269  end += page->count;
270  Page *tmp = page;
271  page = page->next;
272  if (tmp->dyn_stored)
273  delete tmp;
274  }
275 
276  // sort the indices and remove duplicities
277  qsort_int(buffer, end - buffer);
278  int *q = buffer;
279  for (int *p = buffer, last = -1; p < end; p++)
280  if (*p != last)
281  *q++ = last = *p;
282 
283  return q - buffer;
284  }
285 
286  template<typename Scalar>
288  {
289  int total = 0;
290  for (unsigned int i = 0; i < this->size; i++)
291  for (Page *page = &pages[i]; page != nullptr; page = page->next)
292  total += page->count;
293 
294  return total;
295  }
296 
297  template<>
298  HERMES_API SparseMatrix<double>* create_matrix(bool use_direct_solver)
299  {
300  switch (use_direct_solver ? Hermes::HermesCommonApi.get_integral_param_value(Hermes::directMatrixSolverType) : Hermes::HermesCommonApi.get_integral_param_value(Hermes::matrixSolverType))
301  {
302  case Hermes::SOLVER_EXTERNAL:
303  {
304  return new CSCMatrix < double > ;
305  }
306 
307  case Hermes::SOLVER_AMESOS:
308  {
309 #if defined HAVE_AMESOS && defined HAVE_EPETRA
310  return new EpetraMatrix < double > ;
311 #else
312  throw Hermes::Exceptions::Exception("Amesos not installed.");
313 #endif
314  break;
315  }
316  case Hermes::SOLVER_AZTECOO:
317  {
318  if (use_direct_solver)
319  throw Hermes::Exceptions::Exception("The iterative solver AztecOO selected as a direct solver.");
320 #if defined HAVE_AZTECOO && defined HAVE_EPETRA
321  return new EpetraMatrix < double > ;
322 #else
323  throw Hermes::Exceptions::Exception("AztecOO not installed.");
324 #endif
325  break;
326  }
327  case Hermes::SOLVER_MUMPS:
328  {
329 #ifdef WITH_MUMPS
330  return new MumpsMatrix < double > ;
331 #else
332  throw Hermes::Exceptions::Exception("MUMPS not installed.");
333 #endif
334  break;
335  }
336  case Hermes::SOLVER_PETSC:
337  {
338  if (use_direct_solver)
339  throw Hermes::Exceptions::Exception("The iterative solver PETSc selected as a direct solver.");
340 #ifdef WITH_PETSC
341  return new PetscMatrix < double > ;
342 #else
343  throw Hermes::Exceptions::Exception("PETSc not installed.");
344 #endif
345  break;
346  }
347  case Hermes::SOLVER_UMFPACK:
348  {
349 #ifdef WITH_UMFPACK
350  return new CSCMatrix < double > ;
351 #else
352  throw Hermes::Exceptions::Exception("UMFPACK was not installed.");
353 #endif
354  break;
355  }
356  case Hermes::SOLVER_PARALUTION_ITERATIVE:
357  case Hermes::SOLVER_PARALUTION_AMG:
358  {
359  if (use_direct_solver)
360  throw Hermes::Exceptions::Exception("The iterative solver PARALUTION selected as a direct solver.");
361 #ifdef WITH_PARALUTION
362  return new ParalutionMatrix < double > ;
363 #else
364  throw Hermes::Exceptions::Exception("PARALUTION was not installed.");
365 #endif
366  break;
367  }
368  case Hermes::SOLVER_SUPERLU:
369  {
370 #ifdef WITH_SUPERLU
371  return new CSCMatrix < double > ;
372 #else
373  throw Hermes::Exceptions::Exception("SuperLU was not installed.");
374 #endif
375  break;
376  }
377  default:
378  throw Hermes::Exceptions::Exception("Unknown matrix solver requested in create_matrix().");
379  }
380  return nullptr;
381  }
382 
383  template<>
384  HERMES_API SparseMatrix<std::complex<double> >* create_matrix(bool use_direct_solver)
385  {
386  switch (use_direct_solver ? Hermes::HermesCommonApi.get_integral_param_value(Hermes::directMatrixSolverType) : Hermes::HermesCommonApi.get_integral_param_value(Hermes::matrixSolverType))
387  {
388  case Hermes::SOLVER_EXTERNAL:
389  {
390  return new CSCMatrix < std::complex<double> > ;
391  }
392  case Hermes::SOLVER_AMESOS:
393  {
394 #if defined HAVE_AMESOS && defined HAVE_EPETRA
396 #else
397  throw Hermes::Exceptions::Exception("Amesos not installed.");
398 #endif
399  break;
400  }
401  case Hermes::SOLVER_AZTECOO:
402  {
403  if (use_direct_solver)
404  throw Hermes::Exceptions::Exception("The iterative solver AztecOO selected as a direct solver.");
405 #if defined HAVE_AZTECOO && defined HAVE_EPETRA
407 #else
408  throw Hermes::Exceptions::Exception("AztecOO not installed.");
409 #endif
410  break;
411  }
412  case Hermes::SOLVER_MUMPS:
413  {
414 #ifdef WITH_MUMPS
416 #else
417  throw Hermes::Exceptions::Exception("MUMPS not installed.");
418 #endif
419  break;
420  }
421  case Hermes::SOLVER_PETSC:
422  {
423  if (use_direct_solver)
424  throw Hermes::Exceptions::Exception("The iterative solver PETSc selected as a direct solver.");
425 #ifdef WITH_PETSC
426  return new PetscMatrix < std::complex<double> > ;
427 #else
428  throw Hermes::Exceptions::Exception("PETSc not installed.");
429 #endif
430  break;
431  }
432  case Hermes::SOLVER_UMFPACK:
433  {
434 #ifdef WITH_UMFPACK
435  return new CSCMatrix < std::complex<double> > ;
436 #else
437  throw Hermes::Exceptions::Exception("UMFPACK was not installed.");
438 #endif
439  break;
440  }
441  case Hermes::SOLVER_PARALUTION_ITERATIVE:
442  case Hermes::SOLVER_PARALUTION_AMG:
443  {
444  if (use_direct_solver)
445  throw Hermes::Exceptions::Exception("The iterative solver PARALUTION selected as a direct solver.");
446 #ifdef WITH_PARALUTION
447  throw Hermes::Exceptions::Exception("PARALUTION works only for real problems.");
448 #else
449  throw Hermes::Exceptions::Exception("PARALUTION was not installed.");
450 #endif
451  break;
452  }
453  case Hermes::SOLVER_SUPERLU:
454  {
455 #ifdef WITH_SUPERLU
456  return new CSCMatrix < std::complex<double> > ;
457 #else
458  throw Hermes::Exceptions::Exception("SuperLU was not installed.");
459 #endif
460  break;
461  }
462  default:
463  throw Hermes::Exceptions::Exception("Unknown matrix solver requested in create_matrix().");
464  }
465  return nullptr;
466  }
467 
468  template class Matrix < double > ;
469  template class Matrix < std::complex<double> > ;
470 
471  template class SparseMatrix < double > ;
472  template class SparseMatrix < std::complex<double> > ;
473  }
474 }
General (abstract) matrix representation in Hermes.
Definition: matrix.h:36
virtual unsigned int get_size() const
Definition: matrix.cpp:82
virtual void add_to_diagonal(Scalar v)
Add a number to each diagonal entry.
Definition: matrix.cpp:54
AmesosSolver class as an interface to Amesos.
General namespace for the Hermes library.
bool dyn_stored
this page is stored in the dynamically allocated part.
Definition: matrix.h:201
Linear matrix solver functionality.
virtual void extract_col_copy(unsigned int col, unsigned int len, unsigned int &n_entries, double *vals, unsigned int *idxs) const
Definition: matrix.cpp:183
Exception interface Basically a std::exception, but with a constructor with string and with print_msg...
Definition: exceptions.h:49
Main Hermes API.
PARALUTION solver interface.
HERMES_API SparseMatrix< Scalar > * create_matrix(bool use_direct_solver=false)
Function returning a matrix according to the users's choice.
Definition: matrix.cpp:298
File containing common definitions, and basic global enums etc. for HermesCommon. ...
virtual void multiply_with_Scalar(Scalar value)
Multiply with a Scalar.
Definition: matrix.cpp:76
General (abstract) sparse matrix representation in Hermes.
virtual void set_row_zero(unsigned int n)
Definition: matrix.cpp:48
AztecOOSolver class as an interface to AztecOO.
General CSC Matrix class. (can be used in umfpack, in that case use the CSCMatrix subclass...
Definition: cs_matrix.h:131
HERMES_COMMON_API Hermes::Api HermesCommonApi
Global instance used inside Hermes which is also accessible to users.
Definition: api.cpp:158
virtual unsigned int get_nnz() const
Definition: matrix.cpp:228
virtual void add_sparse_to_diagonal_blocks(int num_stages, SparseMatrix< Scalar > *mat)
Definition: matrix.cpp:196
int idx[PAGE_SIZE]
buffer for storing indices
Definition: matrix.h:197
General Paralution matrix.
int sort_and_store_indices(Page *page, int *buffer, int *max)
Definition: matrix.cpp:262
Matrix used with MUMPS solver.
Definition: mumps_solver.h:77
virtual void add_sparse_matrix(SparseMatrix< Scalar > *mat)
Definition: matrix.cpp:190
File containing functionality for investigating call stack.
virtual int get_num_row_entries(unsigned int row) const
Definition: matrix.cpp:164
Basic matrix classes and operations.
UMFPACK solver interface.
unsigned char count
number of indices stored
Definition: matrix.h:193
virtual void multiply_with_vector(Scalar *vector_in, Scalar *&vector_out, bool vector_out_initialized=false) const
Multiply with a vector.
Definition: matrix.cpp:63
MUMPS solver interface.
virtual void prealloc(unsigned int n)
Definition: matrix.cpp:235
Structure for storing indices in sparse matrix.
Definition: matrix.h:191
The QuickSort routine from glibc-2.5 modified for sorting int arrays.
virtual SparseMatrix< Scalar > * duplicate() const
Duplicate sparse matrix (including allocation).
Definition: matrix.cpp:222
virtual Scalar get(unsigned int m, unsigned int n) const =0
virtual void free()
free the memory associated with stiffness matrix
Definition: matrix.cpp:143
Method is not overriden and should be.
Definition: exceptions.h:201
Matrix(unsigned int size=0)
Definition: matrix.cpp:43
PETSc solver interface.
File containing common definitions, and basic global enums etc. for HermesCommon. ...
virtual void pre_add_ij(unsigned int row, unsigned int col)
Definition: matrix.cpp:242
SuperLU solver interface.
virtual void extract_row_copy(unsigned int row, unsigned int len, unsigned int &n_entries, double *vals, unsigned int *idxs) const
Definition: matrix.cpp:170
virtual void add_as_block(unsigned int i, unsigned int j, SparseMatrix< Scalar > *mat)
Definition: matrix.cpp:207
virtual int get_num_col_entries(unsigned int col) const
Definition: matrix.cpp:177
Page * next
pointer to next page
Definition: matrix.h:199
virtual void add(unsigned int m, unsigned int n, Scalar v)=0
virtual void finish()
Finish manipulation with matrix (called before solving)
Definition: matrix.cpp:159