Loading [MathJax]/extensions/tex2jax.js
libMesh
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
petsc_linear_solver.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 #include "libmesh/libmesh_common.h"
19 
20 #ifdef LIBMESH_HAVE_PETSC
21 
22 
23 // Local Includes
24 #include "libmesh/dof_map.h"
25 #include "libmesh/libmesh_logging.h"
26 #include "libmesh/petsc_linear_solver.h"
27 #include "libmesh/shell_matrix.h"
28 #include "libmesh/petsc_matrix.h"
29 #include "libmesh/petsc_preconditioner.h"
30 #include "libmesh/petsc_vector.h"
31 #include "libmesh/enum_to_string.h"
32 #include "libmesh/system.h"
33 #include "libmesh/petsc_auto_fieldsplit.h"
34 #include "libmesh/solver_configuration.h"
35 #include "libmesh/enum_preconditioner_type.h"
36 #include "libmesh/enum_solver_type.h"
37 #include "libmesh/enum_convergence_flags.h"
38 
39 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \
40  !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE)
41 #include <HYPRE_utilities.h>
42 #endif
43 
44 // C++ includes
45 #include <memory>
46 #include <string.h>
47 
48 namespace libMesh
49 {
50 
51 extern "C"
52 {
53  PetscErrorCode libmesh_petsc_preconditioner_setup (PC pc)
54  {
55  PetscFunctionBegin;
56 
57  void * ctx;
58  LibmeshPetscCallQ(PCShellGetContext(pc,&ctx));
59  Preconditioner<Number> * preconditioner = static_cast<Preconditioner<Number> *>(ctx);
60 
61  libmesh_error_msg_if(!preconditioner->initialized(),
62  "Preconditioner not initialized! Make sure you call init() before solve!");
63 
64  preconditioner->setup();
65 
66  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
67  }
68 
69  PetscErrorCode libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
70  {
71  PetscFunctionBegin;
72 
73  void * ctx;
74  LibmeshPetscCallQ(PCShellGetContext(pc,&ctx));
75  Preconditioner<Number> * preconditioner = static_cast<Preconditioner<Number> *>(ctx);
76 
77  PetscVector<Number> x_vec(x, preconditioner->comm());
78  PetscVector<Number> y_vec(y, preconditioner->comm());
79 
80  preconditioner->apply(x_vec,y_vec);
81 
82  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
83  }
84 
85 #ifdef LIBMESH_ENABLE_DEPRECATED
86  PetscErrorCode __libmesh_petsc_preconditioner_setup (PC pc)
87  {
88  PetscFunctionBegin;
89  libmesh_deprecated();
91  }
92 
93  PetscErrorCode __libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
94  {
95  PetscFunctionBegin;
96  libmesh_deprecated();
98  }
99 #endif
100 } // end extern "C"
101 
102 
103 
104 template <typename T>
106  LinearSolver<T>(comm_in),
107  _restrict_solve_to_is(nullptr),
108  _restrict_solve_to_is_complement(nullptr),
109  _subset_solve_mode(SUBSET_ZERO)
110 {
111  if (this->n_processors() == 1)
112  this->_preconditioner_type = ILU_PRECOND;
113  else
114  this->_preconditioner_type = BLOCK_JACOBI_PRECOND;
115 }
116 
117 
118 
119 template <typename T>
121 {
122  if (this->initialized())
123  {
124  this->_is_initialized = false;
125 
126  // Calls specialized destroy() functions
127  if (_restrict_solve_to_is)
128  _restrict_solve_to_is.reset_to_zero();
129  if (_restrict_solve_to_is_complement)
130  _restrict_solve_to_is_complement.reset_to_zero();
131 
132  // Previously we only called KSPDestroy(), we did not reset _ksp
133  // to nullptr, so that behavior is maintained here.
134  _ksp.destroy();
135 
136  // Mimic PETSc default solver and preconditioner
137  this->_solver_type = GMRES;
138 
139  if (!this->_preconditioner)
140  {
141  if (this->n_processors() == 1)
142  this->_preconditioner_type = ILU_PRECOND;
143  else
144  this->_preconditioner_type = BLOCK_JACOBI_PRECOND;
145  }
146  }
147 }
148 
149 
150 
151 template <typename T>
152 void PetscLinearSolver<T>::init (const char * name)
153 {
154  // Initialize the data structures if not done so already.
155  if (!this->initialized())
156  {
157  this->_is_initialized = true;
158 
159  LibmeshPetscCall(KSPCreate(this->comm().get(), _ksp.get()));
160 
161  if (name)
162  LibmeshPetscCall(KSPSetOptionsPrefix(_ksp, name));
163 
164  // Create the preconditioner context
165  LibmeshPetscCall(KSPGetPC(_ksp, &_pc));
166 
167  // Set user-specified solver and preconditioner types
168  this->set_petsc_solver_type();
169 
170  // If the SolverConfiguration object is provided, use it to set
171  // options during solver initialization.
172  if (this->_solver_configuration)
173  {
174  this->_solver_configuration->set_options_during_init();
175  }
176 
177  // Set the options from user-input
178  // Set runtime options, e.g.,
179  // -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol>
180  // These options will override those specified above as long as
181  // KSPSetFromOptions() is called _after_ any other customization
182  // routines.
183  LibmeshPetscCall(KSPSetFromOptions(_ksp));
184 
185  // Have the Krylov subspace method use our good initial guess
186  // rather than 0, unless the user requested a KSPType of
187  // preonly, which complains if asked to use initial guesses.
188  KSPType ksp_type;
189 
190  LibmeshPetscCall(KSPGetType(_ksp, &ksp_type));
191 
192  if (strcmp(ksp_type, "preonly"))
193  LibmeshPetscCall(KSPSetInitialGuessNonzero(_ksp, PETSC_TRUE));
194 
195  // Notify PETSc of location to store residual history.
196  // This needs to be called before any solves, since
197  // it sets the residual history length to zero. The default
198  // behavior is for PETSc to allocate (internally) an array
199  // of size 1000 to hold the residual norm history.
200  LibmeshPetscCall(KSPSetResidualHistory(_ksp,
201  LIBMESH_PETSC_NULLPTR, // pointer to the array which holds the history
202  PETSC_DECIDE, // size of the array holding the history
203  PETSC_TRUE)); // Whether or not to reset the history for each solve.
204 
205  PetscPreconditioner<T>::set_petsc_preconditioner_type(this->_preconditioner_type,_pc);
206 
207  //If there is a preconditioner object we need to set the internal setup and apply routines
208  if (this->_preconditioner)
209  {
210  this->_preconditioner->init();
211  LibmeshPetscCall(PCShellSetContext(_pc,(void *)this->_preconditioner));
212  LibmeshPetscCall(PCShellSetSetUp(_pc,libmesh_petsc_preconditioner_setup));
213  LibmeshPetscCall(PCShellSetApply(_pc,libmesh_petsc_preconditioner_apply));
214  }
215  }
216 }
217 
218 
219 template <typename T>
221  const char * name)
222 {
223  // Initialize the data structures if not done so already.
224  if (!this->initialized())
225  {
226  if (this->_preconditioner)
227  this->_preconditioner->set_matrix(*matrix);
228 
229  this->init(name);
230 
231  // Set operators. The input matrix works as the preconditioning matrix
232  LibmeshPetscCall(KSPSetOperators(_ksp, matrix->mat(), matrix->mat()));
233  }
234 }
235 
236 
237 
238 template <typename T>
239 void
241 {
242  petsc_auto_fieldsplit(this->pc(), sys);
243 }
244 
245 
246 
247 template <typename T>
248 void
249 PetscLinearSolver<T>::restrict_solve_to (const std::vector<unsigned int> * const dofs,
250  const SubsetSolveMode subset_solve_mode)
251 {
252  // The preconditioner (in particular if a default preconditioner)
253  // will have to be reset. We call this->clear() to do that. This
254  // call will also remove and free any previous subset that may have
255  // been set before.
256  this->clear();
257 
258  _subset_solve_mode = subset_solve_mode;
259 
260  if (dofs != nullptr)
261  {
262  PetscInt * petsc_dofs = nullptr;
263  LibmeshPetscCall(PetscMalloc(dofs->size()*sizeof(PetscInt), &petsc_dofs));
264 
265  for (auto i : index_range(*dofs))
266  petsc_dofs[i] = (*dofs)[i];
267 
268  // Create the IS
269  // PETSc now takes over ownership of the "petsc_dofs"
270  // array, so we don't have to worry about it any longer.
271  LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
272  cast_int<PetscInt>(dofs->size()),
273  petsc_dofs, PETSC_OWN_POINTER,
274  _restrict_solve_to_is.get()));
275  }
276 }
277 
278 
279 
280 template <typename T>
281 std::pair<unsigned int, Real>
283  SparseMatrix<T> & precond_in,
284  NumericVector<T> & solution_in,
285  NumericVector<T> & rhs_in,
286  const std::optional<double> tol,
287  const std::optional<unsigned int> m_its)
288 {
289  LOG_SCOPE("solve()", "PetscLinearSolver");
290 
291  const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
292  const double abs_tol = this->get_real_solver_setting("abs_tol",
293  std::nullopt,
294  static_cast<double>(PETSC_DEFAULT));
295  const double max_its = this->get_int_solver_setting("max_its", m_its);
296 
297  return this->solve_common(matrix_in, precond_in, solution_in,
298  rhs_in, rel_tol, abs_tol, max_its, KSPSolve);
299 }
300 
301 template <typename T>
302 std::pair<unsigned int, Real>
304  NumericVector<T> & solution_in,
305  NumericVector<T> & rhs_in,
306  const std::optional<double> tol,
307  const std::optional<unsigned int> m_its)
308 {
309  LOG_SCOPE("adjoint_solve()", "PetscLinearSolver");
310 
311  const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
312  const double abs_tol = this->get_real_solver_setting("abs_tol",
313  std::nullopt,
314  static_cast<double>(PETSC_DEFAULT));
315  const double max_its = this->get_int_solver_setting("max_its", m_its);
316 
317  // Note that the matrix and precond matrix are the same
318  return this->solve_common(matrix_in, matrix_in, solution_in,
319  rhs_in, rel_tol, abs_tol, max_its, KSPSolveTranspose);
320 }
321 
322 
323 template <typename T>
324 std::pair<unsigned int, Real>
326  SparseMatrix<T> & precond_in,
327  NumericVector<T> & solution_in,
328  NumericVector<T> & rhs_in,
329  const double rel_tol,
330  const double abs_tol,
331  const unsigned int m_its,
332  ksp_solve_func_type solve_func)
333 {
334  // Make sure the data passed in are really of Petsc types
335  PetscMatrixBase<T> * matrix = cast_ptr<PetscMatrixBase<T> *>(&matrix_in);
336  PetscMatrixBase<T> * precond = cast_ptr<PetscMatrixBase<T> *>(&precond_in);
337 
338  this->init (matrix);
339 
340  // Close the matrices in case this wasn't already done.
341  matrix->close ();
342  if (precond != matrix)
343  precond->close ();
344 
345  auto mat = matrix->mat();
346 
347  return this->solve_base
348  (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, solve_func);
349 }
350 
351 
352 template <typename T>
353 std::pair<unsigned int, Real>
355  NumericVector<T> & solution_in,
356  NumericVector<T> & rhs_in,
357  const std::optional<double> tol,
358  const std::optional<unsigned int> m_its)
359 {
360  LOG_SCOPE("solve()", "PetscLinearSolver");
361 
362  const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
363  const double abs_tol = this->get_real_solver_setting("abs_tol",
364  std::nullopt,
365  static_cast<double>(PETSC_DEFAULT));
366  const double max_its = this->get_int_solver_setting("max_its", m_its);
367 
368  return this->shell_solve_common(shell_matrix, nullptr, solution_in,
369  rhs_in, rel_tol, abs_tol, max_its);
370 }
371 
372 
373 
374 template <typename T>
375 std::pair<unsigned int, Real>
377  const SparseMatrix<T> & precond_matrix,
378  NumericVector<T> & solution_in,
379  NumericVector<T> & rhs_in,
380  const std::optional<double> tol,
381  const std::optional<unsigned int> m_its)
382 {
383  const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
384  const double abs_tol = this->get_real_solver_setting("abs_tol",
385  std::nullopt,
386  static_cast<double>(PETSC_DEFAULT));
387  const double max_its = this->get_int_solver_setting("max_its", m_its);
388 
389  // Make sure the data passed in are really of Petsc types
390  const PetscMatrixBase<T> * precond = cast_ptr<const PetscMatrixBase<T> *>(&precond_matrix);
391 
392  return this->shell_solve_common
393  (shell_matrix, const_cast<PetscMatrixBase<T> *>(precond), solution_in,
394  rhs_in, rel_tol, abs_tol, max_its);
395 }
396 
397 
398 
399 template <typename T>
400 std::pair<unsigned int, Real>
402  PetscMatrixBase<T> * precond,
403  NumericVector<T> & solution_in,
404  NumericVector<T> & rhs_in,
405  const double rel_tol,
406  const double abs_tol,
407  const unsigned int m_its)
408 {
409  LOG_SCOPE("solve()", "PetscLinearSolver");
410 
411  // We don't really have a matrix for our matrix here
412  SparseMatrix<T> * matrix = nullptr;
413 
414  this->init ();
415 
416  // Prepare the matrix.
417  WrappedPetsc<Mat> mat;
418  LibmeshPetscCall(MatCreateShell(this->comm().get(),
419  rhs_in.local_size(),
420  solution_in.local_size(),
421  rhs_in.size(),
422  solution_in.size(),
423  const_cast<void *>(static_cast<const void *>(&shell_matrix)),
424  mat.get()));
425  // Note that the const_cast above is only necessary because PETSc
426  // does not accept a const void *. Inside the member function
427  // _petsc_shell_matrix() below, the pointer is casted back to a
428  // const ShellMatrix<T> *.
429 
430  LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT, reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)));
431  LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT_ADD, reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult_add)));
432  LibmeshPetscCall(MatShellSetOperation(mat, MATOP_GET_DIAGONAL, reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)));
433 
434  return this->solve_base
435  (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, KSPSolve);
436 }
437 
438 
439 
440 template <typename T>
441 std::pair<unsigned int, Real>
443  PetscMatrixBase<T> * precond,
444  Mat mat,
445  NumericVector<T> & solution_in,
446  NumericVector<T> & rhs_in,
447  const double rel_tol,
448  const double abs_tol,
449  const unsigned int m_its,
450  ksp_solve_func_type solve_func)
451 {
452  // Make sure the data passed in are really of Petsc types
453  PetscVector<T> * solution = cast_ptr<PetscVector<T> *>(&solution_in);
454  PetscVector<T> * rhs = cast_ptr<PetscVector<T> *>(&rhs_in);
455 
456  // Close the vectors in case this wasn't already done.
457  solution->close ();
458  rhs->close ();
459 
460  PetscInt its=0, max_its = static_cast<PetscInt>(m_its);
461  PetscReal final_resid=0.;
462 
463  std::unique_ptr<PetscMatrixBase<Number>> subprecond_matrix;
464  WrappedPetsc<Mat> subprecond;
465 
466  WrappedPetsc<Mat> submat;
467  WrappedPetsc<Vec> subrhs;
468  WrappedPetsc<Vec> subsolution;
469  WrappedPetsc<VecScatter> scatter;
470 
471  // Restrict rhs and solution vectors and set operators. The input
472  // matrix works as the preconditioning matrix.
473  if (_restrict_solve_to_is)
474  {
475  PetscInt is_local_size = this->restrict_solve_to_is_local_size();
476 
477  LibmeshPetscCall(VecCreate(this->comm().get(), subrhs.get()));
478  LibmeshPetscCall(VecSetSizes(subrhs, is_local_size, PETSC_DECIDE));
479  LibmeshPetscCall(VecSetFromOptions(subrhs));
480 
481  LibmeshPetscCall(VecCreate(this->comm().get(), subsolution.get()));
482  LibmeshPetscCall(VecSetSizes(subsolution, is_local_size, PETSC_DECIDE));
483  LibmeshPetscCall(VecSetFromOptions(subsolution));
484 
485  LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is, subrhs, nullptr, scatter.get()));
486 
487  VecScatterBeginEnd(this->comm(), scatter, rhs->vec(), subrhs, INSERT_VALUES, SCATTER_FORWARD);
488  VecScatterBeginEnd(this->comm(), scatter, solution->vec(), subsolution, INSERT_VALUES, SCATTER_FORWARD);
489 
490  LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
491  _restrict_solve_to_is,
492  _restrict_solve_to_is,
493  MAT_INITIAL_MATRIX,
494  submat.get()));
495 
496  if (precond)
497  LibmeshPetscCall(LibMeshCreateSubMatrix(const_cast<PetscMatrixBase<T> *>(precond)->mat(),
498  _restrict_solve_to_is,
499  _restrict_solve_to_is,
500  MAT_INITIAL_MATRIX,
501  subprecond.get()));
502 
503  // Since removing columns of the matrix changes the equation
504  // system, we will now change the right hand side to compensate
505  // for this. Note that this is not necessary if \p SUBSET_ZERO
506  // has been selected.
507  if (_subset_solve_mode!=SUBSET_ZERO)
508  {
509  this->create_complement_is(rhs_in);
510  PetscInt is_complement_local_size =
511  cast_int<PetscInt>(rhs_in.local_size()-is_local_size);
512 
513  WrappedPetsc<Vec> subvec1;
514  LibmeshPetscCall(VecCreate(this->comm().get(), subvec1.get()));
515  LibmeshPetscCall(VecSetSizes(subvec1, is_complement_local_size, PETSC_DECIDE));
516  LibmeshPetscCall(VecSetFromOptions(subvec1));
517 
518  WrappedPetsc<VecScatter> scatter1;
519  LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is_complement, subvec1, nullptr, scatter1.get()));
520 
521  VecScatterBeginEnd(this->comm(), scatter1, _subset_solve_mode==SUBSET_COPY_RHS ? rhs->vec() : solution->vec(), subvec1, INSERT_VALUES, SCATTER_FORWARD);
522 
523  LibmeshPetscCall(VecScale(subvec1, -1.0));
524 
525  WrappedPetsc<Mat> submat1;
526  LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
527  _restrict_solve_to_is,
528  _restrict_solve_to_is_complement,
529  MAT_INITIAL_MATRIX,
530  submat1.get()));
531 
532  LibmeshPetscCall(MatMultAdd(submat1, subvec1, subrhs, subrhs));
533  }
534 
535  if (precond)
536  LibmeshPetscCall(KSPSetOperators(_ksp, submat, subprecond));
537  else
538  LibmeshPetscCall(KSPSetOperators(_ksp, submat, submat));
539 
540  PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
541  LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
542 
543  if (precond && this->_preconditioner)
544  {
545  subprecond_matrix = std::make_unique<PetscMatrix<Number>>(subprecond, this->comm());
546  this->_preconditioner->set_matrix(*subprecond_matrix);
547  this->_preconditioner->init();
548  }
549  }
550  else
551  {
552  PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
553  LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
554 
555  if (precond)
556  LibmeshPetscCall(KSPSetOperators(_ksp, mat, const_cast<PetscMatrixBase<T> *>(precond)->mat()));
557  else
558  LibmeshPetscCall(KSPSetOperators(_ksp, mat, mat));
559 
560  if (this->_preconditioner)
561  {
562  if (matrix)
563  this->_preconditioner->set_matrix(*matrix);
564  else if (precond)
565  this->_preconditioner->set_matrix(const_cast<PetscMatrixBase<Number> &>(*precond));
566 
567  this->_preconditioner->init();
568  }
569  }
570 
571  // Set the tolerances for the iterative solver. Use the user-supplied
572  // tolerance for the relative residual & leave the others at default values.
573  LibmeshPetscCall(KSPSetTolerances(_ksp, rel_tol, abs_tol,
574  PETSC_DEFAULT, max_its));
575 
576  // Allow command line options to override anything set programmatically.
577  LibmeshPetscCall(KSPSetFromOptions(_ksp));
578 
579 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \
580  !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE)
581  {
582  // Make sure hypre has been initialized
583  LibmeshPetscCallExternal(HYPRE_Initialize);
584  PetscScalar * dummyarray;
585  PetscMemType mtype;
586  LibmeshPetscCall(VecGetArrayAndMemType(solution->vec(), &dummyarray, &mtype));
587  LibmeshPetscCall(VecRestoreArrayAndMemType(solution->vec(), &dummyarray));
588  if (PetscMemTypeHost(mtype))
589  LibmeshPetscCallExternal(HYPRE_SetMemoryLocation, HYPRE_MEMORY_HOST);
590  }
591 #endif
592 
593  // If the SolverConfiguration object is provided, use it to override
594  // solver options.
595  if (this->_solver_configuration)
596  {
597  this->_solver_configuration->configure_solver();
598  }
599 
600  // Solve the linear system
601  if (_restrict_solve_to_is)
602  LibmeshPetscCall(solve_func (_ksp, subrhs, subsolution));
603  else
604  LibmeshPetscCall(solve_func (_ksp, rhs->vec(), solution->vec()));
605 
606  // Get the number of iterations required for convergence
607  LibmeshPetscCall(KSPGetIterationNumber (_ksp, &its));
608 
609  // Get the norm of the final residual to return to the user.
610  LibmeshPetscCall(KSPGetResidualNorm (_ksp, &final_resid));
611 
612  if (_restrict_solve_to_is)
613  {
614  switch(_subset_solve_mode)
615  {
616  case SUBSET_ZERO:
617  LibmeshPetscCall(VecZeroEntries(solution->vec()));
618  break;
619 
620  case SUBSET_COPY_RHS:
621  LibmeshPetscCall(VecCopy(rhs->vec(),solution->vec()));
622  break;
623 
624  case SUBSET_DONT_TOUCH:
625  // Nothing to do here.
626  break;
627 
628  default:
629  libmesh_error_msg("Invalid subset solve mode = " << _subset_solve_mode);
630  }
631 
632  VecScatterBeginEnd(this->comm(), scatter, subsolution, solution->vec(), INSERT_VALUES, SCATTER_REVERSE);
633 
634  if (precond && this->_preconditioner)
635  {
636  // Before subprecond_matrix gets cleaned up, we should give
637  // the _preconditioner a different matrix.
638  if (matrix)
639  this->_preconditioner->set_matrix(*matrix);
640  else
641  this->_preconditioner->set_matrix(*precond);
642 
643  this->_preconditioner->init();
644  }
645  }
646 
647  // return the # of its. and the final residual norm.
648  return std::make_pair(its, final_resid);
649 }
650 
651 
652 
653 template <typename T>
655 {
656  this->init();
657  return _ksp;
658 }
659 
660 template <typename T>
661 void PetscLinearSolver<T>::get_residual_history(std::vector<double> & hist)
662 {
663  PetscInt its = 0;
664 
665  // Fill the residual history vector with the residual norms
666  // Note that GetResidualHistory() does not copy any values, it
667  // simply sets the pointer p. Note that for some Krylov subspace
668  // methods, the number of residuals returned in the history
669  // vector may be different from what you are expecting. For
670  // example, TFQMR returns two residual values per iteration step.
671 
672  // Recent versions of PETSc require the residual
673  // history vector pointer to be declared as const.
674 #if PETSC_VERSION_LESS_THAN(3,15,0)
675  PetscReal * p;
676 #else
677  const PetscReal * p;
678 #endif
679 
680  LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
681 
682  // Check for early return
683  if (its == 0) return;
684 
685  // Create space to store the result
686  hist.resize(its);
687 
688  // Copy history into the vector provided by the user.
689  for (PetscInt i=0; i<its; ++i)
690  {
691  hist[i] = *p;
692  p++;
693  }
694 }
695 
696 
697 
698 
699 template <typename T>
701 {
702  PetscInt its = 0;
703 
704  // Fill the residual history vector with the residual norms
705  // Note that GetResidualHistory() does not copy any values, it
706  // simply sets the pointer p. Note that for some Krylov subspace
707  // methods, the number of residuals returned in the history
708  // vector may be different from what you are expecting. For
709  // example, TFQMR returns two residual values per iteration step.
710 
711  // Recent versions of PETSc require the residual
712  // history vector pointer to be declared as const.
713 #if PETSC_VERSION_LESS_THAN(3,15,0)
714  PetscReal * p;
715 #else
716  const PetscReal * p;
717 #endif
718 
719 
720  LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
721 
722  // Check no residual history
723  if (its == 0)
724  {
725  libMesh::err << "No iterations have been performed, returning 0." << std::endl;
726  return 0.;
727  }
728 
729  // Otherwise, return the value pointed to by p.
730  return *p;
731 }
732 
733 
734 
735 
736 template <typename T>
738 {
739  #define CaseKSPSetType(SolverType, KSPT) \
740  case SolverType: \
741  LibmeshPetscCall(KSPSetType (_ksp, const_cast<KSPType>(KSPT))); \
742  return;
743 
744  switch (this->_solver_type)
745  {
746  CaseKSPSetType(CG, KSPCG)
747  CaseKSPSetType(CR, KSPCR)
748  CaseKSPSetType(CGS, KSPCGS)
749  CaseKSPSetType(BICG, KSPBICG)
750  CaseKSPSetType(TCQMR, KSPTCQMR)
751  CaseKSPSetType(TFQMR, KSPTFQMR)
752  CaseKSPSetType(LSQR, KSPLSQR)
753  CaseKSPSetType(BICGSTAB, KSPBCGS)
754  CaseKSPSetType(MINRES, KSPMINRES)
755  CaseKSPSetType(GMRES, KSPGMRES)
756  CaseKSPSetType(RICHARDSON, KSPRICHARDSON)
757  CaseKSPSetType(CHEBYSHEV, KSPCHEBYSHEV)
758 
759  default:
760  libMesh::err << "ERROR: Unsupported PETSC Solver: "
761  << Utility::enum_to_string(this->_solver_type) << std::endl
762  << "Continuing with PETSC defaults" << std::endl;
763  }
764 }
765 
766 
767 
768 template <typename T>
770 {
771  KSPConvergedReason reason;
772  LibmeshPetscCall(KSPGetConvergedReason(_ksp, &reason));
773 
774  switch(reason)
775  {
776  case KSP_CONVERGED_RTOL_NORMAL : return CONVERGED_RTOL_NORMAL;
777  case KSP_CONVERGED_ATOL_NORMAL : return CONVERGED_ATOL_NORMAL;
778  case KSP_CONVERGED_RTOL : return CONVERGED_RTOL;
779  case KSP_CONVERGED_ATOL : return CONVERGED_ATOL;
780  case KSP_CONVERGED_ITS : return CONVERGED_ITS;
781 #if PETSC_VERSION_LESS_THAN(3,19,0)
782  case KSP_CONVERGED_CG_NEG_CURVE : return CONVERGED_CG_NEG_CURVE;
783  // This was deprecated for STEP_LENGTH
784  case KSP_CONVERGED_CG_CONSTRAINED : return CONVERGED_CG_CONSTRAINED;
785 #else
786  case KSP_CONVERGED_NEG_CURVE : return CONVERGED_CG_NEG_CURVE;
787 #endif
788  case KSP_CONVERGED_STEP_LENGTH : return CONVERGED_STEP_LENGTH;
789  case KSP_CONVERGED_HAPPY_BREAKDOWN : return CONVERGED_HAPPY_BREAKDOWN;
790  case KSP_DIVERGED_NULL : return DIVERGED_NULL;
791  case KSP_DIVERGED_ITS : return DIVERGED_ITS;
792  case KSP_DIVERGED_DTOL : return DIVERGED_DTOL;
793  case KSP_DIVERGED_BREAKDOWN : return DIVERGED_BREAKDOWN;
794  case KSP_DIVERGED_BREAKDOWN_BICG : return DIVERGED_BREAKDOWN_BICG;
795  case KSP_DIVERGED_NONSYMMETRIC : return DIVERGED_NONSYMMETRIC;
796  case KSP_DIVERGED_INDEFINITE_PC : return DIVERGED_INDEFINITE_PC;
797  case KSP_DIVERGED_NANORINF : return DIVERGED_NAN;
798  case KSP_DIVERGED_INDEFINITE_MAT : return DIVERGED_INDEFINITE_MAT;
799  case KSP_CONVERGED_ITERATING : return CONVERGED_ITERATING;
800 #if !PETSC_VERSION_LESS_THAN(3,7,0)
801 // PETSc-3.7.0 to 3.10.x
802 #if PETSC_VERSION_LESS_THAN(3,11,0) && PETSC_VERSION_RELEASE
803  case KSP_DIVERGED_PCSETUP_FAILED : return DIVERGED_PCSETUP_FAILED;
804 // PETSc master and future PETSc
805 #else
806  case KSP_DIVERGED_PC_FAILED : return DIVERGED_PCSETUP_FAILED;
807 #endif
808 #endif
809  default :
810  libMesh::err << "Unknown convergence flag!" << std::endl;
811  return UNKNOWN_FLAG;
812  }
813 }
814 
815 
816 template <typename T>
817 PetscErrorCode PetscLinearSolver<T>::_petsc_shell_matrix_mult(Mat mat, Vec arg, Vec dest)
818 {
819  PetscFunctionBegin;
820 
821  // Get the matrix context.
822  void * ctx;
823  PetscErrorCode ierr = MatShellGetContext(mat,&ctx);
824 
825  // Get user shell matrix object.
826  const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
827  CHKERRABORT(shell_matrix.comm().get(), ierr);
828 
829  // Make \p NumericVector instances around the vectors.
830  PetscVector<T> arg_global(arg, shell_matrix.comm());
831  PetscVector<T> dest_global(dest, shell_matrix.comm());
832 
833  // Call the user function.
834  shell_matrix.vector_mult(dest_global,arg_global);
835 
836  PetscFunctionReturn(ierr);
837 }
838 
839 
840 
841 template <typename T>
842 PetscErrorCode PetscLinearSolver<T>::_petsc_shell_matrix_mult_add(Mat mat, Vec arg, Vec add, Vec dest)
843 {
844  PetscFunctionBegin;
845 
846  // Get the matrix context.
847  void * ctx;
848  PetscErrorCode ierr = MatShellGetContext(mat,&ctx);
849 
850  // Get user shell matrix object.
851  const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
852  CHKERRABORT(shell_matrix.comm().get(), ierr);
853 
854  // Make \p NumericVector instances around the vectors.
855  PetscVector<T> arg_global(arg, shell_matrix.comm());
856  PetscVector<T> dest_global(dest, shell_matrix.comm());
857  PetscVector<T> add_global(add, shell_matrix.comm());
858 
859  if (add!=arg)
860  {
861  arg_global = add_global;
862  }
863 
864  // Call the user function.
865  shell_matrix.vector_mult_add(dest_global,arg_global);
866 
867  PetscFunctionReturn(ierr);
868 }
869 
870 
871 
872 template <typename T>
874 {
875  PetscFunctionBegin;
876 
877  // Get the matrix context.
878  void * ctx;
879  PetscErrorCode ierr = MatShellGetContext(mat,&ctx);
880 
881  // Get user shell matrix object.
882  const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
883  CHKERRABORT(shell_matrix.comm().get(), ierr);
884 
885  // Make \p NumericVector instances around the vector.
886  PetscVector<T> dest_global(dest, shell_matrix.comm());
887 
888  // Call the user function.
889  shell_matrix.get_diagonal(dest_global);
890 
891  PetscFunctionReturn(ierr);
892 }
893 
894 
895 
896 template <typename T>
897 void
899 {
900  libmesh_assert(_restrict_solve_to_is);
901  if (!_restrict_solve_to_is_complement)
902  LibmeshPetscCall(ISComplement(_restrict_solve_to_is,
903  vec_in.first_local_index(),
904  vec_in.last_local_index(),
905  _restrict_solve_to_is_complement.get()));
906 }
907 
908 
909 template <typename T>
910 PetscInt
912 {
913  libmesh_assert(_restrict_solve_to_is);
914 
915  PetscInt s;
916  LibmeshPetscCall(ISGetLocalSize(_restrict_solve_to_is, &s));
917 
918  return s;
919 }
920 
921 
922 //------------------------------------------------------------------
923 // Explicit instantiations
924 template class LIBMESH_EXPORT PetscLinearSolver<Number>;
925 
926 } // namespace libMesh
927 
928 
929 
930 #endif // #ifdef LIBMESH_HAVE_PETSC
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
OStreamProxy err
void petsc_auto_fieldsplit(PC my_pc, const System &sys)
This class provides a nice interface to PETSc&#39;s Vec object.
Definition: petsc_vector.h:73
This class provides an interface to the suite of preconditioners available from PETSc.
This class provides a nice interface to the PETSc C-based data structures for parallel, sparse matrices.
PetscErrorCode __libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
virtual numeric_index_type size() const =0
PetscErrorCode libmesh_petsc_preconditioner_apply(PC, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
virtual void apply(const NumericVector< T > &x, NumericVector< T > &y)=0
Computes the preconditioned vector y based on input vector x.
LinearConvergenceReason
Linear solver convergence flags (taken from the PETSc flags).
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
Definition: vector_fe_ex5.C:44
const Parallel::Communicator & comm() const
The libMesh namespace provides an interface to certain functionality in the library.
virtual bool initialized() const
virtual void vector_mult_add(NumericVector< T > &dest, const NumericVector< T > &arg) const =0
Multiplies the matrix with arg and adds the result to dest.
Generic sparse matrix.
Definition: vector_fe_ex5.C:46
This base class can be inherited from to provide interfaces to linear solvers from different packages...
PetscLinearSolver(const libMesh::Parallel::Communicator &comm_in)
Constructor.
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:257
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
libmesh_assert(ctx)
PetscErrorCode libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
PetscErrorCode __libmesh_petsc_preconditioner_setup(PC pc)
This function is called by PETSc to initialize the preconditioner.
virtual void close() override
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
std::string enum_to_string(const T e)
virtual void get_diagonal(NumericVector< T > &dest) const =0
Copies the diagonal part of the matrix into dest.
PetscErrorCode libmesh_petsc_preconditioner_setup(PC pc)
This function is called by PETSc to initialize the preconditioner.
virtual numeric_index_type first_local_index() const =0
LibmeshPetscCallQ(DMShellGetContext(dm, &ctx))
PetscErrorCode libmesh_petsc_preconditioner_setup(PC)
This function is called by PETSc to initialize the preconditioner.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This class provides an interface to PETSc iterative solvers that is compatible with the libMesh Linea...
virtual numeric_index_type local_size() const =0
bool initialized()
Checks that library initialization has been done.
Definition: libmesh.C:276
void * ctx
Generic shell matrix, i.e.
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
virtual void setup()
This is called every time the "operator might have changed".
SubsetSolveMode
defines an enum for the question what happens to the dofs outside the given subset when a system is s...
virtual void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const =0
Multiplies the matrix with arg and stores the result in dest.
virtual numeric_index_type last_local_index() const =0
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:117
virtual void close() override
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
Definition: petsc_vector.h:869