petsc_preconditioner.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 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 // C++ includes
23 
24 // Local Includes
26 #include "libmesh/petsc_macro.h"
27 #include "libmesh/petsc_matrix.h"
28 #include "libmesh/petsc_vector.h"
29 #include "libmesh/libmesh_common.h"
31 
32 // PCBJacobiGetSubKSP was defined in petscksp.h in PETSc 2.3.3, 3.1.0
33 #if PETSC_VERSION_LESS_THAN(3,1,0)
34 # include "petscksp.h"
35 #endif
36 
37 namespace libMesh
38 {
39 
40 template <typename T>
42 {
43  PetscVector<T> & x_pvec = cast_ref<PetscVector<T> &>(const_cast<NumericVector<T> &>(x));
44  PetscVector<T> & y_pvec = cast_ref<PetscVector<T> &>(const_cast<NumericVector<T> &>(y));
45 
46  Vec x_vec = x_pvec.vec();
47  Vec y_vec = y_pvec.vec();
48 
49  int ierr = PCApply(_pc,x_vec,y_vec);
50  LIBMESH_CHKERR(ierr);
51 }
52 
53 
54 
55 
56 template <typename T>
58 {
59  if (!this->_matrix)
60  libmesh_error_msg("ERROR: No matrix set for PetscPreconditioner, but init() called");
61 
62  // Clear the preconditioner in case it has been created in the past
63  if (!this->_is_initialized)
64  {
65  // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead
66  if (_pc)
67  {
68  int ierr = LibMeshPCDestroy(&_pc);
69  LIBMESH_CHKERR(ierr);
70  }
71 
72  int ierr = PCCreate(this->comm().get(),&_pc);
73  LIBMESH_CHKERR(ierr);
74 
75  PetscMatrix<T> * pmatrix = cast_ptr<PetscMatrix<T> *, SparseMatrix<T>>(this->_matrix);
76 
77  _mat = pmatrix->mat();
78  }
79 
80 #if PETSC_RELEASE_LESS_THAN(3,5,0)
81  int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN);
82 #else
83  int ierr = PCSetOperators(_pc,_mat,_mat);
84 #endif
85  LIBMESH_CHKERR(ierr);
86 
87  // Set the PCType. Note: this used to be done *before* the call to
88  // PCSetOperators(), and only when !_is_initialized, but
89  // 1.) Some preconditioners (those employing sub-preconditioners,
90  // for example) have to call PCSetUp(), and can only do this after
91  // the operators have been set.
92  // 2.) It should be safe to call set_petsc_preconditioner_type()
93  // multiple times.
94  set_petsc_preconditioner_type(this->_preconditioner_type, _pc);
95 
96  this->_is_initialized = true;
97 }
98 
99 
100 
101 template <typename T>
103 {
104  if (_pc)
105  {
106  int ierr = LibMeshPCDestroy(&_pc);
107  LIBMESH_CHKERR(ierr);
108  }
109 }
110 
111 
112 
113 
114 template <typename T>
116 {
117  int ierr = 0;
118 
119  // get the communicator from the PETSc object
121  PetscObjectGetComm((PetscObject)pc, & comm);
123 
124  switch (preconditioner_type)
125  {
126  case IDENTITY_PRECOND:
127  ierr = PCSetType (pc, const_cast<KSPType>(PCNONE));
128  CHKERRABORT(comm,ierr);
129  break;
130 
131  case CHOLESKY_PRECOND:
132  ierr = PCSetType (pc, const_cast<KSPType>(PCCHOLESKY));
133  CHKERRABORT(comm,ierr);
134  break;
135 
136  case ICC_PRECOND:
137  ierr = PCSetType (pc, const_cast<KSPType>(PCICC));
138  CHKERRABORT(comm,ierr);
139  break;
140 
141  case ILU_PRECOND:
142  {
143  // In serial, just set the ILU preconditioner type
144  if (communicator.size())
145  {
146  ierr = PCSetType (pc, const_cast<KSPType>(PCILU));
147  CHKERRABORT(comm,ierr);
148  }
149  else
150  {
151  // But PETSc has no truly parallel ILU, instead you have to set
152  // an actual parallel preconditioner (e.g. block Jacobi) and then
153  // assign ILU sub-preconditioners.
154  ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
155  CHKERRABORT(comm,ierr);
156 
157  // Set ILU as the sub preconditioner type
158  set_petsc_subpreconditioner_type(PCILU, pc);
159  }
160  break;
161  }
162 
163  case LU_PRECOND:
164  {
165  // In serial, just set the LU preconditioner type
166  if (communicator.size())
167  {
168  ierr = PCSetType (pc, const_cast<KSPType>(PCLU));
169  CHKERRABORT(comm,ierr);
170  }
171  else
172  {
173  // But PETSc has no truly parallel LU, instead you have to set
174  // an actual parallel preconditioner (e.g. block Jacobi) and then
175  // assign LU sub-preconditioners.
176  ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
177  CHKERRABORT(comm,ierr);
178 
179  // Set ILU as the sub preconditioner type
180  set_petsc_subpreconditioner_type(PCLU, pc);
181  }
182  break;
183  }
184 
185  case ASM_PRECOND:
186  {
187  // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
188  // I tried setting a different sub-preconditioner here, but apparently the matrix
189  // is not in the correct state (at this point) to call PCSetUp().
190  ierr = PCSetType (pc, const_cast<KSPType>(PCASM));
191  CHKERRABORT(comm,ierr);
192  break;
193  }
194 
195  case JACOBI_PRECOND:
196  ierr = PCSetType (pc, const_cast<KSPType>(PCJACOBI));
197  CHKERRABORT(comm,ierr);
198  break;
199 
201  ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
202  CHKERRABORT(comm,ierr);
203  break;
204 
205  case SOR_PRECOND:
206  ierr = PCSetType (pc, const_cast<KSPType>(PCSOR));
207  CHKERRABORT(comm,ierr);
208  break;
209 
210  case EISENSTAT_PRECOND:
211  ierr = PCSetType (pc, const_cast<KSPType>(PCEISENSTAT));
212  CHKERRABORT(comm,ierr);
213  break;
214 
215  case AMG_PRECOND:
216  ierr = PCSetType (pc, const_cast<KSPType>(PCHYPRE));
217  CHKERRABORT(comm,ierr);
218  break;
219 
220  case USER_PRECOND:
221  ierr = PCSetType (pc, const_cast<KSPType>(PCMAT));
222  CHKERRABORT(comm,ierr);
223  break;
224 
225  case SHELL_PRECOND:
226  ierr = PCSetType (pc, const_cast<KSPType>(PCSHELL));
227  CHKERRABORT(comm,ierr);
228  break;
229 
230  default:
231  libMesh::err << "ERROR: Unsupported PETSC Preconditioner: "
232  << preconditioner_type << std::endl
233  << "Continuing with PETSC defaults" << std::endl;
234  }
235 
236  // Set additional options if we are doing AMG and
237  // HYPRE is available
238 #ifdef LIBMESH_HAVE_PETSC_HYPRE
239  if (preconditioner_type == AMG_PRECOND)
240  {
241  ierr = PCHYPRESetType(pc, "boomeramg");
242  CHKERRABORT(comm,ierr);
243  }
244 #endif
245 
246  // Let the commandline override stuff
247  ierr = PCSetFromOptions(pc);
248  CHKERRABORT(comm,ierr);
249 }
250 
251 
252 #if PETSC_VERSION_LESS_THAN(3,0,0)
253 #define PCTYPE_CV_QUALIFIER
254 #else
255 #define PCTYPE_CV_QUALIFIER const
256 #endif
257 
258 template <typename T>
259 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCTYPE_CV_QUALIFIER PCType type, PC & pc)
260 {
261  // For catching PETSc error return codes
262  int ierr = 0;
263 
264  // get the communicator from the PETSc object
266  PetscObjectGetComm((PetscObject)pc, & comm);
268 
269  // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP.
270  // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the:
271  //
272  // "Object is in wrong state!"
273  // "Matrix must be set first."
274  //
275  // error messages...
276  ierr = PCSetUp(pc);
277  CHKERRABORT(comm,ierr);
278 
279  // To store array of local KSP contexts on this processor
280  KSP * subksps;
281 
282  // the number of blocks on this processor
283  PetscInt n_local;
284 
285  // The global number of the first block on this processor.
286  // This is not used, so we just pass PETSC_NULL instead.
287  // int first_local;
288 
289  // Fill array of local KSP contexts
290  ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps);
291  CHKERRABORT(comm,ierr);
292 
293  // Loop over sub-ksp objects, set ILU preconditioner
294  for (PetscInt i=0; i<n_local; ++i)
295  {
296  // Get pointer to sub KSP object's PC
297  PC subpc;
298  ierr = KSPGetPC(subksps[i], &subpc);
299  CHKERRABORT(comm,ierr);
300 
301  // Set requested type on the sub PC
302  ierr = PCSetType(subpc, type);
303  CHKERRABORT(comm,ierr);
304  }
305 
306 }
307 
308 
309 
310 
311 //------------------------------------------------------------------
312 // Explicit instantiations
313 template class PetscPreconditioner<Number>;
314 
315 } // namespace libMesh
316 
317 #endif // #ifdef LIBMESH_HAVE_PETSC
NumericVector interface to PETSc Vec.
Definition: petsc_vector.h:64
MPI_Comm communicator
Definition: communicator.h:57
virtual void init() override
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
Definition: diff_context.h:40
virtual void apply(const NumericVector< T > &x, NumericVector< T > &y) override
static void set_petsc_subpreconditioner_type(PCType type, PC &pc)
OStreamProxy err(std::cerr)
virtual void clear() override
static void set_petsc_preconditioner_type(const PreconditionerType &preconditioner_type, PC &pc)
PetscErrorCode ierr
SparseMatrix interface to PETSc Mat.