petsc_preconditioner.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 = libmesh_cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(x)); 00047 PetscVector<T> & y_pvec = libmesh_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 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00054 } 00055 00056 00057 00058 00059 template <typename T> 00060 void PetscPreconditioner<T>::init () 00061 { 00062 if(!this->_matrix) 00063 { 00064 libMesh::err << "ERROR: No matrix set for PetscPreconditioner, but init() called" << std::endl; 00065 libmesh_error(); 00066 } 00067 00068 // Clear the preconditioner in case it has been created in the past 00069 if (!this->_is_initialized) 00070 { 00071 // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead 00072 if (_pc) 00073 { 00074 int ierr = LibMeshPCDestroy(&_pc); 00075 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00076 } 00077 00078 int ierr = PCCreate(libMesh::COMM_WORLD,&_pc); 00079 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00080 00081 PetscMatrix<T> * pmatrix = libmesh_cast_ptr<PetscMatrix<T>*, SparseMatrix<T> >(this->_matrix); 00082 00083 _mat = pmatrix->mat(); 00084 } 00085 00086 int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN); 00087 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00088 00089 // Set the PCType. Note: this used to be done *before* the call to 00090 // PCSetOperators(), and only when !_is_initialized, but 00091 // 1.) Some preconditioners (those employing sub-preconditioners, 00092 // for example) have to call PCSetUp(), and can only do this after 00093 // the operators have been set. 00094 // 2.) It should be safe to call set_petsc_preconditioner_type() 00095 // multiple times. 00096 set_petsc_preconditioner_type(this->_preconditioner_type, _pc); 00097 00098 this->_is_initialized = true; 00099 } 00100 00101 00102 00103 00104 template <typename T> 00105 void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc) 00106 { 00107 int ierr = 0; 00108 00109 switch (preconditioner_type) 00110 { 00111 case IDENTITY_PRECOND: 00112 ierr = PCSetType (pc, (char*) PCNONE); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00113 00114 case CHOLESKY_PRECOND: 00115 ierr = PCSetType (pc, (char*) PCCHOLESKY); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00116 00117 case ICC_PRECOND: 00118 ierr = PCSetType (pc, (char*) PCICC); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00119 00120 case ILU_PRECOND: 00121 { 00122 // In serial, just set the ILU preconditioner type 00123 if (libMesh::n_processors() == 1) 00124 { 00125 ierr = PCSetType (pc, (char*) PCILU); 00126 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00127 } 00128 else 00129 { 00130 // But PETSc has no truly parallel ILU, instead you have to set 00131 // an actual parallel preconditioner (e.g. block Jacobi) and then 00132 // assign ILU sub-preconditioners. 00133 ierr = PCSetType (pc, (char*) PCBJACOBI); 00134 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00135 00136 // Set ILU as the sub preconditioner type 00137 set_petsc_subpreconditioner_type(PCILU, pc); 00138 } 00139 break; 00140 } 00141 00142 case LU_PRECOND: 00143 { 00144 // In serial, just set the LU preconditioner type 00145 if (libMesh::n_processors() == 1) 00146 { 00147 ierr = PCSetType (pc, (char*) PCLU); 00148 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00149 } 00150 else 00151 { 00152 // But PETSc has no truly parallel LU, instead you have to set 00153 // an actual parallel preconditioner (e.g. block Jacobi) and then 00154 // assign LU sub-preconditioners. 00155 ierr = PCSetType (pc, (char*) PCBJACOBI); 00156 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00157 00158 // Set ILU as the sub preconditioner type 00159 set_petsc_subpreconditioner_type(PCLU, pc); 00160 } 00161 break; 00162 } 00163 00164 case ASM_PRECOND: 00165 { 00166 // In parallel, I think ASM uses ILU by default as the sub-preconditioner... 00167 // I tried setting a different sub-preconditioner here, but apparently the matrix 00168 // is not in the correct state (at this point) to call PCSetUp(). 00169 ierr = PCSetType (pc, (char*) PCASM); 00170 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00171 break; 00172 } 00173 00174 case JACOBI_PRECOND: 00175 ierr = PCSetType (pc, (char*) PCJACOBI); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00176 00177 case BLOCK_JACOBI_PRECOND: 00178 ierr = PCSetType (pc, (char*) PCBJACOBI); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00179 00180 case SOR_PRECOND: 00181 ierr = PCSetType (pc, (char*) PCSOR); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00182 00183 case EISENSTAT_PRECOND: 00184 ierr = PCSetType (pc, (char*) PCEISENSTAT); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00185 00186 case AMG_PRECOND: 00187 ierr = PCSetType (pc, (char*) PCHYPRE); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00188 00189 #if !(PETSC_VERSION_LESS_THAN(2,1,2)) 00190 // Only available for PETSC >= 2.1.2 00191 case USER_PRECOND: 00192 ierr = PCSetType (pc, (char*) PCMAT); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00193 #endif 00194 00195 case SHELL_PRECOND: 00196 ierr = PCSetType (pc, (char*) PCSHELL); CHKERRABORT(libMesh::COMM_WORLD,ierr); break; 00197 00198 default: 00199 libMesh::err << "ERROR: Unsupported PETSC Preconditioner: " 00200 << preconditioner_type << std::endl 00201 << "Continuing with PETSC defaults" << std::endl; 00202 } 00203 00204 // Set additional options if we are doing AMG and 00205 // HYPRE is available 00206 #ifdef LIBMESH_HAVE_PETSC_HYPRE 00207 if (preconditioner_type == AMG_PRECOND) 00208 { 00209 ierr = PCHYPRESetType(pc, "boomeramg"); 00210 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00211 } 00212 #endif 00213 00214 // Let the commandline override stuff 00215 // FIXME: Unless we are doing AMG??? 00216 if (preconditioner_type != AMG_PRECOND) 00217 { 00218 ierr = PCSetFromOptions(pc); 00219 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00220 } 00221 } 00222 00223 00224 00225 template <typename T> 00226 #if PETSC_VERSION_LESS_THAN(3,0,0) 00227 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCType type, PC& pc) 00228 #else 00229 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(const PCType type, PC& pc) 00230 #endif 00231 { 00232 // For catching PETSc error return codes 00233 int ierr = 0; 00234 00235 // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP. 00236 // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the: 00237 // 00238 // "Object is in wrong state!" 00239 // "Matrix must be set first." 00240 // 00241 // error messages... 00242 ierr = PCSetUp(pc); 00243 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00244 00245 // To store array of local KSP contexts on this processor 00246 KSP* subksps; 00247 00248 // the number of blocks on this processor 00249 int n_local; 00250 00251 // The global number of the first block on this processor. 00252 // This is not used, so we just pass PETSC_NULL instead. 00253 // int first_local; 00254 00255 // Fill array of local KSP contexts 00256 ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps); 00257 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00258 00259 // Loop over sub-ksp objects, set ILU preconditioner 00260 for (int i=0; i<n_local; ++i) 00261 { 00262 // Get pointer to sub KSP object's PC 00263 PC subpc; 00264 ierr = KSPGetPC(subksps[i], &subpc); 00265 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00266 00267 // Set requested type on the sub PC 00268 ierr = PCSetType(subpc, type); 00269 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00270 } 00271 00272 } 00273 00274 00275 00276 00277 //------------------------------------------------------------------ 00278 // Explicit instantiations 00279 template class PetscPreconditioner<Number>; 00280 00281 } // namespace libMesh 00282 00283 #endif // #ifdef LIBMESH_HAVE_PETSC
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: