Reference documentation for deal.II version 9.0.0
petsc_matrix_base.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2004 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/lac/petsc_matrix_base.h>
17 
18 #ifdef DEAL_II_WITH_PETSC
19 
20 # include <deal.II/lac/exceptions.h>
21 # include <deal.II/lac/petsc_compatibility.h>
22 # include <deal.II/lac/petsc_full_matrix.h>
23 # include <deal.II/lac/petsc_sparse_matrix.h>
24 # include <deal.II/lac/petsc_parallel_sparse_matrix.h>
25 # include <deal.II/lac/petsc_vector_base.h>
26 
27 DEAL_II_NAMESPACE_OPEN
28 
29 namespace PETScWrappers
30 {
31  namespace MatrixIterators
32  {
33  void
36  {
37  // if we are asked to visit the past-the-end line (or a line that is not
38  // stored on the current processor), then simply release all our caches
39  // and go on with life
40  if (matrix->in_local_range(this->a_row) == false)
41  {
42  colnum_cache.reset ();
43  value_cache.reset ();
44 
45  return;
46  }
47 
48  // get a representation of the present row
49  PetscInt ncols;
50  const PetscInt *colnums;
51  const PetscScalar *values;
52 
53  PetscErrorCode ierr = MatGetRow(*matrix, this->a_row, &ncols, &colnums,
54  &values);
55  AssertThrow (ierr == 0, ExcPETScError(ierr));
56 
57  // copy it into our caches if the line
58  // isn't empty. if it is, then we've
59  // done something wrong, since we
60  // shouldn't have initialized an
61  // iterator for an empty line (what
62  // would it point to?)
63  Assert (ncols != 0, ExcInternalError());
64  colnum_cache = std::make_shared<std::vector<size_type>> (colnums, colnums+ncols);
65  value_cache = std::make_shared<std::vector<PetscScalar>> (values, values+ncols);
66 
67  // and finally restore the matrix
68  ierr = MatRestoreRow(*matrix, this->a_row, &ncols, &colnums, &values);
69  AssertThrow (ierr == 0, ExcPETScError(ierr));
70  }
71  }
72 
73 
74 
76  :
77  matrix (nullptr),
78  last_action (VectorOperation::unknown)
79  {}
80 
81 
82 
84  {
86  }
87 
88 
89 
90  void
92  {
93  // destroy the matrix...
94  {
95  const PetscErrorCode ierr = destroy_matrix (matrix);
96  AssertThrow(ierr == 0, ExcPETScError(ierr));
97  }
98 
99  // ...and replace it by an empty
100  // sequential matrix
101  const int m=0, n=0, n_nonzero_per_row=0;
102  const PetscErrorCode ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, m, n,
103  n_nonzero_per_row,
104  nullptr, &matrix);
105  AssertThrow (ierr == 0, ExcPETScError(ierr));
106  }
107 
108 
109 
110  MatrixBase &
112  {
113  (void)d;
115 
117 
118  const PetscErrorCode ierr = MatZeroEntries (matrix);
119  AssertThrow (ierr == 0, ExcPETScError(ierr));
120 
121  return *this;
122  }
123 
124 
125 
126  void
128  const PetscScalar new_diag_value)
129  {
130  std::vector<size_type> rows (1, row);
131  clear_rows(rows, new_diag_value);
132  }
133 
134 
135 
136  void
137  MatrixBase::clear_rows (const std::vector<size_type> &rows,
138  const PetscScalar new_diag_value)
139  {
141 
142  // now set all the entries of these rows
143  // to zero
144  const std::vector<PetscInt> petsc_rows (rows.begin(), rows.end());
145 
146  // call the functions. note that we have
147  // to call them even if #rows is empty,
148  // since this is a collective operation
149  IS index_set;
150 
151  ISCreateGeneral (get_mpi_communicator(), rows.size(),
152  petsc_rows.data(), PETSC_COPY_VALUES, &index_set);
153 
154  const PetscErrorCode ierr = MatZeroRowsIS(matrix, index_set, new_diag_value,
155  nullptr, nullptr);
156  AssertThrow (ierr == 0, ExcPETScError(ierr));
157  ISDestroy (&index_set);
158  }
159 
160 
161 
162  PetscScalar
164  const size_type j) const
165  {
166  PetscInt petsc_i = i, petsc_j = j;
167 
168  PetscScalar value;
169 
170  const PetscErrorCode ierr = MatGetValues (matrix, 1, &petsc_i, 1, &petsc_j,
171  &value);
172  AssertThrow (ierr == 0, ExcPETScError(ierr));
173 
174  return value;
175  }
176 
177 
178 
179  PetscScalar
181  {
182  Assert (m() == n(), ExcNotQuadratic());
183 
184  // this doesn't seem to work any
185  // different than any other element
186  return el(i,i);
187  }
188 
189 
190 
191  void
193  {
194  {
195 #ifdef DEBUG
196 #ifdef DEAL_II_WITH_MPI
197  // Check that all processors agree that last_action is the same (or none!)
198 
199  int my_int_last_action = last_action;
200  int all_int_last_action;
201 
202  const int ierr = MPI_Allreduce
203  (&my_int_last_action, &all_int_last_action, 1, MPI_INT, MPI_BOR,
205  AssertThrowMPI(ierr);
206 
207  AssertThrow(all_int_last_action != (VectorOperation::add | VectorOperation::insert),
208  ExcMessage("Error: not all processors agree on the last "
209  "VectorOperation before this compress() call."));
210 #endif
211 #endif
212  }
213 
215  || last_action == operation,
216  ExcMessage("Missing compress() or calling with wrong VectorOperation argument."));
217 
218  // flush buffers
219  PetscErrorCode ierr = MatAssemblyBegin (matrix,MAT_FINAL_ASSEMBLY);
220  AssertThrow (ierr == 0, ExcPETScError(ierr));
221 
222  ierr = MatAssemblyEnd (matrix,MAT_FINAL_ASSEMBLY);
223  AssertThrow (ierr == 0, ExcPETScError(ierr));
224 
226  }
227 
228 
229 
231  MatrixBase::m () const
232  {
233  PetscInt n_rows, n_cols;
234 
235  const PetscErrorCode ierr = MatGetSize (matrix, &n_rows, &n_cols);
236  AssertThrow (ierr == 0, ExcPETScError(ierr));
237 
238  return n_rows;
239  }
240 
241 
242 
244  MatrixBase::n () const
245  {
246  PetscInt n_rows, n_cols;
247 
248  const PetscErrorCode ierr = MatGetSize (matrix, &n_rows, &n_cols);
249  AssertThrow (ierr == 0, ExcPETScError(ierr));
250 
251  return n_cols;
252  }
253 
254 
255 
258  {
259  PetscInt n_rows, n_cols;
260 
261  const PetscErrorCode ierr = MatGetLocalSize (matrix, &n_rows, &n_cols);
262  AssertThrow (ierr == 0, ExcPETScError(ierr));
263 
264  return n_rows;
265  }
266 
267 
268 
269  std::pair<MatrixBase::size_type, MatrixBase::size_type>
271  {
272  PetscInt begin, end;
273 
274  const PetscErrorCode ierr = MatGetOwnershipRange (static_cast<const Mat &>(matrix),
275  &begin, &end);
276  AssertThrow (ierr == 0, ExcPETScError(ierr));
277 
278  return std::make_pair (begin, end);
279  }
280 
281 
282 
285  {
286  MatInfo mat_info;
287  const PetscErrorCode ierr = MatGetInfo (matrix, MAT_GLOBAL_SUM, &mat_info);
288  AssertThrow (ierr == 0, ExcPETScError(ierr));
289 
290  return static_cast<size_type>(mat_info.nz_used);
291  }
292 
293 
294 
297  row_length (const size_type row) const
298  {
299 //TODO: this function will probably only work if compress() was called on the
300 //matrix previously. however, we can't do this here, since it would impose
301 //global communication and one would have to make sure that this function is
302 //called the same number of times from all processors, something that is
303 //unreasonable. there should simply be a way in PETSc to query the number of
304 //entries in a row bypassing the call to compress(), but I can't find one
305  Assert (row < m(), ExcInternalError());
306 
307  // get a representation of the present
308  // row
309  PetscInt ncols;
310  const PetscInt *colnums;
311  const PetscScalar *values;
312 
313 //TODO: this is probably horribly inefficient; we should lobby for a way to
314 //query this information from PETSc
315  PetscErrorCode ierr = MatGetRow(*this, row, &ncols, &colnums, &values);
316  AssertThrow (ierr == 0, ExcPETScError(ierr));
317 
318  // then restore the matrix and return the number of columns in this row as
319  // queried previously. Starting with PETSc 3.4, MatRestoreRow actually
320  // resets the last three arguments to zero/NULL, to avoid abuse of pointers
321  // now dangling. as a consequence, we need to save the size of the array
322  // and return the saved value.
323  const PetscInt ncols_saved = ncols;
324  ierr = MatRestoreRow(*this, row, &ncols, &colnums, &values);
325  AssertThrow (ierr == 0, ExcPETScError(ierr));
326 
327  return ncols_saved;
328  }
329 
330 
331  PetscReal
333  {
334  PetscReal result;
335 
336  const PetscErrorCode ierr = MatNorm (matrix, NORM_1, &result);
337  AssertThrow (ierr == 0, ExcPETScError(ierr));
338 
339  return result;
340  }
341 
342 
343 
344  PetscReal
346  {
347  PetscReal result;
348 
349  const PetscErrorCode ierr = MatNorm (matrix, NORM_INFINITY, &result);
350  AssertThrow (ierr == 0, ExcPETScError(ierr));
351 
352  return result;
353  }
354 
355 
356 
357  PetscReal
359  {
360  PetscReal result;
361 
362  const PetscErrorCode ierr = MatNorm (matrix, NORM_FROBENIUS, &result);
363  AssertThrow (ierr == 0, ExcPETScError(ierr));
364 
365  return result;
366  }
367 
368 
369  PetscScalar
371  {
372  VectorBase tmp(v);
373  vmult(tmp, v);
374  return tmp*v;
375  }
376 
377 
378  PetscScalar
380  const VectorBase &v) const
381  {
382  VectorBase tmp(u);
383  vmult(tmp, v);
384  return u*tmp;
385  }
386 
387 
388  PetscScalar
390  {
391  PetscScalar result;
392 
393  const PetscErrorCode ierr = MatGetTrace (matrix, &result);
394  AssertThrow (ierr == 0, ExcPETScError(ierr));
395 
396  return result;
397  }
398 
399 
400 
401  MatrixBase &
402  MatrixBase::operator *= (const PetscScalar a)
403  {
404  const PetscErrorCode ierr = MatScale (matrix, a);
405  AssertThrow (ierr == 0, ExcPETScError(ierr));
406 
407  return *this;
408  }
409 
410 
411 
412  MatrixBase &
413  MatrixBase::operator /= (const PetscScalar a)
414  {
415  const PetscScalar factor = 1./a;
416  const PetscErrorCode ierr = MatScale (matrix, factor);
417  AssertThrow (ierr == 0, ExcPETScError(ierr));
418 
419  return *this;
420  }
421 
422 
423  MatrixBase &
424  MatrixBase::add (const PetscScalar factor,
425  const MatrixBase &other)
426  {
427  const PetscErrorCode ierr = MatAXPY (matrix, factor,
428  other, DIFFERENT_NONZERO_PATTERN);
429  AssertThrow (ierr == 0, ExcPETScError(ierr));
430 
431  return *this;
432  }
433 
434 
435 
436  MatrixBase &
438  const PetscScalar factor)
439  {
440  return add(factor, other);
441  }
442 
443 
444  void
446  const VectorBase &src) const
447  {
448  Assert (&src != &dst, ExcSourceEqualsDestination());
449 
450  const PetscErrorCode ierr = MatMult (matrix, src, dst);
451  AssertThrow (ierr == 0, ExcPETScError(ierr));
452  }
453 
454 
455 
456  void
458  const VectorBase &src) const
459  {
460  Assert (&src != &dst, ExcSourceEqualsDestination());
461 
462  const PetscErrorCode ierr = MatMultTranspose (matrix, src, dst);
463  AssertThrow (ierr == 0, ExcPETScError(ierr));
464  }
465 
466 
467 
468  void
470  const VectorBase &src) const
471  {
472  Assert (&src != &dst, ExcSourceEqualsDestination());
473 
474  const PetscErrorCode ierr = MatMultAdd (matrix, src, dst, dst);
475  AssertThrow (ierr == 0, ExcPETScError(ierr));
476  }
477 
478 
479 
480  void
482  const VectorBase &src) const
483  {
484  Assert (&src != &dst, ExcSourceEqualsDestination());
485 
486  const PetscErrorCode ierr = MatMultTransposeAdd (matrix, src, dst, dst);
487  AssertThrow (ierr == 0, ExcPETScError(ierr));
488  }
489 
490 
491  namespace internals
492  {
493  void perform_mmult (const MatrixBase &inputleft,
494  const MatrixBase &inputright,
495  MatrixBase &result,
496  const VectorBase &V,
497  const bool transpose_left)
498  {
499  const bool use_vector = (V.size() == inputright.m() ? true : false);
500  if (transpose_left == false)
501  {
502  Assert (inputleft.n() == inputright.m(),
503  ExcDimensionMismatch(inputleft.n(), inputright.m()));
504  }
505  else
506  {
507  Assert (inputleft.m() == inputright.m(),
508  ExcDimensionMismatch(inputleft.m(), inputright.m()));
509  }
510 
511  result.clear();
512 
513  PetscErrorCode ierr;
514 
515  if (use_vector == false)
516  {
517  if (transpose_left)
518  {
519  ierr = MatTransposeMatMult (inputleft,
520  inputright,
521  MAT_INITIAL_MATRIX,
522  PETSC_DEFAULT,
523  &result.petsc_matrix());
524  AssertThrow (ierr == 0, ExcPETScError(ierr));
525  }
526  else
527  {
528  ierr = MatMatMult (inputleft,
529  inputright,
530  MAT_INITIAL_MATRIX,
531  PETSC_DEFAULT,
532  &result.petsc_matrix());
533  AssertThrow (ierr == 0, ExcPETScError(ierr));
534  }
535  }
536  else
537  {
538  Mat tmp;
539  ierr = MatDuplicate (inputleft, MAT_COPY_VALUES, &tmp);
540  AssertThrow (ierr == 0, ExcPETScError(ierr));
541  if (transpose_left)
542  {
543 #if DEAL_II_PETSC_VERSION_LT(3,8,0)
544  ierr = MatTranspose(tmp, MAT_REUSE_MATRIX, &tmp);
545 #else
546  ierr = MatTranspose(tmp, MAT_INPLACE_MATRIX, &tmp);
547 #endif
548  AssertThrow (ierr == 0, ExcPETScError(ierr));
549  }
550  ierr = MatDiagonalScale (tmp, nullptr, V);
551  AssertThrow (ierr == 0, ExcPETScError(ierr));
552  ierr = MatMatMult (tmp,
553  inputright,
554  MAT_INITIAL_MATRIX,
555  PETSC_DEFAULT,
556  &result.petsc_matrix());
557  AssertThrow (ierr == 0, ExcPETScError(ierr));
558  }
559  }
560  }
561 
562  void
564  const MatrixBase &B,
565  const VectorBase &V) const
566  {
567  internals::perform_mmult (*this, B, C, V, false);
568  }
569 
570  void
572  const MatrixBase &B,
573  const VectorBase &V) const
574  {
575  internals::perform_mmult (*this, B, C, V, true);
576  }
577 
578  PetscScalar
580  const VectorBase &x,
581  const VectorBase &b) const
582  {
583  // avoid the use of a temporary, and
584  // rather do one negation pass more than
585  // necessary
586  vmult (dst, x);
587  dst -= b;
588  dst *= -1;
589 
590  return dst.l2_norm();
591  }
592 
593 
594 
595  MatrixBase::operator Mat () const
596  {
597  return matrix;
598  }
599 
601  {
602  return matrix;
603  }
604 
605  void
607  {
608  const PetscErrorCode ierr = MatTranspose(matrix, MAT_REUSE_MATRIX, &matrix);
609  AssertThrow (ierr == 0, ExcPETScError(ierr));
610  }
611 
612  PetscBool
613  MatrixBase::is_symmetric (const double tolerance)
614  {
615  PetscBool truth;
617  const PetscErrorCode ierr = MatIsSymmetric (matrix, tolerance, &truth);
618  AssertThrow (ierr == 0, ExcPETScError(ierr));
619  return truth;
620  }
621 
622  PetscBool
623  MatrixBase::is_hermitian (const double tolerance)
624  {
625  PetscBool truth;
626 
628  const PetscErrorCode ierr = MatIsHermitian (matrix, tolerance, &truth);
629  AssertThrow (ierr == 0, ExcPETScError(ierr));
630 
631  return truth;
632  }
633 
634  void
635  MatrixBase::write_ascii (const PetscViewerFormat format)
636  {
638 
639  // Set options
640  PetscErrorCode ierr = PetscViewerSetFormat (PETSC_VIEWER_STDOUT_WORLD,
641  format);
642  AssertThrow (ierr == 0, ExcPETScError(ierr));
643 
644  // Write to screen
645  ierr = MatView (matrix, PETSC_VIEWER_STDOUT_WORLD);
646  AssertThrow (ierr == 0, ExcPETScError(ierr));
647  }
648 
649  void
650  MatrixBase::print (std::ostream &out,
651  const bool /*alternative_output*/) const
652  {
653  std::pair<MatrixBase::size_type, MatrixBase::size_type>
654  loc_range = local_range();
655 
656  PetscInt ncols;
657  const PetscInt *colnums;
658  const PetscScalar *values;
659 
661  for (row = loc_range.first; row < loc_range.second; ++row)
662  {
663  PetscErrorCode ierr = MatGetRow(*this, row, &ncols, &colnums, &values);
664  AssertThrow (ierr == 0, ExcPETScError(ierr));
665 
666  for (PetscInt col = 0; col < ncols; ++col)
667  {
668  out << "(" << row << "," << colnums[col] << ") " << values[col] << std::endl;
669  }
670 
671  ierr = MatRestoreRow(*this, row, &ncols, &colnums, &values);
672  AssertThrow (ierr == 0, ExcPETScError(ierr));
673  }
674 
675  AssertThrow (out, ExcIO());
676  }
677 
678 
679 
680  std::size_t
682  {
683  MatInfo info;
684  const PetscErrorCode ierr = MatGetInfo(matrix, MAT_LOCAL, &info);
685  AssertThrow (ierr == 0, ExcPETScError(ierr));
686 
687  return sizeof(*this) + static_cast<size_type>(info.memory);
688  }
689 
690 }
691 
692 DEAL_II_NAMESPACE_CLOSE
693 
694 #endif // DEAL_II_WITH_PETSC
PetscErrorCode destroy_matrix(Mat &matrix)
void Tmmult(MatrixBase &C, const MatrixBase &B, const VectorBase &V) const
Contents is actually a matrix.
PetscScalar matrix_scalar_product(const VectorBase &u, const VectorBase &v) const
void add(const size_type i, const size_type j, const PetscScalar value)
static ::ExceptionBase & ExcIO()
void vmult(VectorBase &dst, const VectorBase &src) const
const_iterator begin() const
PetscReal frobenius_norm() const
static ::ExceptionBase & ExcScalarAssignmentOnlyForZeroValue()
size_type row_length(const size_type row) const
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
PetscBool is_symmetric(const double tolerance=1.e-12)
PetscBool is_hermitian(const double tolerance=1.e-12)
void clear_rows(const std::vector< size_type > &rows, const PetscScalar new_diag_value=0)
void compress(const VectorOperation::values operation)
size_type n_nonzero_elements() const
MatrixBase & operator=(const MatrixBase &)=delete
static ::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1142
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
void vmult_add(VectorBase &dst, const VectorBase &src) const
PetscScalar residual(VectorBase &dst, const VectorBase &x, const VectorBase &b) const
void mmult(MatrixBase &C, const MatrixBase &B, const VectorBase &V) const
types::global_dof_index size_type
PetscScalar diag_element(const size_type i) const
void Tvmult(VectorBase &dst, const VectorBase &src) const
PetscScalar el(const size_type i, const size_type j) const
void Tvmult_add(VectorBase &dst, const VectorBase &src) const
const_iterator end() const
void print(std::ostream &out, const bool alternative_output=false) const
static ::ExceptionBase & ExcNotQuadratic()
void write_ascii(const PetscViewerFormat format=PETSC_VIEWER_DEFAULT)
VectorOperation::values last_action
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1314
MatrixBase & operator*=(const PetscScalar factor)
std::pair< size_type, size_type > local_range() const
PetscScalar matrix_norm_square(const VectorBase &v) const
MatrixBase & operator/=(const PetscScalar factor)
static ::ExceptionBase & ExcSourceEqualsDestination()
virtual const MPI_Comm & get_mpi_communicator() const =0
void clear_row(const size_type row, const PetscScalar new_diag_value=0)
std::size_t memory_consumption() const
static ::ExceptionBase & ExcInternalError()