$extrastylesheet
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