LCOV - code coverage report
Current view: top level - src/solvers - petsc_linear_solver.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4308 (b969c4) with base 7aa2c3 Lines: 201 314 64.0 %
Date: 2025-11-07 13:38:09 Functions: 19 25 76.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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         490 :   PetscErrorCode libmesh_petsc_preconditioner_setup (PC pc)
      54             :   {
      55             :     PetscFunctionBegin;
      56             : 
      57             :     void * ctx;
      58         490 :     LibmeshPetscCallQ(PCShellGetContext(pc,&ctx));
      59         490 :     Preconditioner<Number> * preconditioner = static_cast<Preconditioner<Number> *>(ctx);
      60             : 
      61         490 :     libmesh_error_msg_if(!preconditioner->initialized(),
      62             :                          "Preconditioner not initialized!  Make sure you call init() before solve!");
      63             : 
      64         490 :     preconditioner->setup();
      65             : 
      66         490 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
      67             :   }
      68             : 
      69        1330 :   PetscErrorCode libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
      70             :   {
      71             :     PetscFunctionBegin;
      72             : 
      73             :     void * ctx;
      74        1330 :     LibmeshPetscCallQ(PCShellGetContext(pc,&ctx));
      75        1330 :     Preconditioner<Number> * preconditioner = static_cast<Preconditioner<Number> *>(ctx);
      76             : 
      77        1406 :     PetscVector<Number> x_vec(x, preconditioner->comm());
      78        1368 :     PetscVector<Number> y_vec(y, preconditioner->comm());
      79             : 
      80        1330 :     preconditioner->apply(x_vec,y_vec);
      81             : 
      82        1368 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
      83        1254 :   }
      84             : } // end extern "C"
      85             : 
      86             : 
      87             : 
      88             : template <typename T>
      89       25902 : PetscLinearSolver<T>::PetscLinearSolver(const libMesh::Parallel::Communicator & comm_in) :
      90             :   LinearSolver<T>(comm_in),
      91             :   _restrict_solve_to_is(nullptr),
      92             :   _restrict_solve_to_is_complement(nullptr),
      93       25902 :   _subset_solve_mode(SUBSET_ZERO)
      94             : {
      95       26664 :   if (this->n_processors() == 1)
      96         373 :     this->_preconditioner_type = ILU_PRECOND;
      97             :   else
      98       25529 :     this->_preconditioner_type = BLOCK_JACOBI_PRECOND;
      99       25902 : }
     100             : 
     101             : 
     102             : 
     103             : template <typename T>
     104       36631 : void PetscLinearSolver<T>::clear ()
     105             : {
     106       36631 :   if (this->initialized())
     107             :     {
     108       24701 :       this->_is_initialized = false;
     109             : 
     110             :       // Calls specialized destroy() functions
     111       24701 :       if (_restrict_solve_to_is)
     112         210 :         _restrict_solve_to_is.reset_to_zero();
     113       24701 :       if (_restrict_solve_to_is_complement)
     114           0 :         _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       24701 :       _ksp.destroy();
     119             : 
     120             :       // Mimic PETSc default solver and preconditioner
     121       24701 :       this->_solver_type = GMRES;
     122             : 
     123       24701 :       if (!this->_preconditioner)
     124             :         {
     125       25417 :           if (this->n_processors() == 1)
     126         347 :             this->_preconditioner_type = ILU_PRECOND;
     127             :           else
     128       24214 :             this->_preconditioner_type = BLOCK_JACOBI_PRECOND;
     129             :         }
     130             :     }
     131       36631 : }
     132             : 
     133             : 
     134             : 
     135             : template <typename T>
     136      601971 : void PetscLinearSolver<T>::init (const char * name)
     137             : {
     138             :   // Initialize the data structures if not done so already.
     139      601971 :   if (!this->initialized())
     140             :     {
     141       47941 :       this->_is_initialized = true;
     142             : 
     143       47941 :       LibmeshPetscCall(KSPCreate(this->comm().get(), _ksp.get()));
     144             : 
     145       47941 :       if (name)
     146         490 :         LibmeshPetscCall(KSPSetOptionsPrefix(_ksp, name));
     147             : 
     148             :       // Create the preconditioner context
     149       47941 :       LibmeshPetscCall(KSPGetPC(_ksp, &_pc));
     150             : 
     151             :       // Set user-specified  solver and preconditioner types
     152       47941 :       this->set_petsc_solver_type();
     153             : 
     154             :       // If the SolverConfiguration object is provided, use it to set
     155             :       // options during solver initialization.
     156       47941 :       if (this->_solver_configuration)
     157             :         {
     158          70 :           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       47941 :       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       47941 :       LibmeshPetscCall(KSPGetType(_ksp, &ksp_type));
     175             : 
     176       47941 :       if (strcmp(ksp_type, "preonly"))
     177       47941 :         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       47941 :       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       47941 :       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       47941 :       if (this->_preconditioner)
     193             :         {
     194         210 :           this->_preconditioner->init();
     195         210 :           LibmeshPetscCall(PCShellSetContext(_pc,(void *)this->_preconditioner));
     196         210 :           LibmeshPetscCall(PCShellSetSetUp(_pc,libmesh_petsc_preconditioner_setup));
     197         210 :           LibmeshPetscCall(PCShellSetApply(_pc,libmesh_petsc_preconditioner_apply));
     198             :         }
     199             :     }
     200      601971 : }
     201             : 
     202             : 
     203             : template <typename T>
     204      433601 : void PetscLinearSolver<T>::init (PetscMatrixBase<T> * matrix,
     205             :                                  const char * name)
     206             : {
     207             :   // Initialize the data structures if not done so already.
     208      433601 :   if (!this->initialized())
     209             :     {
     210         786 :       if (this->_preconditioner)
     211           0 :         this->_preconditioner->set_matrix(*matrix);
     212             : 
     213         786 :       this->init(name);
     214             : 
     215             :       // Set operators. The input matrix works as the preconditioning matrix
     216         786 :       LibmeshPetscCall(KSPSetOperators(_ksp, matrix->mat(), matrix->mat()));
     217             :     }
     218      433601 : }
     219             : 
     220             : 
     221             : 
     222             : template <typename T>
     223             : void
     224      222596 : PetscLinearSolver<T>::init_names (const System & sys)
     225             : {
     226      222596 :   petsc_auto_fieldsplit(this->pc(), sys);
     227      222596 : }
     228             : 
     229             : 
     230             : 
     231             : template <typename T>
     232             : void
     233         420 : PetscLinearSolver<T>::restrict_solve_to (const std::vector<unsigned int> * const dofs,
     234             :                                          const SubsetSolveMode subset_solve_mode)
     235             : {
     236             :   // The preconditioner (in particular if a default preconditioner)
     237             :   // will have to be reset.  We call this->clear() to do that.  This
     238             :   // call will also remove and free any previous subset that may have
     239             :   // been set before.
     240         420 :   this->clear();
     241             : 
     242         420 :   _subset_solve_mode = subset_solve_mode;
     243             : 
     244         420 :   if (dofs != nullptr)
     245             :     {
     246         210 :       PetscInt * petsc_dofs = nullptr;
     247         216 :       LibmeshPetscCall(PetscMalloc(dofs->size()*sizeof(PetscInt), &petsc_dofs));
     248             : 
     249       65330 :       for (auto i : index_range(*dofs))
     250       65120 :         petsc_dofs[i] = (*dofs)[i];
     251             : 
     252             :       // Create the IS
     253             :       // PETSc now takes over ownership of the "petsc_dofs"
     254             :       // array, so we don't have to worry about it any longer.
     255         216 :       LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
     256             :                                        cast_int<PetscInt>(dofs->size()),
     257             :                                        petsc_dofs, PETSC_OWN_POINTER,
     258             :                                        _restrict_solve_to_is.get()));
     259             :     }
     260         420 : }
     261             : 
     262             : 
     263             : 
     264             : template <typename T>
     265             : std::pair<unsigned int, Real>
     266      408931 : PetscLinearSolver<T>::solve (SparseMatrix<T> &  matrix_in,
     267             :                              SparseMatrix<T> &  precond_in,
     268             :                              NumericVector<T> & solution_in,
     269             :                              NumericVector<T> & rhs_in,
     270             :                              const std::optional<double> tol,
     271             :                              const std::optional<unsigned int> m_its)
     272             : {
     273       23920 :   LOG_SCOPE("solve()", "PetscLinearSolver");
     274             : 
     275      817862 :   const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
     276      805902 :   const double abs_tol = this->get_real_solver_setting("abs_tol",
     277             :                                                        std::nullopt,
     278             :                                                        static_cast<double>(PETSC_DEFAULT));
     279      408931 :   const double max_its = this->get_int_solver_setting("max_its", m_its);
     280             : 
     281      385011 :   return this->solve_common(matrix_in, precond_in, solution_in,
     282      432851 :                             rhs_in, rel_tol, abs_tol, max_its, KSPSolve);
     283             : }
     284             : 
     285             : template <typename T>
     286             : std::pair<unsigned int, Real>
     287       24670 : PetscLinearSolver<T>::adjoint_solve (SparseMatrix<T> &  matrix_in,
     288             :                                      NumericVector<T> & solution_in,
     289             :                                      NumericVector<T> & rhs_in,
     290             :                                      const std::optional<double> tol,
     291             :                                      const std::optional<unsigned int> m_its)
     292             : {
     293        1596 :   LOG_SCOPE("adjoint_solve()", "PetscLinearSolver");
     294             : 
     295       49340 :   const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
     296       48542 :   const double abs_tol = this->get_real_solver_setting("abs_tol",
     297             :                                                        std::nullopt,
     298             :                                                        static_cast<double>(PETSC_DEFAULT));
     299       24670 :   const double max_its = this->get_int_solver_setting("max_its", m_its);
     300             : 
     301             :   // Note that the matrix and precond matrix are the same
     302       23074 :   return this->solve_common(matrix_in, matrix_in, solution_in,
     303       26266 :                             rhs_in, rel_tol, abs_tol, max_its, KSPSolveTranspose);
     304             : }
     305             : 
     306             : 
     307             : template <typename T>
     308             : std::pair<unsigned int, Real>
     309      433601 : PetscLinearSolver<T>::solve_common (SparseMatrix<T> &  matrix_in,
     310             :                                     SparseMatrix<T> &  precond_in,
     311             :                                     NumericVector<T> & solution_in,
     312             :                                     NumericVector<T> & rhs_in,
     313             :                                     const double rel_tol,
     314             :                                     const double abs_tol,
     315             :                                     const unsigned int m_its,
     316             :                                     ksp_solve_func_type solve_func)
     317             : {
     318             :   // Make sure the data passed in are really of Petsc types
     319       12758 :   PetscMatrixBase<T> * matrix   = cast_ptr<PetscMatrixBase<T> *>(&matrix_in);
     320       12758 :   PetscMatrixBase<T> * precond  = cast_ptr<PetscMatrixBase<T> *>(&precond_in);
     321             : 
     322      433601 :   this->init (matrix);
     323             : 
     324             :   // Close the matrices in case this wasn't already done.
     325      433601 :   matrix->close ();
     326      433601 :   if (precond != matrix)
     327           0 :     precond->close ();
     328             : 
     329       25516 :   auto mat = matrix->mat();
     330             : 
     331             :   return this->solve_base
     332      433601 :     (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, solve_func);
     333             : }
     334             : 
     335             : 
     336             : template <typename T>
     337             : std::pair<unsigned int, Real>
     338           0 : PetscLinearSolver<T>::solve (const ShellMatrix<T> & shell_matrix,
     339             :                              NumericVector<T> & solution_in,
     340             :                              NumericVector<T> & rhs_in,
     341             :                              const std::optional<double> tol,
     342             :                              const std::optional<unsigned int> m_its)
     343             : {
     344           0 :   LOG_SCOPE("solve()", "PetscLinearSolver");
     345             : 
     346           0 :   const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
     347           0 :   const double abs_tol = this->get_real_solver_setting("abs_tol",
     348             :                                                        std::nullopt,
     349             :                                                        static_cast<double>(PETSC_DEFAULT));
     350           0 :   const double max_its = this->get_int_solver_setting("max_its", m_its);
     351             : 
     352           0 :   return this->shell_solve_common(shell_matrix, nullptr, solution_in,
     353           0 :                                   rhs_in, rel_tol, abs_tol, max_its);
     354             : }
     355             : 
     356             : 
     357             : 
     358             : template <typename T>
     359             : std::pair<unsigned int, Real>
     360          70 : PetscLinearSolver<T>::solve (const ShellMatrix<T> & shell_matrix,
     361             :                              const SparseMatrix<T> & precond_matrix,
     362             :                              NumericVector<T> & solution_in,
     363             :                              NumericVector<T> & rhs_in,
     364             :                              const std::optional<double> tol,
     365             :                              const std::optional<unsigned int> m_its)
     366             : {
     367         140 :   const double rel_tol = this->get_real_solver_setting("rel_tol", tol);
     368         138 :   const double abs_tol = this->get_real_solver_setting("abs_tol",
     369             :                                                        std::nullopt,
     370             :                                                        static_cast<double>(PETSC_DEFAULT));
     371          70 :   const double max_its = this->get_int_solver_setting("max_its", m_its);
     372             : 
     373             :   // Make sure the data passed in are really of Petsc types
     374           2 :   const PetscMatrixBase<T> * precond  = cast_ptr<const PetscMatrixBase<T> *>(&precond_matrix);
     375             : 
     376             :   return this->shell_solve_common
     377          66 :     (shell_matrix, const_cast<PetscMatrixBase<T> *>(precond), solution_in,
     378          70 :      rhs_in, rel_tol, abs_tol, max_its);
     379             : }
     380             : 
     381             : 
     382             : 
     383             : template <typename T>
     384             : std::pair<unsigned int, Real>
     385          70 : PetscLinearSolver<T>::shell_solve_common (const ShellMatrix<T> & shell_matrix,
     386             :                                           PetscMatrixBase<T> * precond,
     387             :                                           NumericVector<T> & solution_in,
     388             :                                           NumericVector<T> & rhs_in,
     389             :                                           const double rel_tol,
     390             :                                           const double abs_tol,
     391             :                                           const unsigned int m_its)
     392             : {
     393           4 :   LOG_SCOPE("solve()", "PetscLinearSolver");
     394             : 
     395             :   // We don't really have a matrix for our matrix here
     396           2 :   SparseMatrix<T> * matrix = nullptr;
     397             : 
     398          70 :   this->init ();
     399             : 
     400             :   // Prepare the matrix.
     401           4 :   WrappedPetsc<Mat> mat;
     402          70 :   LibmeshPetscCall(MatCreateShell(this->comm().get(),
     403             :                                   rhs_in.local_size(),
     404             :                                   solution_in.local_size(),
     405             :                                   rhs_in.size(),
     406             :                                   solution_in.size(),
     407             :                                   const_cast<void *>(static_cast<const void *>(&shell_matrix)),
     408             :                                   mat.get()));
     409             :   // Note that the const_cast above is only necessary because PETSc
     410             :   // does not accept a const void *.  Inside the member function
     411             :   // _petsc_shell_matrix() below, the pointer is casted back to a
     412             :   // const ShellMatrix<T> *.
     413             : 
     414          70 :   LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT, reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult)));
     415          70 :   LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT_ADD, reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_mult_add)));
     416          70 :   LibmeshPetscCall(MatShellSetOperation(mat, MATOP_GET_DIAGONAL, reinterpret_cast<void(*)(void)>(_petsc_shell_matrix_get_diagonal)));
     417             : 
     418             :   return this->solve_base
     419         140 :     (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, KSPSolve);
     420             : }
     421             : 
     422             : 
     423             : 
     424             : template <typename T>
     425             : std::pair<unsigned int, Real>
     426      433671 : PetscLinearSolver<T>::solve_base (SparseMatrix<T> * matrix,
     427             :                                   PetscMatrixBase<T> * precond,
     428             :                                   Mat mat,
     429             :                                   NumericVector<T> & solution_in,
     430             :                                   NumericVector<T> & rhs_in,
     431             :                                   const double rel_tol,
     432             :                                   const double abs_tol,
     433             :                                   const unsigned int m_its,
     434             :                                   ksp_solve_func_type solve_func)
     435             : {
     436             :   // Make sure the data passed in are really of Petsc types
     437       12760 :   PetscVector<T> * solution = cast_ptr<PetscVector<T> *>(&solution_in);
     438       12760 :   PetscVector<T> * rhs      = cast_ptr<PetscVector<T> *>(&rhs_in);
     439             : 
     440             :   // Close the vectors in case this wasn't already done.
     441      433671 :   solution->close ();
     442      433671 :   rhs->close ();
     443             : 
     444      433671 :   PetscInt its=0, max_its = static_cast<PetscInt>(m_its);
     445      433671 :   PetscReal final_resid=0.;
     446             : 
     447      420911 :   std::unique_ptr<PetscMatrixBase<Number>> subprecond_matrix;
     448       25520 :   WrappedPetsc<Mat> subprecond;
     449             : 
     450       25520 :   WrappedPetsc<Mat> submat;
     451       25520 :   WrappedPetsc<Vec> subrhs;
     452       25520 :   WrappedPetsc<Vec> subsolution;
     453       12760 :   WrappedPetsc<VecScatter> scatter;
     454             : 
     455             :   // Restrict rhs and solution vectors and set operators.  The input
     456             :   // matrix works as the preconditioning matrix.
     457      433671 :   if (_restrict_solve_to_is)
     458             :     {
     459         210 :       PetscInt is_local_size = this->restrict_solve_to_is_local_size();
     460             : 
     461         210 :       LibmeshPetscCall(VecCreate(this->comm().get(), subrhs.get()));
     462         210 :       LibmeshPetscCall(VecSetSizes(subrhs, is_local_size, PETSC_DECIDE));
     463         210 :       LibmeshPetscCall(VecSetFromOptions(subrhs));
     464             : 
     465         210 :       LibmeshPetscCall(VecCreate(this->comm().get(), subsolution.get()));
     466         210 :       LibmeshPetscCall(VecSetSizes(subsolution, is_local_size, PETSC_DECIDE));
     467         210 :       LibmeshPetscCall(VecSetFromOptions(subsolution));
     468             : 
     469         210 :       LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is, subrhs, nullptr, scatter.get()));
     470             : 
     471         210 :       VecScatterBeginEnd(this->comm(), scatter, rhs->vec(), subrhs, INSERT_VALUES, SCATTER_FORWARD);
     472         210 :       VecScatterBeginEnd(this->comm(), scatter, solution->vec(), subsolution, INSERT_VALUES, SCATTER_FORWARD);
     473             : 
     474         210 :       LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
     475             :                                               _restrict_solve_to_is,
     476             :                                               _restrict_solve_to_is,
     477             :                                               MAT_INITIAL_MATRIX,
     478             :                                               submat.get()));
     479             : 
     480         210 :       if (precond)
     481         210 :         LibmeshPetscCall(LibMeshCreateSubMatrix(const_cast<PetscMatrixBase<T> *>(precond)->mat(),
     482             :                                                 _restrict_solve_to_is,
     483             :                                                 _restrict_solve_to_is,
     484             :                                                 MAT_INITIAL_MATRIX,
     485             :                                                 subprecond.get()));
     486             : 
     487             :       // Since removing columns of the matrix changes the equation
     488             :       // system, we will now change the right hand side to compensate
     489             :       // for this.  Note that this is not necessary if \p SUBSET_ZERO
     490             :       // has been selected.
     491         210 :       if (_subset_solve_mode!=SUBSET_ZERO)
     492             :         {
     493           0 :           this->create_complement_is(rhs_in);
     494             :           PetscInt is_complement_local_size =
     495           0 :             cast_int<PetscInt>(rhs_in.local_size()-is_local_size);
     496             : 
     497           0 :           WrappedPetsc<Vec> subvec1;
     498           0 :           LibmeshPetscCall(VecCreate(this->comm().get(), subvec1.get()));
     499           0 :           LibmeshPetscCall(VecSetSizes(subvec1, is_complement_local_size, PETSC_DECIDE));
     500           0 :           LibmeshPetscCall(VecSetFromOptions(subvec1));
     501             : 
     502           0 :           WrappedPetsc<VecScatter> scatter1;
     503           0 :           LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is_complement, subvec1, nullptr, scatter1.get()));
     504             : 
     505           0 :           VecScatterBeginEnd(this->comm(), scatter1, _subset_solve_mode==SUBSET_COPY_RHS ? rhs->vec() : solution->vec(), subvec1, INSERT_VALUES, SCATTER_FORWARD);
     506             : 
     507           0 :           LibmeshPetscCall(VecScale(subvec1, -1.0));
     508             : 
     509           0 :           WrappedPetsc<Mat> submat1;
     510           0 :           LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
     511             :                                                   _restrict_solve_to_is,
     512             :                                                   _restrict_solve_to_is_complement,
     513             :                                                   MAT_INITIAL_MATRIX,
     514             :                                                   submat1.get()));
     515             : 
     516           0 :           LibmeshPetscCall(MatMultAdd(submat1, subvec1, subrhs, subrhs));
     517             :         }
     518             : 
     519         210 :       if (precond)
     520         210 :         LibmeshPetscCall(KSPSetOperators(_ksp, submat, subprecond));
     521             :       else
     522           0 :         LibmeshPetscCall(KSPSetOperators(_ksp, submat, submat));
     523             : 
     524         210 :       PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
     525         210 :       LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
     526             : 
     527         210 :       if (precond && this->_preconditioner)
     528             :         {
     529           0 :           subprecond_matrix = std::make_unique<PetscMatrix<Number>>(subprecond, this->comm());
     530           0 :           this->_preconditioner->set_matrix(*subprecond_matrix);
     531           0 :           this->_preconditioner->init();
     532             :         }
     533             :     }
     534             :   else
     535             :     {
     536      433461 :       PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
     537      433461 :       LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
     538             : 
     539      433461 :       if (precond)
     540      433461 :         LibmeshPetscCall(KSPSetOperators(_ksp, mat, const_cast<PetscMatrixBase<T> *>(precond)->mat()));
     541             :       else
     542           0 :         LibmeshPetscCall(KSPSetOperators(_ksp, mat, mat));
     543             : 
     544      433461 :       if (this->_preconditioner)
     545             :         {
     546         210 :           if (matrix)
     547           6 :             this->_preconditioner->set_matrix(*matrix);
     548           0 :           else if (precond)
     549           0 :             this->_preconditioner->set_matrix(const_cast<PetscMatrixBase<Number> &>(*precond));
     550             : 
     551         210 :           this->_preconditioner->init();
     552             :         }
     553             :     }
     554             : 
     555             :   // Set the tolerances for the iterative solver.  Use the user-supplied
     556             :   // tolerance for the relative residual & leave the others at default values.
     557      433671 :   LibmeshPetscCall(KSPSetTolerances(_ksp, rel_tol, abs_tol,
     558             :                                     PETSC_DEFAULT, max_its));
     559             : 
     560             :   // Allow command line options to override anything set programmatically.
     561      433671 :   LibmeshPetscCall(KSPSetFromOptions(_ksp));
     562             : 
     563             : #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) &&                      \
     564             :     !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE)
     565             :   {
     566             :     // Make sure hypre has been initialized
     567             :     LibmeshPetscCallExternal(HYPRE_Initialize);
     568             :     PetscScalar * dummyarray;
     569             :     PetscMemType mtype;
     570             :     LibmeshPetscCall(VecGetArrayAndMemType(solution->vec(), &dummyarray, &mtype));
     571             :     LibmeshPetscCall(VecRestoreArrayAndMemType(solution->vec(), &dummyarray));
     572             :     if (PetscMemTypeHost(mtype))
     573             :       LibmeshPetscCallExternal(HYPRE_SetMemoryLocation, HYPRE_MEMORY_HOST);
     574             :   }
     575             : #endif
     576             : 
     577             :   // If the SolverConfiguration object is provided, use it to override
     578             :   // solver options.
     579      433671 :   if (this->_solver_configuration)
     580             :     {
     581          70 :       this->_solver_configuration->configure_solver();
     582             :     }
     583             : 
     584             :   // Solve the linear system
     585      433671 :   if (_restrict_solve_to_is)
     586         210 :     LibmeshPetscCall(solve_func (_ksp, subrhs, subsolution));
     587             :   else
     588      433461 :     LibmeshPetscCall(solve_func (_ksp, rhs->vec(), solution->vec()));
     589             : 
     590             :   // Get the number of iterations required for convergence
     591      433671 :   LibmeshPetscCall(KSPGetIterationNumber (_ksp, &its));
     592             : 
     593             :   // Get the norm of the final residual to return to the user.
     594      433671 :   LibmeshPetscCall(KSPGetResidualNorm (_ksp, &final_resid));
     595             : 
     596      433671 :   if (_restrict_solve_to_is)
     597             :     {
     598         210 :       switch(_subset_solve_mode)
     599             :         {
     600          12 :         case SUBSET_ZERO:
     601         210 :           LibmeshPetscCall(VecZeroEntries(solution->vec()));
     602           6 :           break;
     603             : 
     604           0 :         case SUBSET_COPY_RHS:
     605           0 :           LibmeshPetscCall(VecCopy(rhs->vec(),solution->vec()));
     606           0 :           break;
     607             : 
     608           0 :         case SUBSET_DONT_TOUCH:
     609             :           // Nothing to do here.
     610           0 :           break;
     611             : 
     612           0 :         default:
     613           0 :           libmesh_error_msg("Invalid subset solve mode = " << _subset_solve_mode);
     614             :         }
     615             : 
     616         210 :       VecScatterBeginEnd(this->comm(), scatter, subsolution, solution->vec(), INSERT_VALUES, SCATTER_REVERSE);
     617             : 
     618         210 :       if (precond && this->_preconditioner)
     619             :         {
     620             :           // Before subprecond_matrix gets cleaned up, we should give
     621             :           // the _preconditioner a different matrix.
     622           0 :           if (matrix)
     623           0 :             this->_preconditioner->set_matrix(*matrix);
     624             :           else
     625           0 :             this->_preconditioner->set_matrix(*precond);
     626             : 
     627           0 :           this->_preconditioner->init();
     628             :         }
     629             :     }
     630             : 
     631             :   // return the # of its. and the final residual norm.
     632      893702 :   return std::make_pair(its, final_resid);
     633      408151 : }
     634             : 
     635             : 
     636             : 
     637             : template <typename T>
     638         280 : KSP PetscLinearSolver<T>::ksp()
     639             : {
     640         280 :   this->init();
     641         280 :   return _ksp;
     642             : }
     643             : 
     644             : template <typename T>
     645           0 : void PetscLinearSolver<T>::get_residual_history(std::vector<double> & hist)
     646             : {
     647           0 :   PetscInt its  = 0;
     648             : 
     649             :   // Fill the residual history vector with the residual norms
     650             :   // Note that GetResidualHistory() does not copy any values, it
     651             :   // simply sets the pointer p.  Note that for some Krylov subspace
     652             :   // methods, the number of residuals returned in the history
     653             :   // vector may be different from what you are expecting.  For
     654             :   // example, TFQMR returns two residual values per iteration step.
     655             : 
     656             :   // Recent versions of PETSc require the residual
     657             :   // history vector pointer to be declared as const.
     658             : #if PETSC_VERSION_LESS_THAN(3,15,0)
     659             :   PetscReal * p;
     660             : #else
     661             :   const PetscReal * p;
     662             : #endif
     663             : 
     664           0 :   LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
     665             : 
     666             :   // Check for early return
     667           0 :   if (its == 0) return;
     668             : 
     669             :   // Create space to store the result
     670           0 :   hist.resize(its);
     671             : 
     672             :   // Copy history into the vector provided by the user.
     673           0 :   for (PetscInt i=0; i<its; ++i)
     674             :     {
     675           0 :       hist[i] = *p;
     676           0 :       p++;
     677             :     }
     678             : }
     679             : 
     680             : 
     681             : 
     682             : 
     683             : template <typename T>
     684           0 : Real PetscLinearSolver<T>::get_initial_residual()
     685             : {
     686           0 :   PetscInt its  = 0;
     687             : 
     688             :   // Fill the residual history vector with the residual norms
     689             :   // Note that GetResidualHistory() does not copy any values, it
     690             :   // simply sets the pointer p.  Note that for some Krylov subspace
     691             :   // methods, the number of residuals returned in the history
     692             :   // vector may be different from what you are expecting.  For
     693             :   // example, TFQMR returns two residual values per iteration step.
     694             : 
     695             :   // Recent versions of PETSc require the residual
     696             :   // history vector pointer to be declared as const.
     697             : #if PETSC_VERSION_LESS_THAN(3,15,0)
     698             :   PetscReal * p;
     699             : #else
     700             :   const PetscReal * p;
     701             : #endif
     702             : 
     703             : 
     704           0 :   LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
     705             : 
     706             :   // Check no residual history
     707           0 :   if (its == 0)
     708             :     {
     709           0 :       libMesh::err << "No iterations have been performed, returning 0." << std::endl;
     710           0 :       return 0.;
     711             :     }
     712             : 
     713             :   // Otherwise, return the value pointed to by p.
     714           0 :   return *p;
     715             : }
     716             : 
     717             : 
     718             : 
     719             : 
     720             : template <typename T>
     721       47941 : void PetscLinearSolver<T>::set_petsc_solver_type()
     722             : {
     723             :   #define CaseKSPSetType(SolverType, KSPT)                          \
     724             :   case SolverType:                                                  \
     725             :     LibmeshPetscCall(KSPSetType (_ksp, const_cast<KSPType>(KSPT))); \
     726             :     return;
     727             : 
     728       47941 :   switch (this->_solver_type)
     729             :     {
     730         140 :     CaseKSPSetType(CG,         KSPCG)
     731           0 :     CaseKSPSetType(CR,         KSPCR)
     732           0 :     CaseKSPSetType(CGS,        KSPCGS)
     733           0 :     CaseKSPSetType(BICG,       KSPBICG)
     734           0 :     CaseKSPSetType(TCQMR,      KSPTCQMR)
     735           0 :     CaseKSPSetType(TFQMR,      KSPTFQMR)
     736           0 :     CaseKSPSetType(LSQR,       KSPLSQR)
     737           0 :     CaseKSPSetType(BICGSTAB,   KSPBCGS)
     738           0 :     CaseKSPSetType(MINRES,     KSPMINRES)
     739       47731 :     CaseKSPSetType(GMRES,      KSPGMRES)
     740           0 :     CaseKSPSetType(RICHARDSON, KSPRICHARDSON)
     741           0 :     CaseKSPSetType(CHEBYSHEV,  KSPCHEBYSHEV)
     742             : 
     743           2 :     default:
     744           2 :       libMesh::err << "ERROR:  Unsupported PETSC Solver: "
     745         140 :                    << Utility::enum_to_string(this->_solver_type) << std::endl
     746           2 :                    << "Continuing with PETSC defaults" << std::endl;
     747             :     }
     748             : }
     749             : 
     750             : 
     751             : 
     752             : template <typename T>
     753      160259 : LinearConvergenceReason PetscLinearSolver<T>::get_converged_reason() const
     754             : {
     755             :   KSPConvergedReason reason;
     756      160259 :   LibmeshPetscCall(KSPGetConvergedReason(_ksp, &reason));
     757             : 
     758      160259 :   switch(reason)
     759             :     {
     760             : #if PETSC_VERSION_LESS_THAN(3,24,0)
     761           0 :     case KSP_CONVERGED_RTOL_NORMAL     : return CONVERGED_RTOL_NORMAL;
     762           0 :     case KSP_CONVERGED_ATOL_NORMAL     : return CONVERGED_ATOL_NORMAL;
     763             : #else
     764             :     case KSP_CONVERGED_RTOL_NORMAL_EQUATIONS : return CONVERGED_RTOL_NORMAL;
     765             :     case KSP_CONVERGED_ATOL_NORMAL_EQUATIONS : return CONVERGED_ATOL_NORMAL;
     766             : #endif
     767      159839 :     case KSP_CONVERGED_RTOL            : return CONVERGED_RTOL;
     768         420 :     case KSP_CONVERGED_ATOL            : return CONVERGED_ATOL;
     769           0 :     case KSP_CONVERGED_ITS             : return CONVERGED_ITS;
     770             : #if PETSC_VERSION_LESS_THAN(3,19,0)
     771           0 :     case KSP_CONVERGED_CG_NEG_CURVE    : return CONVERGED_CG_NEG_CURVE;
     772             :     // This was deprecated for STEP_LENGTH
     773           0 :     case KSP_CONVERGED_CG_CONSTRAINED  : return CONVERGED_CG_CONSTRAINED;
     774             : #else
     775           0 :     case KSP_CONVERGED_NEG_CURVE       : return CONVERGED_CG_NEG_CURVE;
     776             : #endif
     777           0 :     case KSP_CONVERGED_STEP_LENGTH     : return CONVERGED_STEP_LENGTH;
     778           0 :     case KSP_CONVERGED_HAPPY_BREAKDOWN : return CONVERGED_HAPPY_BREAKDOWN;
     779           0 :     case KSP_DIVERGED_NULL             : return DIVERGED_NULL;
     780           0 :     case KSP_DIVERGED_ITS              : return DIVERGED_ITS;
     781           0 :     case KSP_DIVERGED_DTOL             : return DIVERGED_DTOL;
     782           0 :     case KSP_DIVERGED_BREAKDOWN        : return DIVERGED_BREAKDOWN;
     783           0 :     case KSP_DIVERGED_BREAKDOWN_BICG   : return DIVERGED_BREAKDOWN_BICG;
     784           0 :     case KSP_DIVERGED_NONSYMMETRIC     : return DIVERGED_NONSYMMETRIC;
     785           0 :     case KSP_DIVERGED_INDEFINITE_PC    : return DIVERGED_INDEFINITE_PC;
     786           0 :     case KSP_DIVERGED_NANORINF         : return DIVERGED_NAN;
     787           0 :     case KSP_DIVERGED_INDEFINITE_MAT   : return DIVERGED_INDEFINITE_MAT;
     788           0 :     case KSP_CONVERGED_ITERATING       : return CONVERGED_ITERATING;
     789             : #if !PETSC_VERSION_LESS_THAN(3,7,0)
     790             : // PETSc-3.7.0 to 3.10.x
     791             : #if PETSC_VERSION_LESS_THAN(3,11,0) && PETSC_VERSION_RELEASE
     792             :     case KSP_DIVERGED_PCSETUP_FAILED   : return DIVERGED_PCSETUP_FAILED;
     793             : // PETSc master and future PETSc
     794             : #else
     795           0 :     case KSP_DIVERGED_PC_FAILED        : return DIVERGED_PCSETUP_FAILED;
     796             : #endif
     797             : #endif
     798           0 :     default :
     799           0 :       libMesh::err << "Unknown convergence flag!" << std::endl;
     800           0 :       return UNKNOWN_FLAG;
     801             :     }
     802             : }
     803             : 
     804             : 
     805             : template <typename T>
     806         988 : PetscErrorCode PetscLinearSolver<T>::_petsc_shell_matrix_mult(Mat mat, Vec arg, Vec dest)
     807             : {
     808             :   PetscFunctionBegin;
     809             : 
     810             :   // Get the matrix context.
     811             :   void * ctx;
     812         988 :   PetscErrorCode ierr = MatShellGetContext(mat,&ctx);
     813             : 
     814             :   // Get user shell matrix object.
     815         988 :   const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
     816         988 :   CHKERRABORT(shell_matrix.comm().get(), ierr);
     817             : 
     818             :   // Make \p NumericVector instances around the vectors.
     819        1152 :   PetscVector<T> arg_global(arg, shell_matrix.comm());
     820        1070 :   PetscVector<T> dest_global(dest, shell_matrix.comm());
     821             : 
     822             :   // Call the user function.
     823         988 :   shell_matrix.vector_mult(dest_global,arg_global);
     824             : 
     825        1070 :   PetscFunctionReturn(ierr);
     826         824 : }
     827             : 
     828             : 
     829             : 
     830             : template <typename T>
     831           0 : PetscErrorCode PetscLinearSolver<T>::_petsc_shell_matrix_mult_add(Mat mat, Vec arg, Vec add, Vec dest)
     832             : {
     833             :   PetscFunctionBegin;
     834             : 
     835             :   // Get the matrix context.
     836             :   void * ctx;
     837           0 :   PetscErrorCode ierr = MatShellGetContext(mat,&ctx);
     838             : 
     839             :   // Get user shell matrix object.
     840           0 :   const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
     841           0 :   CHKERRABORT(shell_matrix.comm().get(), ierr);
     842             : 
     843             :   // Make \p NumericVector instances around the vectors.
     844           0 :   PetscVector<T> arg_global(arg, shell_matrix.comm());
     845           0 :   PetscVector<T> dest_global(dest, shell_matrix.comm());
     846           0 :   PetscVector<T> add_global(add, shell_matrix.comm());
     847             : 
     848           0 :   if (add!=arg)
     849             :     {
     850           0 :       arg_global = add_global;
     851             :     }
     852             : 
     853             :   // Call the user function.
     854           0 :   shell_matrix.vector_mult_add(dest_global,arg_global);
     855             : 
     856           0 :   PetscFunctionReturn(ierr);
     857           0 : }
     858             : 
     859             : 
     860             : 
     861             : template <typename T>
     862           0 : PetscErrorCode PetscLinearSolver<T>::_petsc_shell_matrix_get_diagonal(Mat mat, Vec dest)
     863             : {
     864             :   PetscFunctionBegin;
     865             : 
     866             :   // Get the matrix context.
     867             :   void * ctx;
     868           0 :   PetscErrorCode ierr = MatShellGetContext(mat,&ctx);
     869             : 
     870             :   // Get user shell matrix object.
     871           0 :   const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
     872           0 :   CHKERRABORT(shell_matrix.comm().get(), ierr);
     873             : 
     874             :   // Make \p NumericVector instances around the vector.
     875           0 :   PetscVector<T> dest_global(dest, shell_matrix.comm());
     876             : 
     877             :   // Call the user function.
     878           0 :   shell_matrix.get_diagonal(dest_global);
     879             : 
     880           0 :   PetscFunctionReturn(ierr);
     881           0 : }
     882             : 
     883             : 
     884             : 
     885             : template <typename T>
     886             : void
     887           0 : PetscLinearSolver<T>::create_complement_is (const NumericVector<T> & vec_in)
     888             : {
     889           0 :   libmesh_assert(_restrict_solve_to_is);
     890           0 :   if (!_restrict_solve_to_is_complement)
     891           0 :     LibmeshPetscCall(ISComplement(_restrict_solve_to_is,
     892             :                                   vec_in.first_local_index(),
     893             :                                   vec_in.last_local_index(),
     894             :                                   _restrict_solve_to_is_complement.get()));
     895           0 : }
     896             : 
     897             : 
     898             : template <typename T>
     899             : PetscInt
     900         210 : PetscLinearSolver<T>::restrict_solve_to_is_local_size() const
     901             : {
     902           6 :   libmesh_assert(_restrict_solve_to_is);
     903             : 
     904             :   PetscInt s;
     905         210 :   LibmeshPetscCall(ISGetLocalSize(_restrict_solve_to_is, &s));
     906             : 
     907         210 :   return s;
     908             : }
     909             : 
     910             : 
     911             : //------------------------------------------------------------------
     912             : // Explicit instantiations
     913             : template class LIBMESH_EXPORT PetscLinearSolver<Number>;
     914             : 
     915             : } // namespace libMesh
     916             : 
     917             : 
     918             : 
     919             : #endif // #ifdef LIBMESH_HAVE_PETSC

Generated by: LCOV version 1.14