1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18 
19 
20 // Local Includes
21 #include "libmesh/auto_ptr.h" // libmesh_make_unique
22 #include "libmesh/libmesh_logging.h"
23 #include "libmesh/linear_solver.h"
24 #include "libmesh/laspack_linear_solver.h"
25 #include "libmesh/eigen_sparse_linear_solver.h"
26 #include "libmesh/petsc_linear_solver.h"
27 #include "libmesh/trilinos_aztec_linear_solver.h"
28 #include "libmesh/preconditioner.h"
29 #include "libmesh/sparse_matrix.h"
30 #include "libmesh/enum_to_string.h"
31 #include "libmesh/solver_configuration.h"
32 #include "libmesh/enum_solver_package.h"
33 #include "libmesh/enum_preconditioner_type.h"
34 #include "libmesh/enum_solver_type.h"
35 
36 namespace libMesh
37 {
38 
39 //------------------------------------------------------------------
40 // LinearSolver members
41 template <typename T>
LinearSolver(const libMesh::Parallel::Communicator & comm_in)42 LinearSolver<T>::LinearSolver (const libMesh::Parallel::Communicator & comm_in) :
43   ParallelObject       (comm_in),
44   _solver_type         (GMRES),
45   _preconditioner_type (ILU_PRECOND),
46   _is_initialized      (false),
47   _preconditioner      (nullptr),
48   same_preconditioner  (false),
49   _solver_configuration(nullptr)
50 {
51 }
52 
53 
54 
55 template <typename T>
56 std::unique_ptr<LinearSolver<T>>
build(const libMesh::Parallel::Communicator & comm,const SolverPackage solver_package)57 LinearSolver<T>::build(const libMesh::Parallel::Communicator & comm,
58                        const SolverPackage solver_package)
59 {
60   // Avoid unused parameter warnings when no solver packages are enabled.
61   libmesh_ignore(comm);
62 
63   // Build the appropriate solver
64   switch (solver_package)
65     {
66 #ifdef LIBMESH_HAVE_LASPACK
67     case LASPACK_SOLVERS:
68       return libmesh_make_unique<LaspackLinearSolver<T>>(comm);
69 #endif
70 
71 
72 #ifdef LIBMESH_HAVE_PETSC
73     case PETSC_SOLVERS:
74       return libmesh_make_unique<PetscLinearSolver<T>>(comm);
75 #endif
76 
77 
78 #ifdef LIBMESH_TRILINOS_HAVE_AZTECOO
79     case TRILINOS_SOLVERS:
80       return libmesh_make_unique<AztecLinearSolver<T>>(comm);
81 #endif
82 
83 
84 #ifdef LIBMESH_HAVE_EIGEN
85     case EIGEN_SOLVERS:
86       return libmesh_make_unique<EigenSparseLinearSolver<T>>(comm);
87 #endif
88 
89     default:
90       libmesh_error_msg("ERROR:  Unrecognized solver package: " << solver_package);
91     }
92 
93   return std::unique_ptr<LinearSolver<T>>();
94 }
95 
96 template <typename T>
97 PreconditionerType
preconditioner_type()98 LinearSolver<T>::preconditioner_type () const
99 {
100   if (_preconditioner)
101     return _preconditioner->type();
102 
103   return _preconditioner_type;
104 }
105 
106 template <typename T>
107 void
set_preconditioner_type(const PreconditionerType pct)108 LinearSolver<T>::set_preconditioner_type (const PreconditionerType pct)
109 {
110   if (_preconditioner)
111     _preconditioner->set_type(pct);
112   else
113     _preconditioner_type = pct;
114 }
115 
116 template <typename T>
117 void
attach_preconditioner(Preconditioner<T> * preconditioner)118 LinearSolver<T>::attach_preconditioner(Preconditioner<T> * preconditioner)
119 {
120   libmesh_error_msg_if(this->_is_initialized,
121                        "Preconditioner must be attached before the solver is initialized!");
122 
123   _preconditioner_type = SHELL_PRECOND;
124   _preconditioner = preconditioner;
125 }
126 
127 template <typename T>
128 void
reuse_preconditioner(bool reuse_flag)129 LinearSolver<T>::reuse_preconditioner(bool reuse_flag)
130 {
131   same_preconditioner = reuse_flag;
132 }
133 
134 template <typename T>
135 void
restrict_solve_to(const std::vector<unsigned int> * const dofs,const SubsetSolveMode)136 LinearSolver<T>::restrict_solve_to(const std::vector<unsigned int> * const dofs,
137                                    const SubsetSolveMode /*subset_solve_mode*/)
138 {
139   if (dofs != nullptr)
140     libmesh_not_implemented();
141 }
142 
143 
144 template <typename T>
adjoint_solve(SparseMatrix<T> & mat,NumericVector<T> & sol,NumericVector<T> & rhs,const double tol,const unsigned int n_iter)145 std::pair<unsigned int, Real> LinearSolver<T>::adjoint_solve (SparseMatrix<T> & mat,
146                                                               NumericVector<T> & sol,
147                                                               NumericVector<T> & rhs,
148                                                               const double tol,
149                                                               const unsigned int n_iter)
150 {
151   // Log how long the linear solve takes.
152   LOG_SCOPE("adjoint_solve()", "LinearSolver");
153 
154   // Take the discrete adjoint
155   mat.close();
156   mat.get_transpose(mat);
157 
158   // Call the solve function for the relevant linear algebra library and
159   // solve the transpose matrix
160   const std::pair<unsigned int, Real> totalrval =  this->solve (mat, sol, rhs, tol, n_iter);
161 
162   // Now transpose back and restore the original matrix
163   // by taking the discrete adjoint
164   mat.get_transpose(mat);
165 
166   return totalrval;
167 }
168 
169 template <typename T>
print_converged_reason()170 void LinearSolver<T>::print_converged_reason() const
171 {
172   LinearConvergenceReason reason = this->get_converged_reason();
173   libMesh::out << "Linear solver convergence/divergence reason: " << Utility::enum_to_string(reason) << std::endl;
174 }
175 
176 template <typename T>
set_solver_configuration(SolverConfiguration & solver_configuration)177 void LinearSolver<T>::set_solver_configuration(SolverConfiguration & solver_configuration)
178 {
179   _solver_configuration = &solver_configuration;
180 }
181 
182 //------------------------------------------------------------------
183 // Explicit instantiations
184 template class LinearSolver<Number>;
185 
186 
187 
188 } // namespace libMesh
189