$extrastylesheet
petsc_preconditioner.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 #include "libmesh/libmesh_common.h"
00019 
00020 #ifdef LIBMESH_HAVE_PETSC
00021 
00022 // C++ includes
00023 
00024 // Local Includes
00025 #include "libmesh/petsc_preconditioner.h"
00026 #include "libmesh/petsc_macro.h"
00027 #include "libmesh/petsc_matrix.h"
00028 #include "libmesh/petsc_vector.h"
00029 #include "libmesh/libmesh_common.h"
00030 
00031 // PCBJacobiGetSubKSP was defined in petscksp.h in PETSc 2.3.3, 3.1.0
00032 #if PETSC_VERSION_LESS_THAN(3,1,0)
00033 
00034 EXTERN_C_FOR_PETSC_BEGIN
00035 #include "petscksp.h"
00036 EXTERN_C_FOR_PETSC_END
00037 
00038 #endif
00039 
00040 namespace libMesh
00041 {
00042 
00043 template <typename T>
00044 void PetscPreconditioner<T>::apply(const NumericVector<T> & x, NumericVector<T> & y)
00045 {
00046   PetscVector<T> & x_pvec = cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(x));
00047   PetscVector<T> & y_pvec = cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(y));
00048 
00049   Vec x_vec = x_pvec.vec();
00050   Vec y_vec = y_pvec.vec();
00051 
00052   int ierr = PCApply(_pc,x_vec,y_vec);
00053   LIBMESH_CHKERRABORT(ierr);
00054 }
00055 
00056 
00057 
00058 
00059 template <typename T>
00060 void PetscPreconditioner<T>::init ()
00061 {
00062   if(!this->_matrix)
00063     libmesh_error_msg("ERROR: No matrix set for PetscPreconditioner, but init() called");
00064 
00065   // Clear the preconditioner in case it has been created in the past
00066   if (!this->_is_initialized)
00067     {
00068       // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead
00069       if (_pc)
00070         {
00071           int ierr = LibMeshPCDestroy(&_pc);
00072           LIBMESH_CHKERRABORT(ierr);
00073         }
00074 
00075       int ierr = PCCreate(this->comm().get(),&_pc);
00076       LIBMESH_CHKERRABORT(ierr);
00077 
00078       PetscMatrix<T> * pmatrix = cast_ptr<PetscMatrix<T>*, SparseMatrix<T> >(this->_matrix);
00079 
00080       _mat = pmatrix->mat();
00081     }
00082 
00083 #if PETSC_RELEASE_LESS_THAN(3,5,0)
00084   int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN);
00085 #else
00086   int ierr = PCSetOperators(_pc,_mat,_mat);
00087 #endif
00088   LIBMESH_CHKERRABORT(ierr);
00089 
00090   // Set the PCType.  Note: this used to be done *before* the call to
00091   // PCSetOperators(), and only when !_is_initialized, but
00092   // 1.) Some preconditioners (those employing sub-preconditioners,
00093   // for example) have to call PCSetUp(), and can only do this after
00094   // the operators have been set.
00095   // 2.) It should be safe to call set_petsc_preconditioner_type()
00096   // multiple times.
00097   set_petsc_preconditioner_type(this->_preconditioner_type, _pc);
00098 
00099   this->_is_initialized = true;
00100 }
00101 
00102 
00103 
00104 template <typename T>
00105 void PetscPreconditioner<T>::clear()
00106 {
00107   if (_pc)
00108     {
00109       int ierr = LibMeshPCDestroy(&_pc);
00110       LIBMESH_CHKERRABORT(ierr);
00111     }
00112 }
00113 
00114 
00115 
00116 
00117 template <typename T>
00118 void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc)
00119 {
00120   int ierr = 0;
00121 
00122   // get the communicator from the PETSc object
00123   Parallel::communicator comm;
00124   PetscObjectGetComm((PetscObject)pc, &comm);
00125   Parallel::Communicator communicator(comm);
00126 
00127   switch (preconditioner_type)
00128     {
00129     case IDENTITY_PRECOND:
00130       ierr = PCSetType (pc, const_cast<KSPType>(PCNONE));
00131       CHKERRABORT(comm,ierr);
00132       break;
00133 
00134     case CHOLESKY_PRECOND:
00135       ierr = PCSetType (pc, const_cast<KSPType>(PCCHOLESKY));
00136       CHKERRABORT(comm,ierr);
00137       break;
00138 
00139     case ICC_PRECOND:
00140       ierr = PCSetType (pc, const_cast<KSPType>(PCICC));
00141       CHKERRABORT(comm,ierr);
00142       break;
00143 
00144     case ILU_PRECOND:
00145       {
00146         // In serial, just set the ILU preconditioner type
00147         if (communicator.size())
00148           {
00149             ierr = PCSetType (pc, const_cast<KSPType>(PCILU));
00150             CHKERRABORT(comm,ierr);
00151           }
00152         else
00153           {
00154             // But PETSc has no truly parallel ILU, instead you have to set
00155             // an actual parallel preconditioner (e.g. block Jacobi) and then
00156             // assign ILU sub-preconditioners.
00157             ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
00158             CHKERRABORT(comm,ierr);
00159 
00160             // Set ILU as the sub preconditioner type
00161             set_petsc_subpreconditioner_type(PCILU, pc);
00162           }
00163         break;
00164       }
00165 
00166     case LU_PRECOND:
00167       {
00168         // In serial, just set the LU preconditioner type
00169         if (communicator.size())
00170           {
00171             ierr = PCSetType (pc, const_cast<KSPType>(PCLU));
00172             CHKERRABORT(comm,ierr);
00173           }
00174         else
00175           {
00176             // But PETSc has no truly parallel LU, instead you have to set
00177             // an actual parallel preconditioner (e.g. block Jacobi) and then
00178             // assign LU sub-preconditioners.
00179             ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
00180             CHKERRABORT(comm,ierr);
00181 
00182             // Set ILU as the sub preconditioner type
00183             set_petsc_subpreconditioner_type(PCLU, pc);
00184           }
00185         break;
00186       }
00187 
00188     case ASM_PRECOND:
00189       {
00190         // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
00191         // I tried setting a different sub-preconditioner here, but apparently the matrix
00192         // is not in the correct state (at this point) to call PCSetUp().
00193         ierr = PCSetType (pc, const_cast<KSPType>(PCASM));
00194         CHKERRABORT(comm,ierr);
00195         break;
00196       }
00197 
00198     case JACOBI_PRECOND:
00199       ierr = PCSetType (pc, const_cast<KSPType>(PCJACOBI));
00200       CHKERRABORT(comm,ierr);
00201       break;
00202 
00203     case BLOCK_JACOBI_PRECOND:
00204       ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
00205       CHKERRABORT(comm,ierr);
00206       break;
00207 
00208     case SOR_PRECOND:
00209       ierr = PCSetType (pc, const_cast<KSPType>(PCSOR));
00210       CHKERRABORT(comm,ierr);
00211       break;
00212 
00213     case EISENSTAT_PRECOND:
00214       ierr = PCSetType (pc, const_cast<KSPType>(PCEISENSTAT));
00215       CHKERRABORT(comm,ierr);
00216       break;
00217 
00218     case AMG_PRECOND:
00219       ierr = PCSetType (pc, const_cast<KSPType>(PCHYPRE));
00220       CHKERRABORT(comm,ierr);
00221       break;
00222 
00223 #if !(PETSC_VERSION_LESS_THAN(2,1,2))
00224       // Only available for PETSC >= 2.1.2
00225     case USER_PRECOND:
00226       ierr = PCSetType (pc, const_cast<KSPType>(PCMAT));
00227       CHKERRABORT(comm,ierr);
00228       break;
00229 #endif
00230 
00231     case SHELL_PRECOND:
00232       ierr = PCSetType (pc, const_cast<KSPType>(PCSHELL));
00233       CHKERRABORT(comm,ierr);
00234       break;
00235 
00236     default:
00237       libMesh::err << "ERROR:  Unsupported PETSC Preconditioner: "
00238                    << preconditioner_type       << std::endl
00239                    << "Continuing with PETSC defaults" << std::endl;
00240     }
00241 
00242   // Set additional options if we are doing AMG and
00243   // HYPRE is available
00244 #ifdef LIBMESH_HAVE_PETSC_HYPRE
00245   if (preconditioner_type == AMG_PRECOND)
00246     {
00247       ierr = PCHYPRESetType(pc, "boomeramg");
00248       CHKERRABORT(comm,ierr);
00249     }
00250 #endif
00251 
00252   // Let the commandline override stuff
00253   // FIXME: Unless we are doing AMG???
00254   if (preconditioner_type != AMG_PRECOND)
00255     {
00256       ierr = PCSetFromOptions(pc);
00257       CHKERRABORT(comm,ierr);
00258     }
00259 }
00260 
00261 
00262 
00263 template <typename T>
00264 #if PETSC_VERSION_LESS_THAN(3,0,0)
00265 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCType type, PC& pc)
00266 #else
00267   void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(const PCType type, PC& pc)
00268 #endif
00269 {
00270   // For catching PETSc error return codes
00271   int ierr = 0;
00272 
00273   // get the communicator from the PETSc object
00274   Parallel::communicator comm;
00275   PetscObjectGetComm((PetscObject)pc, &comm);
00276   Parallel::Communicator communicator(comm);
00277 
00278   // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP.
00279   // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the:
00280   //
00281   // "Object is in wrong state!"
00282   // "Matrix must be set first."
00283   //
00284   // error messages...
00285   ierr = PCSetUp(pc);
00286   CHKERRABORT(comm,ierr);
00287 
00288   // To store array of local KSP contexts on this processor
00289   KSP* subksps;
00290 
00291   // the number of blocks on this processor
00292   PetscInt n_local;
00293 
00294   // The global number of the first block on this processor.
00295   // This is not used, so we just pass PETSC_NULL instead.
00296   // int first_local;
00297 
00298   // Fill array of local KSP contexts
00299   ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps);
00300   CHKERRABORT(comm,ierr);
00301 
00302   // Loop over sub-ksp objects, set ILU preconditioner
00303   for (PetscInt i=0; i<n_local; ++i)
00304     {
00305       // Get pointer to sub KSP object's PC
00306       PC subpc;
00307       ierr = KSPGetPC(subksps[i], &subpc);
00308       CHKERRABORT(comm,ierr);
00309 
00310       // Set requested type on the sub PC
00311       ierr = PCSetType(subpc, type);
00312       CHKERRABORT(comm,ierr);
00313     }
00314 
00315 }
00316 
00317 
00318 
00319 
00320 //------------------------------------------------------------------
00321 // Explicit instantiations
00322 template class PetscPreconditioner<Number>;
00323 
00324 } // namespace libMesh
00325 
00326 #endif // #ifdef LIBMESH_HAVE_PETSC