libmesh解析
本工作只是尝试解析原libmesh的代码,供学习使用
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 
petsc_matrix.C
浏览该文件的文档.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2023 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 #include "libmesh/libmesh_config.h"
21 
22 #ifdef LIBMESH_HAVE_PETSC
23 
24 // Local includes
25 #include "libmesh/petsc_matrix.h"
26 #include "libmesh/dof_map.h"
27 #include "libmesh/dense_matrix.h"
28 #include "libmesh/petsc_vector.h"
29 #include "libmesh/parallel.h"
30 #include "libmesh/utility.h"
31 #include "libmesh/wrapped_petsc.h"
32 
33 // C++ includes
34 #ifdef LIBMESH_HAVE_UNISTD_H
35 #include <unistd.h> // mkstemp
36 #endif
37 #include <fstream>
38 
39 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE
40 
41 namespace
42 {
43 using namespace libMesh;
44 
45 // historic libMesh n_nz & n_oz arrays are set up for PETSc's AIJ format.
46 // however, when the blocksize is >1, we need to transform these into
47 // their BAIJ counterparts.
48 inline
49 void transform_preallocation_arrays (const PetscInt blocksize,
50  const std::vector<numeric_index_type> & n_nz,
51  const std::vector<numeric_index_type> & n_oz,
52  std::vector<numeric_index_type> & b_n_nz,
53  std::vector<numeric_index_type> & b_n_oz)
54 {
55  libmesh_assert_equal_to (n_nz.size(), n_oz.size());
56  libmesh_assert_equal_to (n_nz.size()%blocksize, 0);
57 
58  b_n_nz.clear(); b_n_nz.reserve(n_nz.size()/blocksize);
59  b_n_oz.clear(); b_n_oz.reserve(n_oz.size()/blocksize);
60 
61  for (std::size_t nn=0, nnzs=n_nz.size(); nn<nnzs; nn += blocksize)
62  {
63  b_n_nz.push_back (n_nz[nn]/blocksize);
64  b_n_oz.push_back (n_oz[nn]/blocksize);
65  }
66 }
67 }
68 
69 #endif
70 
71 
72 
73 namespace libMesh
74 {
75 
76 
77 //-----------------------------------------------------------------------
78 // PetscMatrix members
79 
80 
81 // Constructor
82 template <typename T>
83 PetscMatrix<T>::PetscMatrix(const Parallel::Communicator & comm_in) :
84  SparseMatrix<T>(comm_in),
85  _mat(nullptr),
86  _destroy_mat_on_exit(true),
87  _mat_type(AIJ)
88 {}
89 
90 
91 
92 // Constructor taking an existing Mat but not the responsibility
93 // for destroying it
94 template <typename T>
96  const Parallel::Communicator & comm_in) :
97  SparseMatrix<T>(comm_in),
98  _destroy_mat_on_exit(false),
99  _mat_type(AIJ)
100 {
101  this->_mat = mat_in;
102  this->_is_initialized = true;
103 }
104 
105 
106 
107 // Destructor
108 template <typename T>
110 {
111  this->clear();
112 }
113 
114 template <typename T>
116 {
117  _mat_type = mat_type;
118 }
119 
120 template <typename T>
122  const numeric_index_type n_in,
123  const numeric_index_type m_l,
124  const numeric_index_type n_l,
125  const numeric_index_type nnz,
126  const numeric_index_type noz,
127  const numeric_index_type blocksize_in)
128 {
129  // So compilers don't warn when !LIBMESH_ENABLE_BLOCKED_STORAGE
130  libmesh_ignore(blocksize_in);
131 
132  // Clear initialized matrices
133  if (this->initialized())
134  this->clear();
135 
136  this->_is_initialized = true;
137 
138 
139  PetscErrorCode ierr = 0;
140  PetscInt m_global = static_cast<PetscInt>(m_in);
141  PetscInt n_global = static_cast<PetscInt>(n_in);
142  PetscInt m_local = static_cast<PetscInt>(m_l);
143  PetscInt n_local = static_cast<PetscInt>(n_l);
144  PetscInt n_nz = static_cast<PetscInt>(nnz);
145  PetscInt n_oz = static_cast<PetscInt>(noz);
146 
147  ierr = MatCreate(this->comm().get(), &_mat);
148  LIBMESH_CHKERR(ierr);
149  ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global);
150  LIBMESH_CHKERR(ierr);
151  PetscInt blocksize = static_cast<PetscInt>(blocksize_in);
152  ierr = MatSetBlockSize(_mat,blocksize);
153  LIBMESH_CHKERR(ierr);
154 
155 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE
156  if (blocksize > 1)
157  {
158  // specified blocksize, bs>1.
159  // double check sizes.
160  libmesh_assert_equal_to (m_local % blocksize, 0);
161  libmesh_assert_equal_to (n_local % blocksize, 0);
162  libmesh_assert_equal_to (m_global % blocksize, 0);
163  libmesh_assert_equal_to (n_global % blocksize, 0);
164  libmesh_assert_equal_to (n_nz % blocksize, 0);
165  libmesh_assert_equal_to (n_oz % blocksize, 0);
166 
167  ierr = MatSetType(_mat, MATBAIJ); // Automatically chooses seqbaij or mpibaij
168  LIBMESH_CHKERR(ierr);
169 
170  // MatSetFromOptions needs to happen before Preallocation routines
171  // since MatSetFromOptions can change matrix type and remove incompatible
172  // preallocation
173  ierr = MatSetOptionsPrefix(_mat, "");
174  LIBMESH_CHKERR(ierr);
175  ierr = MatSetFromOptions(_mat);
176  LIBMESH_CHKERR(ierr);
177  ierr = MatSeqBAIJSetPreallocation(_mat, blocksize, n_nz/blocksize, NULL);
178  LIBMESH_CHKERR(ierr);
179  ierr = MatMPIBAIJSetPreallocation(_mat, blocksize,
180  n_nz/blocksize, NULL,
181  n_oz/blocksize, NULL);
182  LIBMESH_CHKERR(ierr);
183  }
184  else
185 #endif
186  {
187  switch (_mat_type) {
188  case AIJ:
189  ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij
190  LIBMESH_CHKERR(ierr);
191 
192  // MatSetFromOptions needs to happen before Preallocation routines
193  // since MatSetFromOptions can change matrix type and remove incompatible
194  // preallocation
195  ierr = MatSetOptionsPrefix(_mat, "");
196  LIBMESH_CHKERR(ierr);
197  ierr = MatSetFromOptions(_mat);
198  LIBMESH_CHKERR(ierr);
199  ierr = MatSeqAIJSetPreallocation(_mat, n_nz, NULL);
200  LIBMESH_CHKERR(ierr);
201  ierr = MatMPIAIJSetPreallocation(_mat, n_nz, NULL, n_oz, NULL);
202  LIBMESH_CHKERR(ierr);
203  break;
204 
205  case HYPRE:
206 #if !PETSC_VERSION_LESS_THAN(3,9,4) && LIBMESH_HAVE_PETSC_HYPRE
207  ierr = MatSetType(_mat, MATHYPRE);
208 
209  // MatSetFromOptions needs to happen before Preallocation routines
210  // since MatSetFromOptions can change matrix type and remove incompatible
211  // preallocation
212  LIBMESH_CHKERR(ierr);
213  ierr = MatSetOptionsPrefix(_mat, "");
214  LIBMESH_CHKERR(ierr);
215  ierr = MatSetFromOptions(_mat);
216  LIBMESH_CHKERR(ierr);
217  ierr = MatHYPRESetPreallocation(_mat, n_nz, NULL, n_oz, NULL);
218  LIBMESH_CHKERR(ierr);
219 #else
220  libmesh_error_msg("PETSc 3.9.4 or higher with hypre is required for MatHypre");
221 #endif
222  break;
223 
224  default: libmesh_error_msg("Unsupported petsc matrix type");
225  }
226  }
227 
228  // Make it an error for PETSc to allocate new nonzero entries during assembly
229  ierr = MatSetOption(_mat, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
230  LIBMESH_CHKERR(ierr);
231 
232  this->zero ();
233 }
234 
235 
236 template <typename T>
238  const numeric_index_type n_in,
239  const numeric_index_type m_l,
240  const numeric_index_type n_l,
241  const std::vector<numeric_index_type> & n_nz,
242  const std::vector<numeric_index_type> & n_oz,
243  const numeric_index_type blocksize_in)
244 {
245  // So compilers don't warn when !LIBMESH_ENABLE_BLOCKED_STORAGE
246  libmesh_ignore(blocksize_in);
247 
248  PetscInt blocksize = static_cast<PetscInt>(blocksize_in);
249 
250  // Clear initialized matrices
251  if (this->initialized())
252  this->clear();
253 
254  this->_is_initialized = true;
255 
256  // Make sure the sparsity pattern isn't empty unless the matrix is 0x0
257  libmesh_assert_equal_to (n_nz.size(), m_l);
258  libmesh_assert_equal_to (n_oz.size(), m_l);
259 
260  PetscErrorCode ierr = 0;
261  PetscInt m_global = static_cast<PetscInt>(m_in);
262  PetscInt n_global = static_cast<PetscInt>(n_in);
263  PetscInt m_local = static_cast<PetscInt>(m_l);
264  PetscInt n_local = static_cast<PetscInt>(n_l);
265 
266  ierr = MatCreate(this->comm().get(), &_mat);
267  LIBMESH_CHKERR(ierr);
268  ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global);
269  LIBMESH_CHKERR(ierr);
270  ierr = MatSetBlockSize(_mat,blocksize);
271  LIBMESH_CHKERR(ierr);
272 
273 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE
274  if (blocksize > 1)
275  {
276  // specified blocksize, bs>1.
277  // double check sizes.
278  libmesh_assert_equal_to (m_local % blocksize, 0);
279  libmesh_assert_equal_to (n_local % blocksize, 0);
280  libmesh_assert_equal_to (m_global % blocksize, 0);
281  libmesh_assert_equal_to (n_global % blocksize, 0);
282 
283  ierr = MatSetType(_mat, MATBAIJ); // Automatically chooses seqbaij or mpibaij
284  LIBMESH_CHKERR(ierr);
285 
286  // MatSetFromOptions needs to happen before Preallocation routines
287  // since MatSetFromOptions can change matrix type and remove incompatible
288  // preallocation
289  LIBMESH_CHKERR(ierr);
290  ierr = MatSetOptionsPrefix(_mat, "");
291  LIBMESH_CHKERR(ierr);
292  ierr = MatSetFromOptions(_mat);
293  LIBMESH_CHKERR(ierr);
294  // transform the per-entry n_nz and n_oz arrays into their block counterparts.
295  std::vector<numeric_index_type> b_n_nz, b_n_oz;
296 
297  transform_preallocation_arrays (blocksize,
298  n_nz, n_oz,
299  b_n_nz, b_n_oz);
300 
301  ierr = MatSeqBAIJSetPreallocation (_mat,
302  blocksize,
303  0,
304  numeric_petsc_cast(b_n_nz.empty() ? nullptr : b_n_nz.data()));
305  LIBMESH_CHKERR(ierr);
306 
307  ierr = MatMPIBAIJSetPreallocation (_mat,
308  blocksize,
309  0,
310  numeric_petsc_cast(b_n_nz.empty() ? nullptr : b_n_nz.data()),
311  0,
312  numeric_petsc_cast(b_n_oz.empty() ? nullptr : b_n_oz.data()));
313  LIBMESH_CHKERR(ierr);
314  }
315  else
316 #endif
317  {
318  switch (_mat_type) {
319  case AIJ:
320  ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij
321  LIBMESH_CHKERR(ierr);
322 
323  // MatSetFromOptions needs to happen before Preallocation routines
324  // since MatSetFromOptions can change matrix type and remove incompatible
325  // preallocation
326  LIBMESH_CHKERR(ierr);
327  ierr = MatSetOptionsPrefix(_mat, "");
328  LIBMESH_CHKERR(ierr);
329  ierr = MatSetFromOptions(_mat);
330  LIBMESH_CHKERR(ierr);
331  ierr = MatSeqAIJSetPreallocation (_mat,
332  0,
333  numeric_petsc_cast(n_nz.empty() ? nullptr : n_nz.data()));
334  LIBMESH_CHKERR(ierr);
335  ierr = MatMPIAIJSetPreallocation (_mat,
336  0,
337  numeric_petsc_cast(n_nz.empty() ? nullptr : n_nz.data()),
338  0,
339  numeric_petsc_cast(n_oz.empty() ? nullptr : n_oz.data()));
340  break;
341 
342  case HYPRE:
343 #if !PETSC_VERSION_LESS_THAN(3,9,4) && LIBMESH_HAVE_PETSC_HYPRE
344  ierr = MatSetType(_mat, MATHYPRE);
345  LIBMESH_CHKERR(ierr);
346 
347  // MatSetFromOptions needs to happen before Preallocation routines
348  // since MatSetFromOptions can change matrix type and remove incompatible
349  // preallocation
350  LIBMESH_CHKERR(ierr);
351  ierr = MatSetOptionsPrefix(_mat, "");
352  LIBMESH_CHKERR(ierr);
353  ierr = MatSetFromOptions(_mat);
354  LIBMESH_CHKERR(ierr);
355  ierr = MatHYPRESetPreallocation (_mat,
356  0,
357  numeric_petsc_cast(n_nz.empty() ? nullptr : n_nz.data()),
358  0,
359  numeric_petsc_cast(n_oz.empty() ? nullptr : n_oz.data()));
360  LIBMESH_CHKERR(ierr);
361 #else
362  libmesh_error_msg("PETSc 3.9.4 or higher with hypre is required for MatHypre");
363 #endif
364  break;
365 
366  default: libmesh_error_msg("Unsupported petsc matrix type");
367  }
368 
369  }
370 
371  // Make it an error for PETSc to allocate new nonzero entries during assembly
372  ierr = MatSetOption(_mat, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
373  LIBMESH_CHKERR(ierr);
374  this->zero();
375 }
376 
377 
378 template <typename T>
379 void PetscMatrix<T>::init (const ParallelType)
380 {
381  libmesh_assert(this->_dof_map);
382 
383  const numeric_index_type m_in = this->_dof_map->n_dofs();
384  const numeric_index_type m_l = this->_dof_map->n_dofs_on_processor(this->processor_id());
385 
386  const std::vector<numeric_index_type> & n_nz = this->_sp->get_n_nz();
387  const std::vector<numeric_index_type> & n_oz = this->_sp->get_n_oz();
388 
389  PetscInt blocksize = static_cast<PetscInt>(this->_dof_map->block_size());
390 
391  this->init(m_in, m_in, m_l, m_l, n_nz, n_oz, blocksize);
392 }
393 
394 
395 template <typename T>
397 {
398  libmesh_not_implemented();
399 }
400 
401 template <typename T>
403 {
404 #if !PETSC_VERSION_LESS_THAN(3,9,0)
405  libmesh_assert (this->initialized());
406 
407  auto ierr = MatResetPreallocation(_mat);
408  LIBMESH_CHKERR(ierr);
409 #else
410  libmesh_warning("Your version of PETSc doesn't support resetting of "
411  "preallocation, so we will use your most recent sparsity "
412  "pattern. This may result in a degradation of performance\n");
413 #endif
414 }
415 
416 template <typename T>
418 {
419  libmesh_assert (this->initialized());
420 
421  semiparallel_only();
422 
423  PetscErrorCode ierr=0;
424 
425  PetscInt m_l, n_l;
426 
427  ierr = MatGetLocalSize(_mat,&m_l,&n_l);
428  LIBMESH_CHKERR(ierr);
429 
430  if (n_l)
431  {
432  ierr = MatZeroEntries(_mat);
433  LIBMESH_CHKERR(ierr);
434  }
435 }
436 
437 template <typename T>
438 void PetscMatrix<T>::zero_rows (std::vector<numeric_index_type> & rows, T diag_value)
439 {
440  libmesh_assert (this->initialized());
441 
442  semiparallel_only();
443 
444  PetscErrorCode ierr=0;
445 
446  // As of petsc-dev at the time of 3.1.0, MatZeroRows now takes two additional
447  // optional arguments. The optional arguments (x,b) can be used to specify the
448  // solutions for the zeroed rows (x) and right hand side (b) to update.
449  // Could be useful for setting boundary conditions...
450  if (!rows.empty())
451  ierr = MatZeroRows(_mat, cast_int<PetscInt>(rows.size()),
452  numeric_petsc_cast(rows.data()), PS(diag_value),
453  NULL, NULL);
454  else
455  ierr = MatZeroRows(_mat, 0, NULL, PS(diag_value), NULL, NULL);
456 
457  LIBMESH_CHKERR(ierr);
458 }
459 
460 template <typename T>
461 std::unique_ptr<SparseMatrix<T>> PetscMatrix<T>::zero_clone () const
462 {
463  libmesh_error_msg_if(!this->closed(), "Matrix must be closed before it can be cloned!");
464 
465  // Copy the nonzero pattern only
466  Mat copy;
467  PetscErrorCode ierr = MatDuplicate(_mat, MAT_DO_NOT_COPY_VALUES, &copy);
468  LIBMESH_CHKERR(ierr);
469 
470  // Call wrapping PetscMatrix constructor, have it take over
471  // ownership.
472  auto ret = std::make_unique<PetscMatrix<T>>(copy, this->comm());
473  ret->set_destroy_mat_on_exit(true);
474 
475  // Work around an issue on older compilers. We are able to simply
476  // "return ret;" on newer compilers
477  return std::unique_ptr<SparseMatrix<T>>(ret.release());
478 }
479 
480 
481 
482 template <typename T>
483 std::unique_ptr<SparseMatrix<T>> PetscMatrix<T>::clone () const
484 {
485  libmesh_error_msg_if(!this->closed(), "Matrix must be closed before it can be cloned!");
486 
487  // Copy the nonzero pattern and numerical values
488  Mat copy;
489  PetscErrorCode ierr = MatDuplicate(_mat, MAT_COPY_VALUES, &copy);
490  LIBMESH_CHKERR(ierr);
491 
492  // Call wrapping PetscMatrix constructor, have it take over
493  // ownership.
494  auto ret = std::make_unique<PetscMatrix<T>>(copy, this->comm());
495  ret->set_destroy_mat_on_exit(true);
496 
497  // Work around an issue on older compilers. We are able to simply
498  // "return ret;" on newer compilers
499  return std::unique_ptr<SparseMatrix<T>>(ret.release());
500 }
501 
502 template <typename T>
503 void PetscMatrix<T>::clear () noexcept
504 {
505  if ((this->initialized()) && (this->_destroy_mat_on_exit))
506  {
507  exceptionless_semiparallel_only();
508 
509  // If we encounter an error here, print a warning but otherwise
510  // keep going since we may be recovering from an exception.
511  PetscErrorCode ierr = MatDestroy (&_mat);
512  if (ierr)
513  libmesh_warning("Warning: MatDestroy returned a non-zero error code which we ignored.");
514 
515  this->_is_initialized = false;
516  }
517 }
518 
519 
520 
521 template <typename T>
523 {
524  libmesh_assert (this->initialized());
525 
526  semiparallel_only();
527 
528  PetscErrorCode ierr=0;
529  PetscReal petsc_value;
530  Real value;
531 
532  libmesh_assert (this->closed());
533 
534  ierr = MatNorm(_mat, NORM_1, &petsc_value);
535  LIBMESH_CHKERR(ierr);
536 
537  value = static_cast<Real>(petsc_value);
538 
539  return value;
540 }
541 
542 
543 
544 template <typename T>
546 {
547  libmesh_assert (this->initialized());
548 
549  semiparallel_only();
550 
551  PetscErrorCode ierr=0;
552  PetscReal petsc_value;
553  Real value;
554 
555  libmesh_assert (this->closed());
556 
557  ierr = MatNorm(_mat, NORM_INFINITY, &petsc_value);
558  LIBMESH_CHKERR(ierr);
559 
560  value = static_cast<Real>(petsc_value);
561 
562  return value;
563 }
564 
565 
566 
567 template <typename T>
568 void PetscMatrix<T>::print_matlab (const std::string & name) const
569 {
570  libmesh_assert (this->initialized());
571 
572  semiparallel_only();
573 
574  if (!this->closed())
575  {
576  libmesh_deprecated();
577  libmesh_warning("The matrix must be assembled before calling PetscMatrix::print_matlab().\n"
578  "Please update your code, as this warning will become an error in a future release.");
579  const_cast<PetscMatrix<T> *>(this)->close();
580  }
581 
582  PetscErrorCode ierr = 0;
583 
584  WrappedPetsc<PetscViewer> petsc_viewer;
585  ierr = PetscViewerCreate (this->comm().get(),
586  petsc_viewer.get());
587  LIBMESH_CHKERR(ierr);
588 
589  // Create an ASCII file containing the matrix
590  // if a filename was provided.
591  if (name != "")
592  {
593  ierr = PetscViewerASCIIOpen( this->comm().get(),
594  name.c_str(),
595  petsc_viewer.get());
596  LIBMESH_CHKERR(ierr);
597 
598 #if PETSC_VERSION_LESS_THAN(3,7,0)
599  ierr = PetscViewerSetFormat (petsc_viewer,
600  PETSC_VIEWER_ASCII_MATLAB);
601 #else
602  ierr = PetscViewerPushFormat (petsc_viewer,
603  PETSC_VIEWER_ASCII_MATLAB);
604 #endif
605 
606  LIBMESH_CHKERR(ierr);
607 
608  ierr = MatView (_mat, petsc_viewer);
609  LIBMESH_CHKERR(ierr);
610  }
611 
612  // Otherwise the matrix will be dumped to the screen.
613  else
614  {
615 #if PETSC_VERSION_LESS_THAN(3,7,0)
616  ierr = PetscViewerSetFormat (PETSC_VIEWER_STDOUT_WORLD,
617  PETSC_VIEWER_ASCII_MATLAB);
618 #else
619  ierr = PetscViewerPushFormat (PETSC_VIEWER_STDOUT_WORLD,
620  PETSC_VIEWER_ASCII_MATLAB);
621 #endif
622 
623  LIBMESH_CHKERR(ierr);
624 
625  ierr = MatView (_mat, PETSC_VIEWER_STDOUT_WORLD);
626  LIBMESH_CHKERR(ierr);
627  }
628 }
629 
630 
631 
632 
633 
634 template <typename T>
635 void PetscMatrix<T>::print_personal(std::ostream & os) const
636 {
637  libmesh_assert (this->initialized());
638 
639  // Routine must be called in parallel on parallel matrices
640  // and serial on serial matrices.
641  semiparallel_only();
642 
643  // #ifndef NDEBUG
644  // if (os != std::cout)
645  // libMesh::err << "Warning! PETSc can only print to std::cout!" << std::endl;
646  // #endif
647 
648  // Matrix must be in an assembled state to be printed
649  if (!this->closed())
650  {
651  libmesh_deprecated();
652  libmesh_warning("The matrix must be assembled before calling PetscMatrix::print_personal().\n"
653  "Please update your code, as this warning will become an error in a future release.");
654  const_cast<PetscMatrix<T> *>(this)->close();
655  }
656 
657  PetscErrorCode ierr=0;
658 
659  // Print to screen if ostream is stdout
660  if (os.rdbuf() == std::cout.rdbuf())
661  {
662  ierr = MatView(_mat, NULL);
663  LIBMESH_CHKERR(ierr);
664  }
665 
666  // Otherwise, print to the requested file, in a roundabout way...
667  else
668  {
669  // We will create a temporary filename, and file, for PETSc to
670  // write to.
671  std::string temp_filename;
672 
673  {
674  // Template for temporary filename
675  char c[] = "temp_petsc_matrix.XXXXXX";
676 
677  // Generate temporary, unique filename only on processor 0. We will
678  // use this filename for PetscViewerASCIIOpen, before copying it into
679  // the user's stream
680  if (this->processor_id() == 0)
681  {
682  int fd = mkstemp(c);
683 
684  // Check to see that mkstemp did not fail.
685  libmesh_error_msg_if(fd == -1, "mkstemp failed in PetscMatrix::print_personal()");
686 
687  // mkstemp returns a file descriptor for an open file,
688  // so let's close it before we hand it to PETSc!
689  ::close (fd);
690  }
691 
692  // Store temporary filename as string, makes it easier to broadcast
693  temp_filename = c;
694  }
695 
696  // Now broadcast the filename from processor 0 to all processors.
697  this->comm().broadcast(temp_filename);
698 
699  // PetscViewer object for passing to MatView
700  PetscViewer petsc_viewer;
701 
702  // This PETSc function only takes a string and handles the opening/closing
703  // of the file internally. Since print_personal() takes a reference to
704  // an ostream, we have to do an extra step... print_personal() should probably
705  // have a version that takes a string to get rid of this problem.
706  ierr = PetscViewerASCIIOpen( this->comm().get(),
707  temp_filename.c_str(),
708  &petsc_viewer);
709  LIBMESH_CHKERR(ierr);
710 
711  // Probably don't need to set the format if it's default...
712  // ierr = PetscViewerSetFormat (petsc_viewer,
713  // PETSC_VIEWER_DEFAULT);
714  // LIBMESH_CHKERR(ierr);
715 
716  // Finally print the matrix using the viewer
717  ierr = MatView (_mat, petsc_viewer);
718  LIBMESH_CHKERR(ierr);
719 
720  if (this->processor_id() == 0)
721  {
722  // Now the inefficient bit: open temp_filename as an ostream and copy the contents
723  // into the user's desired ostream. We can't just do a direct file copy, we don't even have the filename!
724  std::ifstream input_stream(temp_filename.c_str());
725  os << input_stream.rdbuf(); // The "most elegant" way to copy one stream into another.
726  // os.close(); // close not defined in ostream
727 
728  // Now remove the temporary file
729  input_stream.close();
730  std::remove(temp_filename.c_str());
731  }
732  }
733 }
734 
735 
736 
737 
738 
739 
740 template <typename T>
742  const std::vector<numeric_index_type> & rows,
743  const std::vector<numeric_index_type> & cols)
744 {
745  libmesh_assert (this->initialized());
746 
747  const numeric_index_type n_rows = dm.m();
748  const numeric_index_type n_cols = dm.n();
749 
750  libmesh_assert_equal_to (rows.size(), n_rows);
751  libmesh_assert_equal_to (cols.size(), n_cols);
752 
753  PetscErrorCode ierr=0;
754  ierr = MatSetValues(_mat,
755  n_rows, numeric_petsc_cast(rows.data()),
756  n_cols, numeric_petsc_cast(cols.data()),
757  pPS(const_cast<T*>(dm.get_values().data())),
758  ADD_VALUES);
759  LIBMESH_CHKERR(ierr);
760 }
761 
762 
763 
764 
765 
766 
767 template <typename T>
769  const std::vector<numeric_index_type> & brows,
770  const std::vector<numeric_index_type> & bcols)
771 {
772  libmesh_assert (this->initialized());
773 
774  const numeric_index_type n_brows =
775  cast_int<numeric_index_type>(brows.size());
776  const numeric_index_type n_bcols =
777  cast_int<numeric_index_type>(bcols.size());
778 
779  PetscErrorCode ierr=0;
780 
781 #ifndef NDEBUG
782  const numeric_index_type n_rows =
783  cast_int<numeric_index_type>(dm.m());
784  const numeric_index_type n_cols =
785  cast_int<numeric_index_type>(dm.n());
786  const numeric_index_type blocksize = n_rows / n_brows;
787 
788  libmesh_assert_equal_to (n_cols / n_bcols, blocksize);
789  libmesh_assert_equal_to (blocksize*n_brows, n_rows);
790  libmesh_assert_equal_to (blocksize*n_bcols, n_cols);
791 
792  PetscInt petsc_blocksize;
793  ierr = MatGetBlockSize(_mat, &petsc_blocksize);
794  LIBMESH_CHKERR(ierr);
795  libmesh_assert_equal_to (blocksize, static_cast<numeric_index_type>(petsc_blocksize));
796 #endif
797 
798  // These casts are required for PETSc <= 2.1.5
799  ierr = MatSetValuesBlocked(_mat,
800  n_brows, numeric_petsc_cast(brows.data()),
801  n_bcols, numeric_petsc_cast(bcols.data()),
802  pPS(const_cast<T*>(dm.get_values().data())),
803  ADD_VALUES);
804  LIBMESH_CHKERR(ierr);
805 }
806 
807 
808 
809 
810 
811 template <typename T>
813  const std::vector<numeric_index_type> & rows,
814  const std::vector<numeric_index_type> & cols,
815  const bool reuse_submatrix) const
816 {
817  if (!this->closed())
818  {
819  libmesh_deprecated();
820  libmesh_warning("The matrix must be assembled before calling PetscMatrix::create_submatrix().\n"
821  "Please update your code, as this warning will become an error in a future release.");
822  const_cast<PetscMatrix<T> *>(this)->close();
823  }
824 
825  // Make sure the SparseMatrix passed in is really a PetscMatrix
826  PetscMatrix<T> * petsc_submatrix = cast_ptr<PetscMatrix<T> *>(&submatrix);
827 
828  // If we're not reusing submatrix and submatrix is already initialized
829  // then we need to clear it, otherwise we get a memory leak.
830  if (!reuse_submatrix && submatrix.initialized())
831  submatrix.clear();
832 
833  // Construct row and column index sets.
834  PetscErrorCode ierr=0;
835 
836  WrappedPetsc<IS> isrow;
837  ierr = ISCreateGeneral(this->comm().get(),
838  cast_int<PetscInt>(rows.size()),
839  numeric_petsc_cast(rows.data()),
840  PETSC_USE_POINTER,
841  isrow.get()); LIBMESH_CHKERR(ierr);
842 
843  WrappedPetsc<IS> iscol;
844  ierr = ISCreateGeneral(this->comm().get(),
845  cast_int<PetscInt>(cols.size()),
846  numeric_petsc_cast(cols.data()),
847  PETSC_USE_POINTER,
848  iscol.get()); LIBMESH_CHKERR(ierr);
849 
850  // Extract submatrix
851  ierr = LibMeshCreateSubMatrix(_mat,
852  isrow,
853  iscol,
854  (reuse_submatrix ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX),
855  &(petsc_submatrix->_mat)); LIBMESH_CHKERR(ierr);
856 
857  // Specify that the new submatrix is initialized and close it.
858  petsc_submatrix->_is_initialized = true;
859  petsc_submatrix->close();
860 }
861 
862 template <typename T>
864  const std::vector<numeric_index_type> & rows,
865  const std::vector<numeric_index_type> & cols) const
866 {
867  if (!this->closed())
868  {
869  libmesh_deprecated();
870  libmesh_warning("The matrix must be assembled before calling PetscMatrix::create_submatrix_nosort().\n"
871  "Please update your code, as this warning will become an error in a future release.");
872  const_cast<PetscMatrix<T> *>(this)->close();
873  }
874 
875  // Make sure the SparseMatrix passed in is really a PetscMatrix
876  PetscMatrix<T> * petsc_submatrix = cast_ptr<PetscMatrix<T> *>(&submatrix);
877 
878  PetscErrorCode ierr=0;
879 
880  ierr=MatZeroEntries(petsc_submatrix->_mat);
881  LIBMESH_CHKERR(ierr);
882 
883  PetscInt pc_ncols = 0;
884  const PetscInt * pc_cols;
885  const PetscScalar * pc_vals;
886 
887  // // data for creating the submatrix
888  std::vector<PetscInt> sub_cols;
889  std::vector<PetscScalar> sub_vals;
890 
891  for (auto i : index_range(rows))
892  {
893  PetscInt sub_rid[] = {static_cast<PetscInt>(i)};
894  PetscInt rid = static_cast<PetscInt>(rows[i]);
895  // only get value from local rows, and set values to the corresponding columns in the submatrix
896  if (rows[i]>= this->row_start() && rows[i]< this->row_stop())
897  {
898  // get one row of data from the original matrix
899  ierr = MatGetRow(_mat, rid, &pc_ncols, &pc_cols, &pc_vals);
900  LIBMESH_CHKERR(ierr);
901  // extract data from certain cols, save the indices and entries sub_cols and sub_vals
902  for (auto j : index_range(cols))
903  {
904  for (unsigned int idx = 0; idx< static_cast<unsigned int>(pc_ncols); idx++)
905  {
906  if (pc_cols[idx] == static_cast<PetscInt>(cols[j]))
907  {
908  sub_cols.push_back(static_cast<PetscInt>(j));
909  sub_vals.push_back(pc_vals[idx]);
910  }
911  }
912  }
913  // set values
914  ierr = MatSetValues(petsc_submatrix->_mat,
915  1,
916  sub_rid,
917  static_cast<PetscInt>(sub_vals.size()),
918  sub_cols.data(),
919  sub_vals.data(),
920  INSERT_VALUES);
921  LIBMESH_CHKERR(ierr);
922  ierr = MatRestoreRow(_mat, rid, &pc_ncols, &pc_cols, &pc_vals);
923  LIBMESH_CHKERR(ierr);
924  // clear data for this row
925  sub_cols.clear();
926  sub_vals.clear();
927  }
928  }
929  MatAssemblyBeginEnd(petsc_submatrix->comm(), petsc_submatrix->_mat, MAT_FINAL_ASSEMBLY);
930  // Specify that the new submatrix is initialized and close it.
931  petsc_submatrix->_is_initialized = true;
932  petsc_submatrix->close();
933 }
934 
935 
936 template <typename T>
938 {
939  // Make sure the NumericVector passed in is really a PetscVector
940  PetscVector<T> & petsc_dest = cast_ref<PetscVector<T> &>(dest);
941 
942  // Needs a const_cast since PETSc does not work with const.
943  PetscErrorCode ierr =
944  MatGetDiagonal(const_cast<PetscMatrix<T> *>(this)->mat(),petsc_dest.vec()); LIBMESH_CHKERR(ierr);
945 }
946 
947 
948 
949 template <typename T>
951 {
952  // Make sure the SparseMatrix passed in is really a PetscMatrix
953  PetscMatrix<T> & petsc_dest = cast_ref<PetscMatrix<T> &>(dest);
954 
955  // If we aren't reusing the matrix then need to clear dest,
956  // otherwise we get a memory leak
957  if (&petsc_dest != this)
958  dest.clear();
959 
960  PetscErrorCode ierr;
961  if (&petsc_dest == this)
962  // The MAT_REUSE_MATRIX flag was replaced by MAT_INPLACE_MATRIX
963  // in PETSc 3.7.0
964 #if PETSC_VERSION_LESS_THAN(3,7,0)
965  ierr = MatTranspose(_mat,MAT_REUSE_MATRIX,&petsc_dest._mat);
966 #else
967  ierr = MatTranspose(_mat, MAT_INPLACE_MATRIX, &petsc_dest._mat);
968 #endif
969  else
970  ierr = MatTranspose(_mat,MAT_INITIAL_MATRIX,&petsc_dest._mat);
971  LIBMESH_CHKERR(ierr);
972 
973  // Specify that the transposed matrix is initialized and close it.
974  petsc_dest._is_initialized = true;
975  petsc_dest.close();
976 }
977 
978 
979 
980 
981 
982 template <typename T>
984 {
985  semiparallel_only();
986 
987  // BSK - 1/19/2004
988  // strictly this check should be OK, but it seems to
989  // fail on matrix-free matrices. Do they falsely
990  // state they are assembled? Check with the developers...
991  // if (this->closed())
992  // return;
993 
994  MatAssemblyBeginEnd(this->comm(), _mat, MAT_FINAL_ASSEMBLY);
995 }
996 
997 template <typename T>
999 {
1000  semiparallel_only();
1001 
1002  MatAssemblyBeginEnd(this->comm(), _mat, MAT_FLUSH_ASSEMBLY);
1003 }
1004 
1005 
1006 
1007 template <typename T>
1009 {
1010  libmesh_assert (this->initialized());
1011 
1012  PetscInt petsc_m=0, petsc_n=0;
1013  PetscErrorCode ierr=0;
1014 
1015  ierr = MatGetSize (_mat, &petsc_m, &petsc_n);
1016  LIBMESH_CHKERR(ierr);
1017 
1018  return static_cast<numeric_index_type>(petsc_m);
1019 }
1020 
1021 template <typename T>
1023 {
1024  libmesh_assert (this->initialized());
1025 
1026  PetscInt m = 0;
1027 
1028  auto ierr = MatGetLocalSize (_mat, &m, NULL);
1029  LIBMESH_CHKERR(ierr);
1030 
1031  return static_cast<numeric_index_type>(m);
1032 }
1033 
1034 template <typename T>
1036 {
1037  libmesh_assert (this->initialized());
1038 
1039  PetscInt petsc_m=0, petsc_n=0;
1040  PetscErrorCode ierr=0;
1041 
1042  ierr = MatGetSize (_mat, &petsc_m, &petsc_n);
1043  LIBMESH_CHKERR(ierr);
1044 
1045  return static_cast<numeric_index_type>(petsc_n);
1046 }
1047 
1048 template <typename T>
1050 {
1051  libmesh_assert (this->initialized());
1052 
1053  PetscInt n = 0;
1054 
1055  auto ierr = MatGetLocalSize (_mat, NULL, &n);
1056  LIBMESH_CHKERR(ierr);
1057 
1058  return static_cast<numeric_index_type>(n);
1059 }
1060 
1061 template <typename T>
1063  numeric_index_type & n) const
1064 {
1065  libmesh_assert (this->initialized());
1066 
1067  PetscInt petsc_m = 0, petsc_n = 0;
1068 
1069  auto ierr = MatGetLocalSize (_mat, &petsc_m, &petsc_n);
1070  LIBMESH_CHKERR(ierr);
1071 
1072  m = static_cast<numeric_index_type>(petsc_m);
1073  n = static_cast<numeric_index_type>(petsc_n);
1074 }
1075 
1076 template <typename T>
1078 {
1079  libmesh_assert (this->initialized());
1080 
1081  PetscInt start=0, stop=0;
1082  PetscErrorCode ierr=0;
1083 
1084  ierr = MatGetOwnershipRange(_mat, &start, &stop);
1085  LIBMESH_CHKERR(ierr);
1086 
1087  return static_cast<numeric_index_type>(start);
1088 }
1089 
1090 
1091 
1092 template <typename T>
1094 {
1095  libmesh_assert (this->initialized());
1096 
1097  PetscInt start=0, stop=0;
1098  PetscErrorCode ierr=0;
1099 
1100  ierr = MatGetOwnershipRange(_mat, &start, &stop);
1101  LIBMESH_CHKERR(ierr);
1102 
1103  return static_cast<numeric_index_type>(stop);
1104 }
1105 
1106 
1107 
1108 template <typename T>
1110  const numeric_index_type j,
1111  const T value)
1112 {
1113  libmesh_assert (this->initialized());
1114 
1115  PetscErrorCode ierr=0;
1116  PetscInt i_val=i, j_val=j;
1117 
1118  PetscScalar petsc_value = static_cast<PetscScalar>(value);
1119  ierr = MatSetValues(_mat, 1, &i_val, 1, &j_val,
1120  &petsc_value, INSERT_VALUES);
1121  LIBMESH_CHKERR(ierr);
1122 }
1123 
1124 
1125 
1126 template <typename T>
1128  const numeric_index_type j,
1129  const T value)
1130 {
1131  libmesh_assert (this->initialized());
1132 
1133  PetscErrorCode ierr=0;
1134  PetscInt i_val=i, j_val=j;
1135 
1136  PetscScalar petsc_value = static_cast<PetscScalar>(value);
1137  ierr = MatSetValues(_mat, 1, &i_val, 1, &j_val,
1138  &petsc_value, ADD_VALUES);
1139  LIBMESH_CHKERR(ierr);
1140 }
1141 
1142 
1143 
1144 template <typename T>
1146  const std::vector<numeric_index_type> & dof_indices)
1147 {
1148  this->add_matrix (dm, dof_indices, dof_indices);
1149 }
1150 
1151 
1152 
1153 
1154 
1155 
1156 
1157 template <typename T>
1158 void PetscMatrix<T>::add (const T a_in, const SparseMatrix<T> & X_in)
1159 {
1160  libmesh_assert (this->initialized());
1161 
1162  // sanity check. but this cannot avoid
1163  // crash due to incompatible sparsity structure...
1164  libmesh_assert_equal_to (this->m(), X_in.m());
1165  libmesh_assert_equal_to (this->n(), X_in.n());
1166 
1167  PetscScalar a = static_cast<PetscScalar> (a_in);
1168  const PetscMatrix<T> * X = cast_ptr<const PetscMatrix<T> *> (&X_in);
1169 
1170  libmesh_assert (X);
1171 
1172  PetscErrorCode ierr=0;
1173 
1174  // the matrix from which we copy the values has to be assembled/closed
1175  libmesh_assert(X->closed());
1176 
1177  semiparallel_only();
1178 
1179  ierr = MatAXPY(_mat, a, X->_mat, DIFFERENT_NONZERO_PATTERN);
1180  LIBMESH_CHKERR(ierr);
1181 }
1182 
1183 
1184 template <typename T>
1186 {
1187  libmesh_assert (this->initialized());
1188 
1189  // sanity check
1190  // we do not check the Y_out size here as we will initialize & close it at the end
1191  libmesh_assert_equal_to (this->n(), X_in.m());
1192 
1193  const PetscMatrix<T> * X = cast_ptr<const PetscMatrix<T> *> (&X_in);
1194  PetscMatrix<T> * Y = cast_ptr<PetscMatrix<T> *> (&Y_out);
1195 
1196  PetscErrorCode ierr = 0;
1197 
1198  // the matrix from which we copy the values has to be assembled/closed
1199  libmesh_assert(X->closed());
1200 
1201  semiparallel_only();
1202 
1203  if (reuse)
1204  {
1205  ierr = MatMatMult(_mat, X->_mat, MAT_REUSE_MATRIX, PETSC_DEFAULT, &Y->_mat);
1206  LIBMESH_CHKERR(ierr);
1207  }
1208  else
1209  {
1210  Y->clear();
1211  ierr = MatMatMult(_mat, X->_mat, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &Y->_mat);
1212  LIBMESH_CHKERR(ierr);
1213  }
1214  // Specify that the new matrix is initialized
1215  // We do not close it here as `MatMatMult` ensures Y being closed
1216  Y->_is_initialized = true;
1217 }
1218 
1219 template <typename T>
1220 void
1222  const std::map<numeric_index_type, numeric_index_type> & row_ltog,
1223  const std::map<numeric_index_type, numeric_index_type> & col_ltog,
1224  const T scalar)
1225 {
1226  // size of spm is usually greater than row_ltog and col_ltog in parallel as the indices are owned by the processor
1227  // also, we should allow adding certain parts of spm to _mat
1228  libmesh_assert_greater_equal(spm.m(), row_ltog.size());
1229  libmesh_assert_greater_equal(spm.n(), col_ltog.size());
1230 
1231  // make sure matrix has larger size than spm
1232  libmesh_assert_greater_equal(this->m(), spm.m());
1233  libmesh_assert_greater_equal(this->n(), spm.n());
1234 
1235  if (!this->closed())
1236  this->close();
1237 
1238  PetscErrorCode ierr = 0;
1239 
1240  auto pscm = cast_ptr<const PetscMatrix<T> *>(&spm);
1241 
1242  PetscInt ncols = 0;
1243 
1244  const PetscInt * lcols;
1245  const PetscScalar * vals;
1246 
1247  std::vector<PetscInt> gcols;
1248  std::vector<PetscScalar> values;
1249 
1250  for (auto ltog : row_ltog)
1251  {
1252  PetscInt grow[] = {static_cast<PetscInt>(ltog.second)}; // global row index
1253 
1254  ierr = MatGetRow(pscm->_mat, static_cast<PetscInt>(ltog.first), &ncols, &lcols, &vals);
1255  LIBMESH_CHKERR(ierr);
1256 
1257  // get global indices (gcols) from lcols, increment values = vals*scalar
1258  gcols.resize(ncols);
1259  values.resize(ncols);
1260  for (auto i : index_range(gcols))
1261  {
1262  gcols[i] = libmesh_map_find(col_ltog, lcols[i]);
1263  values[i] = PS(scalar) * vals[i];
1264  }
1265 
1266  ierr = MatSetValues(_mat, 1, grow, ncols, gcols.data(), values.data(), ADD_VALUES);
1267  LIBMESH_CHKERR(ierr);
1268  ierr = MatRestoreRow(pscm->_mat, static_cast<PetscInt>(ltog.first), &ncols, &lcols, &vals);
1269  LIBMESH_CHKERR(ierr);
1270  }
1271  // Note: We are not closing the matrix because it is expensive to do so when adding multiple sparse matrices.
1272  // Remember to manually close the matrix once all changes to the matrix have been made.
1273 }
1274 
1275 template <typename T>
1277  const numeric_index_type j_in) const
1278 {
1279  libmesh_assert (this->initialized());
1280 
1281  // PETSc 2.2.1 & newer
1282  const PetscScalar * petsc_row;
1283  const PetscInt * petsc_cols;
1284 
1285  // If the entry is not in the sparse matrix, it is 0.
1286  T value=0.;
1287 
1288  PetscErrorCode
1289  ierr=0;
1290  PetscInt
1291  ncols=0,
1292  i_val=static_cast<PetscInt>(i_in),
1293  j_val=static_cast<PetscInt>(j_in);
1294 
1295 
1296  // the matrix needs to be closed for this to work
1297  // this->close();
1298  // but closing it is a semiparallel operation; we want operator()
1299  // to run on one processor.
1300  libmesh_assert(this->closed());
1301 
1302  ierr = MatGetRow(_mat, i_val, &ncols, &petsc_cols, &petsc_row);
1303  LIBMESH_CHKERR(ierr);
1304 
1305  // Perform a binary search to find the contiguous index in
1306  // petsc_cols (resp. petsc_row) corresponding to global index j_val
1307  std::pair<const PetscInt *, const PetscInt *> p =
1308  std::equal_range (petsc_cols, petsc_cols + ncols, j_val);
1309 
1310  // Found an entry for j_val
1311  if (p.first != p.second)
1312  {
1313  // The entry in the contiguous row corresponding
1314  // to the j_val column of interest
1315  const std::size_t j =
1316  std::distance (const_cast<PetscInt *>(petsc_cols),
1317  const_cast<PetscInt *>(p.first));
1318 
1319  libmesh_assert_less (j, ncols);
1320  libmesh_assert_equal_to (petsc_cols[j], j_val);
1321 
1322  value = static_cast<T> (petsc_row[j]);
1323  }
1324 
1325  ierr = MatRestoreRow(_mat, i_val,
1326  &ncols, &petsc_cols, &petsc_row);
1327  LIBMESH_CHKERR(ierr);
1328 
1329  return value;
1330 }
1331 
1332 template <typename T>
1334  std::vector<numeric_index_type> & indices,
1335  std::vector<T> & values) const
1336 {
1337  libmesh_assert (this->initialized());
1338 
1339  const PetscScalar * petsc_row;
1340  const PetscInt * petsc_cols;
1341 
1342  PetscErrorCode ierr=0;
1343  PetscInt
1344  ncols=0,
1345  i_val = static_cast<PetscInt>(i_in);
1346 
1347  // the matrix needs to be closed for this to work
1348  // this->close();
1349  // but closing it is a semiparallel operation; we want operator()
1350  // to run on one processor.
1351  libmesh_assert(this->closed());
1352 
1353  // PETSc makes no effort at being thread safe. Helgrind complains about
1354  // possible data races even just in PetscFunctionBegin (due to things
1355  // like stack counter incrementing). Perhaps we could ignore
1356  // this, but there are legitimate data races for Mat data members like
1357  // mat->getrowactive between MatGetRow and MatRestoreRow. Moreover,
1358  // there could be a write into mat->rowvalues during MatGetRow from
1359  // one thread while we are attempting to read from mat->rowvalues
1360  // (through petsc_cols) during data copy in another thread. So
1361  // the safe thing to do is to lock the whole method
1362 
1363 #ifdef LIBMESH_HAVE_CXX11_THREAD
1364  std::lock_guard<std::mutex>
1365 #else
1366  Threads::spin_mutex::scoped_lock
1367 #endif
1368  lock(_petsc_matrix_mutex);
1369 
1370  ierr = MatGetRow(_mat, i_val, &ncols, &petsc_cols, &petsc_row);
1371  LIBMESH_CHKERR(ierr);
1372 
1373  // Copy the data
1374  indices.resize(static_cast<std::size_t>(ncols));
1375  values.resize(static_cast<std::size_t>(ncols));
1376 
1377  for (auto i : index_range(indices))
1378  {
1379  indices[i] = static_cast<numeric_index_type>(petsc_cols[i]);
1380  values[i] = static_cast<T>(petsc_row[i]);
1381  }
1382 
1383  ierr = MatRestoreRow(_mat, i_val,
1384  &ncols, &petsc_cols, &petsc_row);
1385  LIBMESH_CHKERR(ierr);
1386 }
1387 
1388 
1389 template <typename T>
1391 {
1392  libmesh_assert (this->initialized());
1393 
1394  PetscErrorCode ierr=0;
1395  PetscBool assembled;
1396 
1397  ierr = MatAssembled(_mat, &assembled);
1398  LIBMESH_CHKERR(ierr);
1399 
1400  return (assembled == PETSC_TRUE);
1401 }
1402 
1403 template <typename T>
1405 {
1406  this->_destroy_mat_on_exit = destroy;
1407 }
1408 
1409 
1410 template <typename T>
1412 {
1413  std::swap(_mat, m_in._mat);
1414  std::swap(_destroy_mat_on_exit, m_in._destroy_mat_on_exit);
1415 }
1416 
1417 
1418 
1419 //------------------------------------------------------------------
1420 // Explicit instantiations
1421 template class LIBMESH_EXPORT PetscMatrix<Number>;
1422 
1423 } // namespace libMesh
1424 
1425 
1426 #endif // #ifdef LIBMESH_HAVE_PETSC
bool closed()
Checks that the library has been closed.
Definition: libmesh.C:268
void reset_preallocation()
重置矩阵以使用用户提供的原始非零模式。
Definition: petsc_matrix.C:402
virtual T operator()(const numeric_index_type i, const numeric_index_type j) const override
获取矩阵中特定位置的值。
该类提供了一个良好的接口,用于访问 PETSc 的 Vec 对象。所有重写的虚拟函数都在 numeric_vector.h 中有文档说明。
Definition: petsc_vector.h:75
void set_matrix_type(PetscMatrixType mat_type)
设置矩阵的类型(如稀疏矩阵类型)。
Definition: petsc_matrix.C:115
virtual void print_matlab(const std::string &name="") const override
将矩阵内容以 MATLAB 格式打印出来。
Definition: petsc_matrix.C:568
unsigned int n() const
返回矩阵的列维度。
bool _destroy_mat_on_exit
此布尔值仅应在接受 PETSc Mat 对象的构造函数中设置为 false。
Definition: petsc_matrix.h:508
virtual numeric_index_type local_m() const final
获取由该进程拥有的矩阵行数。
virtual void zero() override
将矩阵所有元素置为零。
Definition: petsc_matrix.C:417
PetscMatrix(const Parallel::Communicator &comm_in)
构造函数:将矩阵初始化为空,没有任何结构。这个构造函数只适用于类的成员矩阵。 所有其他矩阵应该在所有必要信息都可用的数据流中的某一点创建。
Definition: petsc_matrix.C:83
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type nnz=30, const numeric_index_type noz=10, const numeric_index_type blocksize=1) override
初始化 PETSc 矩阵。
Definition: petsc_matrix.C:121
virtual void clear() noexceptoverride
clear() 在析构函数中调用,因此它不应该抛出异常。
Definition: petsc_matrix.C:503
void get_local_size(numeric_index_type &m, numeric_index_type &n) const
获取由该进程拥有的矩阵行数和列数。
virtual numeric_index_type n() const override
获取矩阵的列数。
提供了不同线性代数库的向量存储方案的统一接口。
Definition: dof_map.h:67
void update_preallocation_and_zero()
更新基于 dof_map 的稀疏模式,并将矩阵置零。这在稀疏模式在计算过程中发生变化的情况下很有用。
Definition: petsc_matrix.C:396
virtual void add_block_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &brows, const std::vector< numeric_index_type > &bcols) override
将稠密块矩阵添加到此稀疏矩阵的指定块行和块列。
Definition: petsc_matrix.C:768
PetscScalar * pPS(T *ptr)
Definition: petsc_macro.h:172
virtual void print_personal(std::ostream &os=libMesh::out) const override
使用 PETSc 查看器将矩阵的内容打印到屏幕。 由于我们限制了一个 PETSc 实现,所以此函数仅允许打印到标准输出。
Definition: petsc_matrix.C:635
virtual std::unique_ptr< SparseMatrix< T > > zero_clone() const override
创建一个新的空矩阵,并将其所有元素置为零。
Definition: petsc_matrix.C:461
const Number zero
.
Definition: libmesh.h:248
void swap(PetscMatrix< T > &)
交换两个 PetscMatrix 的内部数据指针,不交换实际值。
numeric_index_type local_n() const
获取由该进程拥有的矩阵列数。
virtual void add_sparse_matrix(const SparseMatrix< T > &spm, const std::map< numeric_index_type, numeric_index_type > &row_ltog, const std::map< numeric_index_type, numeric_index_type > &col_ltog, const T scalar) override
将标量乘以稀疏矩阵 spm 添加到此矩阵的指定行和列。
Vec vec()
获取当前向量的原始 PETSc Vec 指针。
Definition: petsc_vector.h:641
virtual std::unique_ptr< SparseMatrix< T > > clone() const override
克隆当前矩阵。
Definition: petsc_matrix.C:483
virtual void clear()=0
恢复 SparseMatrix&lt;T&gt; 到原始状态。
PetscInt * numeric_petsc_cast(const numeric_index_type *p)
virtual bool initialized() const
这是一个通用的稀疏矩阵类。该类包含了必须在派生类中覆盖的纯虚拟成员。 使用一个公共的基类允许从不同的求解器包中以不同的格式统一访问稀疏矩阵。
Definition: dof_map.h:66
PetscScalar PS(T val)
Definition: petsc_macro.h:166
virtual ~PetscMatrix()
析构函数,释放矩阵资源。
Definition: petsc_matrix.C:109
void libmesh_ignore(const Args &...)
dof_id_type numeric_index_type
Definition: id_types.h:99
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:242
unsigned int m() const
返回矩阵的行维度。
bool _is_initialized
标志,指示矩阵是否已初始化。
int mkstemp(char *tmpl)
Definition: win_mkstemp.h:13
virtual numeric_index_type m() const =0
T * get()
获取托管对象的指针。 这用于模拟以下代码: KSP ksp; KSPCreate(comm, &amp;ksp); 因为在这种上下文中,取包装对象的地址是没有意义的。
void stop(const char *file, int line, const char *date, const char *time)
virtual numeric_index_type row_stop() const override
获取本地处理的行的结束索引。
virtual void get_row(numeric_index_type i, std::vector< numeric_index_type > &indices, std::vector< T > &values) const override
获取矩阵中指定行的索引和值。
virtual void create_submatrix_nosort(SparseMatrix< T > &submatrix, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols) const override
根据给定的 rows 和 cols 向量中的索引创建一个子矩阵,类似于 create_submatrix 函数。
Definition: petsc_matrix.C:863
std::vector< T > & get_values()
返回对应于存储向量的引用的底层数据存储矢量。
Definition: dense_matrix.h:488
virtual void set_destroy_mat_on_exit(bool destroy=true)
设置析构时是否删除 Mat 对象。如果设置为 false,则允许 PETSc 管理它。
virtual numeric_index_type m() const override
获取矩阵的行数。
virtual void matrix_matrix_mult(SparseMatrix< T > &X, SparseMatrix< T > &Y, bool reuse=false) override
计算 Y = A*X,其中 A 是当前矩阵,X 是另一个矩阵。
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value) override
在矩阵的特定位置添加值。
virtual void get_diagonal(NumericVector< T > &dest) const override
获取矩阵的对角线并将其存储在给定的向量中。
Definition: petsc_matrix.C:937
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual bool closed() const override
检查矩阵是否已经关闭,即所有的插入和添加操作是否已经完成。
virtual numeric_index_type row_start() const override
获取本地处理的行的起始索引。
virtual void get_transpose(SparseMatrix< T > &dest) const override
获取矩阵的转置。
Definition: petsc_matrix.C:950
virtual Real l1_norm() const override
计算矩阵的 L1 范数。
Definition: petsc_matrix.C:522
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols) override
将稠密矩阵添加到此稀疏矩阵的指定行和列。
Definition: petsc_matrix.C:741
virtual void set(const numeric_index_type i, const numeric_index_type j, const T value) override
设置矩阵中特定位置的值。
这个类提供了一个方便的接口,用于操作并行稀疏矩阵的 PETSc C 库数据结构。 所有覆盖的虚拟函数都在 sparse_matrix.h 中有详细的文档说明。
Definition: petsc_matrix.h:92
bool initialized()
Checks that library initialization has been done.
Definition: libmesh.C:261
Mat _mat
用于存储值的 PETSc 矩阵数据类型。
Definition: petsc_matrix.h:503
virtual void _get_submatrix(SparseMatrix< T > &submatrix, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols, const bool reuse_submatrix) const override
创建或重新初始化一个由 rows 和 cols 向量中给出的索引定义的矩阵 submatrix。
Definition: petsc_matrix.C:812
virtual void zero_rows(std::vector< numeric_index_type > &rows, T diag_value=0.0) override
将指定行的所有元素置为零,并在对角线位置放置一个指定值。
Definition: petsc_matrix.C:438
定义用于有限元类型计算的密集矩阵。 用于在求和成全局矩阵之前存储单元刚度矩阵。所有被覆盖的虚函数都记录在dense_matrix_base.h中。
Definition: dof_map.h:65
virtual void flush() override
刷新矩阵的内部缓冲区,确保所有操作都已完成。
Definition: petsc_matrix.C:998
virtual void close() override
完成任何挂起的插入或添加操作。
Definition: petsc_matrix.C:983
virtual Real linfty_norm() const override
计算矩阵的无穷范数。
Definition: petsc_matrix.C:545
virtual numeric_index_type n() const =0