petsc_diff_solver.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 00019 #include "libmesh/diff_system.h" 00020 #include "libmesh/dof_map.h" 00021 #include "libmesh/libmesh_logging.h" 00022 #include "libmesh/petsc_diff_solver.h" 00023 #include "libmesh/petsc_matrix.h" 00024 #include "libmesh/petsc_vector.h" 00025 00026 #ifdef LIBMESH_HAVE_PETSC 00027 00028 namespace libMesh 00029 { 00030 00031 //-------------------------------------------------------------------- 00032 // Functions with C linkage to pass to PETSc. PETSc will call these 00033 // methods as needed. 00034 // 00035 // Since they must have C linkage they have no knowledge of a namespace. 00036 // Give them an obscure name to avoid namespace pollution. 00037 extern "C" 00038 { 00039 // Older versions of PETSc do not have the different int typedefs. 00040 // On 64-bit machines, PetscInt may actually be a long long int. 00041 // This change occurred in Petsc-2.2.1. 00042 #if PETSC_VERSION_LESS_THAN(2,2,1) 00043 typedef int PetscErrorCode; 00044 typedef int PetscInt; 00045 #endif 00046 00047 // Function to hand to PETSc's SNES, 00048 // which monitors convergence at X 00049 PetscErrorCode 00050 __libmesh_petsc_diff_solver_monitor (SNES, PetscInt its, 00051 PetscReal fnorm, void *ctx) 00052 { 00053 PetscDiffSolver& solver = 00054 *(static_cast<PetscDiffSolver*> (ctx)); 00055 00056 if (solver.verbose) 00057 libMesh::out << " PetscDiffSolver step " << its 00058 << ", |residual|_2 = " << fnorm << std::endl; 00059 00060 return 0; 00061 } 00062 00063 // Functions to hand to PETSc's SNES, 00064 // which compute the residual or jacobian at X 00065 PetscErrorCode 00066 __libmesh_petsc_diff_solver_residual (SNES, Vec x, Vec r, void *ctx) 00067 { 00068 libmesh_assert(x); 00069 libmesh_assert(r); 00070 libmesh_assert(ctx); 00071 00072 PetscDiffSolver& solver = 00073 *(static_cast<PetscDiffSolver*> (ctx)); 00074 ImplicitSystem &sys = solver.system(); 00075 00076 if (solver.verbose) 00077 libMesh::out << "Assembling the residual" << std::endl; 00078 00079 PetscVector<Number>& X_system = 00080 *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get()); 00081 PetscVector<Number>& R_system = 00082 *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs); 00083 PetscVector<Number> X_input(x), R_input(r); 00084 00085 // DiffSystem assembles from the solution and into the rhs, so swap 00086 // those with our input vectors before assembling. They'll probably 00087 // already be references to the same vectors, but PETSc might do 00088 // something tricky. 00089 X_input.swap(X_system); 00090 R_input.swap(R_system); 00091 00092 // We may need to correct a non-conforming solution 00093 sys.get_dof_map().enforce_constraints_exactly(sys); 00094 00095 // We may need to localize a parallel solution 00096 sys.update(); 00097 00098 // Do DiffSystem assembly 00099 sys.assembly(true, false); 00100 R_system.close(); 00101 00102 // Swap back 00103 X_input.swap(X_system); 00104 R_input.swap(R_system); 00105 00106 // No errors, we hope 00107 return 0; 00108 } 00109 00110 00111 PetscErrorCode 00112 __libmesh_petsc_diff_solver_jacobian (SNES, Vec x, Mat *libmesh_dbg_var(j), Mat *pc, 00113 MatStructure *msflag, void *ctx) 00114 { 00115 libmesh_assert(x); 00116 libmesh_assert(j); 00117 // libmesh_assert_equal_to (pc, j); // We don't use separate preconditioners yet 00118 libmesh_assert(ctx); 00119 00120 PetscDiffSolver& solver = 00121 *(static_cast<PetscDiffSolver*> (ctx)); 00122 ImplicitSystem &sys = solver.system(); 00123 00124 if (solver.verbose) 00125 libMesh::out << "Assembling the Jacobian" << std::endl; 00126 00127 PetscVector<Number>& X_system = 00128 *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get()); 00129 PetscVector<Number> X_input(x); 00130 00131 PetscMatrix<Number> J_input(*pc); 00132 PetscMatrix<Number>& J_system = 00133 *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix); 00134 00135 // DiffSystem assembles from the solution and into the jacobian, so 00136 // swap those with our input vectors before assembling. They'll 00137 // probably already be references to the same vectors, but PETSc 00138 // might do something tricky. 00139 X_input.swap(X_system); 00140 J_input.swap(J_system); 00141 00142 // We may need to correct a non-conforming solution 00143 sys.get_dof_map().enforce_constraints_exactly(sys); 00144 00145 // We may need to localize a parallel solution 00146 sys.update(); 00147 00148 // Do DiffSystem assembly 00149 sys.assembly(false, true); 00150 J_system.close(); 00151 00152 // Swap back 00153 X_input.swap(X_system); 00154 J_input.swap(J_system); 00155 00156 *msflag = SAME_NONZERO_PATTERN; 00157 00158 // No errors, we hope 00159 return 0; 00160 } 00161 00162 } // extern "C" 00163 00164 00165 PetscDiffSolver::PetscDiffSolver (sys_type& s) 00166 : Parent(s) 00167 { 00168 } 00169 00170 00171 void PetscDiffSolver::init () 00172 { 00173 START_LOG("init()", "PetscDiffSolver"); 00174 00175 Parent::init(); 00176 00177 int ierr=0; 00178 00179 #if PETSC_VERSION_LESS_THAN(2,1,2) 00180 // At least until Petsc 2.1.1, the SNESCreate had a different 00181 // calling syntax. The second argument was of type SNESProblemType, 00182 // and could have a value of either SNES_NONLINEAR_EQUATIONS or 00183 // SNES_UNCONSTRAINED_MINIMIZATION. 00184 ierr = SNESCreate(libMesh::COMM_WORLD, SNES_NONLINEAR_EQUATIONS, &_snes); 00185 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00186 #else 00187 ierr = SNESCreate(libMesh::COMM_WORLD,&_snes); 00188 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00189 #endif 00190 00191 #if PETSC_VERSION_LESS_THAN(2,3,3) 00192 ierr = SNESSetMonitor (_snes, __libmesh_petsc_diff_solver_monitor, 00193 this, PETSC_NULL); 00194 #else 00195 // API name change in PETSc 2.3.3 00196 ierr = SNESMonitorSet (_snes, __libmesh_petsc_diff_solver_monitor, 00197 this, PETSC_NULL); 00198 #endif 00199 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00200 00201 ierr = SNESSetFromOptions(_snes); 00202 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00203 00204 STOP_LOG("init()", "PetscDiffSolver"); 00205 } 00206 00207 00208 00209 PetscDiffSolver::~PetscDiffSolver () 00210 { 00211 } 00212 00213 00214 00215 void PetscDiffSolver::clear() 00216 { 00217 START_LOG("clear()", "PetscDiffSolver"); 00218 00219 int ierr=0; 00220 00221 ierr = LibMeshSNESDestroy(&_snes); 00222 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00223 00224 STOP_LOG("clear()", "PetscDiffSolver"); 00225 } 00226 00227 00228 00229 void PetscDiffSolver::reinit() 00230 { 00231 Parent::reinit(); 00232 } 00233 00234 00235 00236 unsigned int PetscDiffSolver::solve() 00237 { 00238 this->init(); 00239 00240 START_LOG("solve()", "PetscDiffSolver"); 00241 00242 PetscVector<Number> &x = 00243 *(libmesh_cast_ptr<PetscVector<Number>*>(_system.solution.get())); 00244 PetscMatrix<Number> &jac = 00245 *(libmesh_cast_ptr<PetscMatrix<Number>*>(_system.matrix)); 00246 PetscVector<Number> &r = 00247 *(libmesh_cast_ptr<PetscVector<Number>*>(_system.rhs)); 00248 00249 #ifdef LIBMESH_ENABLE_CONSTRAINTS 00250 _system.get_dof_map().enforce_constraints_exactly(_system); 00251 #endif 00252 00253 int ierr = 0; 00254 00255 ierr = SNESSetFunction (_snes, r.vec(), 00256 __libmesh_petsc_diff_solver_residual, this); 00257 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00258 00259 ierr = SNESSetJacobian (_snes, jac.mat(), jac.mat(), 00260 __libmesh_petsc_diff_solver_jacobian, this); 00261 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00262 00263 # if PETSC_VERSION_LESS_THAN(2,2,0) 00264 00265 ierr = SNESSolve (_snes, x.vec(), &_outer_iterations); 00266 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00267 00268 // 2.2.x style 00269 #elif PETSC_VERSION_LESS_THAN(2,3,0) 00270 00271 ierr = SNESSolve (_snes, x.vec()); 00272 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00273 00274 // 2.3.x & newer style 00275 #else 00276 00277 ierr = SNESSolve (_snes, PETSC_NULL, x.vec()); 00278 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00279 00280 #endif 00281 00282 STOP_LOG("solve()", "PetscDiffSolver"); 00283 00284 this->clear(); 00285 00286 // FIXME - We'll worry about getting the solve result right later... 00287 00288 return DiffSolver::CONVERGED_RELATIVE_RESIDUAL; 00289 } 00290 00291 } // namespace libMesh 00292 00293 #endif // LIBMESH_HAVE_PETSC
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: