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